1
0
mirror of https://e.coding.net/circlecloud/MinecraftAccount.git synced 2025-11-25 21:36:08 +00:00

首次提交...

Signed-off-by: j502647092 <jtb1@163.com>
This commit is contained in:
j502647092
2015-11-01 22:25:03 +08:00
commit 2003fda7cb
409 changed files with 77938 additions and 0 deletions

174
ThinkPHP/Library/Vendor/Boris/Boris.php vendored Normal file
View File

@@ -0,0 +1,174 @@
<?php
/* vim: set shiftwidth=2 expandtab softtabstop=2: */
namespace Boris;
/**
* Boris is a tiny REPL for PHP.
*/
class Boris {
const VERSION = "1.0.8";
private $_prompt;
private $_historyFile;
private $_exports = array();
private $_startHooks = array();
private $_failureHooks = array();
private $_inspector;
/**
* Create a new REPL, which consists of an evaluation worker and a readline client.
*
* @param string $prompt, optional
* @param string $historyFile, optional
*/
public function __construct($prompt = 'boris> ', $historyFile = null) {
$this->setPrompt($prompt);
$this->_historyFile = $historyFile
? $historyFile
: sprintf('%s/.boris_history', getenv('HOME'))
;
$this->_inspector = new ColoredInspector();
}
/**
* Add a new hook to run in the context of the REPL when it starts.
*
* @param mixed $hook
*
* The hook is either a string of PHP code to eval(), or a Closure accepting
* the EvalWorker object as its first argument and the array of defined
* local variables in the second argument.
*
* If the hook is a callback and needs to set any local variables in the
* REPL's scope, it should invoke $worker->setLocal($var_name, $value) to
* do so.
*
* Hooks are guaranteed to run in the order they were added and the state
* set by each hook is available to the next hook (either through global
* resources, such as classes and interfaces, or through the 2nd parameter
* of the callback, if any local variables were set.
*
* @example Contrived example where one hook sets the date and another
* prints it in the REPL.
*
* $boris->onStart(function($worker, $vars){
* $worker->setLocal('date', date('Y-m-d'));
* });
*
* $boris->onStart('echo "The date is $date\n";');
*/
public function onStart($hook) {
$this->_startHooks[] = $hook;
}
/**
* Add a new hook to run in the context of the REPL when a fatal error occurs.
*
* @param mixed $hook
*
* The hook is either a string of PHP code to eval(), or a Closure accepting
* the EvalWorker object as its first argument and the array of defined
* local variables in the second argument.
*
* If the hook is a callback and needs to set any local variables in the
* REPL's scope, it should invoke $worker->setLocal($var_name, $value) to
* do so.
*
* Hooks are guaranteed to run in the order they were added and the state
* set by each hook is available to the next hook (either through global
* resources, such as classes and interfaces, or through the 2nd parameter
* of the callback, if any local variables were set.
*
* @example An example if your project requires some database connection cleanup:
*
* $boris->onFailure(function($worker, $vars){
* DB::reset();
* });
*/
public function onFailure($hook){
$this->_failureHooks[] = $hook;
}
/**
* Set a local variable, or many local variables.
*
* @example Setting a single variable
* $boris->setLocal('user', $bob);
*
* @example Setting many variables at once
* $boris->setLocal(array('user' => $bob, 'appContext' => $appContext));
*
* This method can safely be invoked repeatedly.
*
* @param array|string $local
* @param mixed $value, optional
*/
public function setLocal($local, $value = null) {
if (!is_array($local)) {
$local = array($local => $value);
}
$this->_exports = array_merge($this->_exports, $local);
}
/**
* Sets the Boris prompt text
*
* @param string $prompt
*/
public function setPrompt($prompt) {
$this->_prompt = $prompt;
}
/**
* Set an Inspector object for Boris to output return values with.
*
* @param object $inspector any object the responds to inspect($v)
*/
public function setInspector($inspector) {
$this->_inspector = $inspector;
}
/**
* Start the REPL (display the readline prompt).
*
* This method never returns.
*/
public function start() {
declare(ticks = 1);
pcntl_signal(SIGINT, SIG_IGN, true);
if (!$pipes = stream_socket_pair(
STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP)) {
throw new \RuntimeException('Failed to create socket pair');
}
$pid = pcntl_fork();
if ($pid > 0) {
if (function_exists('setproctitle')) {
setproctitle('boris (master)');
}
fclose($pipes[0]);
$client = new ReadlineClient($pipes[1]);
$client->start($this->_prompt, $this->_historyFile);
} elseif ($pid < 0) {
throw new \RuntimeException('Failed to fork child process');
} else {
if (function_exists('setproctitle')) {
setproctitle('boris (worker)');
}
fclose($pipes[1]);
$worker = new EvalWorker($pipes[0]);
$worker->setLocal($this->_exports);
$worker->setStartHooks($this->_startHooks);
$worker->setFailureHooks($this->_failureHooks);
$worker->setInspector($this->_inspector);
$worker->start();
}
}
}

View File

@@ -0,0 +1,85 @@
<?php
/* vim: set shiftwidth=2 expandtab softtabstop=2: */
namespace Boris;
/**
* Processes available command line flags.
*/
class CLIOptionsHandler {
/**
* Accept the REPL object and perform any setup necessary from the CLI flags.
*
* @param Boris $boris
*/
public function handle($boris) {
$args = getopt('hvr:', array('help', 'version', 'require:'));
foreach ($args as $option => $value) {
switch ($option) {
/*
* Sets files to load at startup, may be used multiple times,
* i.e: boris -r test.php,foo/bar.php -r ba/foo.php --require hey.php
*/
case 'r':
case 'require':
$this->_handleRequire($boris, $value);
break;
/*
* Show Usage info
*/
case 'h':
case 'help':
$this->_handleUsageInfo();
break;
/*
* Show version
*/
case 'v':
case 'version':
$this->_handleVersion();
break;
}
}
}
// -- Private Methods
private function _handleRequire($boris, $paths) {
$require = array_reduce(
(array) $paths,
function($acc, $v) { return array_merge($acc, explode(',', $v)); },
array()
);
$boris->onStart(function($worker, $scope) use($require) {
foreach($require as $path) {
require $path;
}
$worker->setLocal(get_defined_vars());
});
}
private function _handleUsageInfo() {
echo <<<USAGE
Usage: boris [options]
boris is a tiny REPL for PHP
Options:
-h, --help show this help message and exit
-r, --require a comma-separated list of files to require on startup
-v, --version show Boris version
USAGE;
exit(0);
}
private function _handleVersion() {
printf("Boris %s\n", Boris::VERSION);
exit(0);
}
}

View File

@@ -0,0 +1,273 @@
<?php
/* vim: set shiftwidth=2 expandtab softtabstop=2: */
/**
* @author Rob Morris <rob@irongaze.com>
* @author Chris Corbyn <chris@w3style.co.uk>
*
* Copyright © 2013-2014 Rob Morris.
*/
namespace Boris;
/**
* Identifies data types in data structures and syntax highlights them.
*/
class ColoredInspector implements Inspector {
static $TERM_COLORS = array(
'black' => "\033[0;30m",
'white' => "\033[1;37m",
'none' => "\033[1;30m",
'dark_grey' => "\033[1;30m",
'light_grey' => "\033[0;37m",
'dark_red' => "\033[0;31m",
'light_red' => "\033[1;31m",
'dark_green' => "\033[0;32m",
'light_green' => "\033[1;32m",
'dark_yellow' => "\033[0;33m",
'light_yellow' => "\033[1;33m",
'dark_blue' => "\033[0;34m",
'light_blue' => "\033[1;34m",
'dark_purple' => "\033[0;35m",
'light_purple' => "\033[1;35m",
'dark_cyan' => "\033[0;36m",
'light_cyan' => "\033[1;36m",
);
private $_fallback;
private $_colorMap = array();
/**
* Initialize a new ColoredInspector, using $colorMap.
*
* The colors should be an associative array with the keys:
*
* - 'integer'
* - 'float'
* - 'keyword'
* - 'string'
* - 'boolean'
* - 'default'
*
* And the values, one of the following colors:
*
* - 'none'
* - 'black'
* - 'white'
* - 'dark_grey'
* - 'light_grey'
* - 'dark_red'
* - 'light_red'
* - 'dark_green'
* - 'light_green'
* - 'dark_yellow'
* - 'light_yellow'
* - 'dark_blue'
* - 'light_blue'
* - 'dark_purple'
* - 'light_purple'
* - 'dark_cyan'
* - 'light_cyan'
*
* An empty $colorMap array effectively means 'none' for all types.
*
* @param array $colorMap
*/
public function __construct($colorMap = null) {
$this->_fallback = new DumpInspector();
if (isset($colorMap)) {
$this->_colorMap = $colorMap;
} else {
$this->_colorMap = $this->_defaultColorMap();
}
}
public function inspect($variable) {
return preg_replace(
'/^/m',
$this->_colorize('comment', '// '),
$this->_dump($variable)
);
}
/**
* Returns an associative array of an object's properties.
*
* This method is public so that subclasses may override it.
*
* @param object $value
* @return array
* */
public function objectVars($value) {
return get_object_vars($value);
}
// -- Private Methods
public function _dump($value) {
$tests = array(
'is_null' => '_dumpNull',
'is_string' => '_dumpString',
'is_bool' => '_dumpBoolean',
'is_integer' => '_dumpInteger',
'is_float' => '_dumpFloat',
'is_array' => '_dumpArray',
'is_object' => '_dumpObject'
);
foreach ($tests as $predicate => $outputMethod) {
if (call_user_func($predicate, $value))
return call_user_func(array($this, $outputMethod), $value);
}
return $this->_fallback->inspect($value);
}
private function _dumpNull($value) {
return $this->_colorize('keyword', 'NULL');
}
private function _dumpString($value) {
return $this->_colorize('string', var_export($value, true));
}
private function _dumpBoolean($value) {
return $this->_colorize('bool', var_export($value, true));
}
private function _dumpInteger($value) {
return $this->_colorize('integer', var_export($value, true));
}
private function _dumpFloat($value) {
return $this->_colorize('float', var_export($value, true));
}
private function _dumpArray($value) {
return $this->_dumpStructure('array', $value);
}
private function _dumpObject($value) {
return $this->_dumpStructure(
sprintf('object(%s)', get_class($value)),
$this->objectVars($value)
);
}
private function _dumpStructure($type, $value) {
return $this->_astToString($this->_buildAst($type, $value));
}
public function _buildAst($type, $value, $seen = array()) {
// FIXME: Improve this AST so it doesn't require access to dump() or colorize()
if ($this->_isSeen($value, $seen)) {
return $this->_colorize('default', '*** RECURSION ***');
} else {
$nextSeen = array_merge($seen, array($value));
}
if (is_object($value)) {
$vars = $this->objectVars($value);
} else {
$vars = $value;
}
$self = $this;
return array(
'name' => $this->_colorize('keyword', $type),
'children' => empty($vars) ? array() : array_combine(
array_map(array($this, '_dump'), array_keys($vars)),
array_map(
function($v) use($self, $nextSeen) {
if (is_object($v)) {
return $self->_buildAst(
sprintf('object(%s)', get_class($v)),
$v,
$nextSeen
);
} elseif (is_array($v)) {
return $self->_buildAst('array', $v, $nextSeen);
} else {
return $self->_dump($v);
}
},
array_values($vars)
)
)
);
}
public function _astToString($node, $indent = 0) {
$children = $node['children'];
$self = $this;
return implode(
"\n",
array(
sprintf('%s(', $node['name']),
implode(
",\n",
array_map(
function($k) use($self, $children, $indent) {
if (is_array($children[$k])) {
return sprintf(
'%s%s => %s',
str_repeat(' ', ($indent + 1) * 2),
$k,
$self->_astToString($children[$k], $indent + 1)
);
} else {
return sprintf(
'%s%s => %s',
str_repeat(' ', ($indent + 1) * 2),
$k,
$children[$k]
);
}
},
array_keys($children)
)
),
sprintf('%s)', str_repeat(' ', $indent * 2))
)
);
}
private function _defaultColorMap() {
return array(
'integer' => 'light_green',
'float' => 'light_yellow',
'string' => 'light_red',
'bool' => 'light_purple',
'keyword' => 'light_cyan',
'comment' => 'dark_grey',
'default' => 'none'
);
}
private function _colorize($type, $value) {
if (!empty($this->_colorMap[$type])) {
$colorName = $this->_colorMap[$type];
} else {
$colorName = $this->_colorMap['default'];
}
return sprintf(
"%s%s\033[0m",
static::$TERM_COLORS[$colorName],
$value
);
}
private function _isSeen($value, $seen) {
foreach ($seen as $v) {
if ($v === $value)
return true;
}
return false;
}
}

View File

@@ -0,0 +1,85 @@
<?php
/* vim: set shiftwidth=2 expandtab softtabstop=2: */
namespace Boris;
/**
* Config handles loading configuration files for boris
*/
class Config {
private $_searchPaths;
private $_cascade = false;
private $_files = array();
/**
* Create a new Config instance, optionally with an array
* of paths to search for configuration files.
*
* Additionally, if the second, optional boolean argument is
* true, all existing configuration files will be loaded, and
* effectively merged.
*
* @param array $searchPaths
* @param bool $cascade
*/
public function __construct($searchPaths = null, $cascade = false) {
if (is_null($searchPaths)) {
$searchPaths = array();
if ($userHome = getenv('HOME')) {
$searchPaths[] = "{$userHome}/.borisrc";
}
$searchPaths[] = getcwd() . '/.borisrc';
}
$this->_cascade = $cascade;
$this->_searchPaths = $searchPaths;
}
/**
* Searches for configuration files in the available
* search paths, and applies them to the provided
* boris instance.
*
* Returns true if any configuration files were found.
*
* @param Boris\Boris $boris
* @return bool
*/
public function apply(Boris $boris) {
$applied = false;
foreach($this->_searchPaths as $path) {
if (is_readable($path)) {
$this->_loadInIsolation($path, $boris);
$applied = true;
$this->_files[] = $path;
if (!$this->_cascade) {
break;
}
}
}
return $applied;
}
/**
* Returns an array of files that were loaded
* for this Config
*
* @return array
*/
public function loadedFiles() {
return $this->_files;
}
// -- Private Methods
private function _loadInIsolation($path, $boris) {
require $path;
}
}

View File

@@ -0,0 +1,16 @@
<?php
/* vim: set shiftwidth=2 expandtab softtabstop=2: */
namespace Boris;
/**
* Passes values through var_dump() to inspect them.
*/
class DumpInspector implements Inspector {
public function inspect($variable) {
ob_start();
var_dump($variable);
return sprintf(" → %s", trim(ob_get_clean()));
}
}

View File

@@ -0,0 +1,247 @@
<?php
/* vim: set shiftwidth=2 expandtab softtabstop=2: */
namespace Boris;
/**
* EvalWorker is responsible for evaluating PHP expressions in forked processes.
*/
class EvalWorker {
const ABNORMAL_EXIT = 255;
const DONE = "\0";
const EXITED = "\1";
const FAILED = "\2";
const READY = "\3";
private $_socket;
private $_exports = array();
private $_startHooks = array();
private $_failureHooks = array();
private $_ppid;
private $_pid;
private $_cancelled;
private $_inspector;
private $_exceptionHandler;
/**
* Create a new worker using the given socket for communication.
*
* @param resource $socket
*/
public function __construct($socket) {
$this->_socket = $socket;
$this->_inspector = new DumpInspector();
stream_set_blocking($socket, 0);
}
/**
* Set local variables to be placed in the workers's scope.
*
* @param array|string $local
* @param mixed $value, if $local is a string
*/
public function setLocal($local, $value = null) {
if (!is_array($local)) {
$local = array($local => $value);
}
$this->_exports = array_merge($this->_exports, $local);
}
/**
* Set hooks to run inside the worker before it starts looping.
*
* @param array $hooks
*/
public function setStartHooks($hooks) {
$this->_startHooks = $hooks;
}
/**
* Set hooks to run inside the worker after a fatal error is caught.
*
* @param array $hooks
*/
public function setFailureHooks($hooks) {
$this->_failureHooks = $hooks;
}
/**
* Set an Inspector object for Boris to output return values with.
*
* @param object $inspector any object the responds to inspect($v)
*/
public function setInspector($inspector) {
$this->_inspector = $inspector;
}
/**
* Start the worker.
*
* This method never returns.
*/
public function start() {
$__scope = $this->_runHooks($this->_startHooks);
extract($__scope);
$this->_write($this->_socket, self::READY);
/* Note the naming of the local variables due to shared scope with the user here */
for (;;) {
declare(ticks = 1);
// don't exit on ctrl-c
pcntl_signal(SIGINT, SIG_IGN, true);
$this->_cancelled = false;
$__input = $this->_transform($this->_read($this->_socket));
if ($__input === null) {
continue;
}
$__response = self::DONE;
$this->_ppid = posix_getpid();
$this->_pid = pcntl_fork();
if ($this->_pid < 0) {
throw new \RuntimeException('Failed to fork child labourer');
} elseif ($this->_pid > 0) {
// kill the child on ctrl-c
pcntl_signal(SIGINT, array($this, 'cancelOperation'), true);
pcntl_waitpid($this->_pid, $__status);
if (!$this->_cancelled && $__status != (self::ABNORMAL_EXIT << 8)) {
$__response = self::EXITED;
} else {
$this->_runHooks($this->_failureHooks);
$__response = self::FAILED;
}
} else {
// user exception handlers normally cause a clean exit, so Boris will exit too
if (!$this->_exceptionHandler =
set_exception_handler(array($this, 'delegateExceptionHandler'))) {
restore_exception_handler();
}
// undo ctrl-c signal handling ready for user code execution
pcntl_signal(SIGINT, SIG_DFL, true);
$__pid = posix_getpid();
$__result = eval($__input);
if (posix_getpid() != $__pid) {
// whatever the user entered caused a forked child
// (totally valid, but we don't want that child to loop and wait for input)
exit(0);
}
if (preg_match('/\s*return\b/i', $__input)) {
fwrite(STDOUT, sprintf("%s\n", $this->_inspector->inspect($__result)));
}
$this->_expungeOldWorker();
}
$this->_write($this->_socket, $__response);
if ($__response == self::EXITED) {
exit(0);
}
}
}
/**
* While a child process is running, terminate it immediately.
*/
public function cancelOperation() {
printf("Cancelling...\n");
$this->_cancelled = true;
posix_kill($this->_pid, SIGKILL);
pcntl_signal_dispatch();
}
/**
* If any user-defined exception handler is present, call it, but be sure to exit correctly.
*/
public function delegateExceptionHandler($ex) {
call_user_func($this->_exceptionHandler, $ex);
exit(self::ABNORMAL_EXIT);
}
// -- Private Methods
private function _runHooks($hooks) {
extract($this->_exports);
foreach ($hooks as $__hook) {
if (is_string($__hook)) {
eval($__hook);
} elseif (is_callable($__hook)) {
call_user_func($__hook, $this, get_defined_vars());
} else {
throw new \RuntimeException(
sprintf(
'Hooks must be closures or strings of PHP code. Got [%s].',
gettype($__hook)
)
);
}
// hooks may set locals
extract($this->_exports);
}
return get_defined_vars();
}
private function _expungeOldWorker() {
posix_kill($this->_ppid, SIGTERM);
pcntl_signal_dispatch();
}
private function _write($socket, $data) {
if (!fwrite($socket, $data)) {
throw new \RuntimeException('Socket error: failed to write data');
}
}
private function _read($socket)
{
$read = array($socket);
$except = array($socket);
if ($this->_select($read, $except) > 0) {
if ($read) {
return stream_get_contents($read[0]);
} else if ($except) {
throw new \UnexpectedValueException("Socket error: closed");
}
}
}
private function _select(&$read, &$except) {
$write = null;
set_error_handler(function(){return true;}, E_WARNING);
$result = stream_select($read, $write, $except, 10);
restore_error_handler();
return $result;
}
private function _transform($input) {
if ($input === null) {
return null;
}
$transforms = array(
'exit' => 'exit(0)'
);
foreach ($transforms as $from => $to) {
$input = preg_replace('/^\s*' . preg_quote($from, '/') . '\s*;?\s*$/', $to . ';', $input);
}
return $input;
}
}

View File

@@ -0,0 +1,14 @@
<?php
/* vim: set shiftwidth=2 expandtab softtabstop=2: */
namespace Boris;
/**
* Passes values through var_export() to inspect them.
*/
class ExportInspector implements Inspector {
public function inspect($variable) {
return sprintf(" → %s", var_export($variable, true));
}
}

View File

@@ -0,0 +1,19 @@
<?php
/* vim: set shiftwidth=2 expandtab softtabstop=2: */
namespace Boris;
/**
* Something that is capable of returning a useful representation of a variable.
*/
interface Inspector {
/**
* Return a debug-friendly string representation of $variable.
*
* @param mixed $variable
*
* @return string
*/
public function inspect($variable);
}

View File

@@ -0,0 +1,109 @@
<?php
/* vim: set shiftwidth=2 expandtab softtabstop=2: */
namespace Boris;
/**
* The Readline client is what the user spends their time entering text into.
*
* Input is collected and sent to {@link \Boris\EvalWorker} for processing.
*/
class ReadlineClient {
private $_socket;
private $_prompt;
private $_historyFile;
private $_clear = false;
/**
* Create a new ReadlineClient using $socket for communication.
*
* @param resource $socket
*/
public function __construct($socket) {
$this->_socket = $socket;
}
/**
* Start the client with an prompt and readline history path.
*
* This method never returns.
*
* @param string $prompt
* @param string $historyFile
*/
public function start($prompt, $historyFile) {
readline_read_history($historyFile);
declare(ticks = 1);
pcntl_signal(SIGCHLD, SIG_IGN);
pcntl_signal(SIGINT, array($this, 'clear'), true);
// wait for the worker to finish executing hooks
if (fread($this->_socket, 1) != EvalWorker::READY) {
throw new \RuntimeException('EvalWorker failed to start');
}
$parser = new ShallowParser();
$buf = '';
$lineno = 1;
for (;;) {
$this->_clear = false;
$line = readline(
sprintf(
'[%d] %s',
$lineno,
($buf == ''
? $prompt
: str_pad('*> ', strlen($prompt), ' ', STR_PAD_LEFT))
)
);
if ($this->_clear) {
$buf = '';
continue;
}
if (false === $line) {
$buf = 'exit(0);'; // ctrl-d acts like exit
}
if (strlen($line) > 0) {
readline_add_history($line);
}
$buf .= sprintf("%s\n", $line);
if ($statements = $parser->statements($buf)) {
++$lineno;
$buf = '';
foreach ($statements as $stmt) {
if (false === $written = fwrite($this->_socket, $stmt)) {
throw new \RuntimeException('Socket error: failed to write data');
}
if ($written > 0) {
$status = fread($this->_socket, 1);
if ($status == EvalWorker::EXITED) {
readline_write_history($historyFile);
echo "\n";
exit(0);
} elseif ($status == EvalWorker::FAILED) {
break;
}
}
}
}
}
}
/**
* Clear the input buffer.
*/
public function clear() {
// FIXME: I'd love to have this send \r to readline so it puts the user on a blank line
$this->_clear = true;
}
}

View File

@@ -0,0 +1,233 @@
<?php
/* vim: set shiftwidth=2 expandtab softtabstop=2: */
namespace Boris;
/**
* The ShallowParser takes whatever is currently buffered and chunks it into individual statements.
*/
class ShallowParser {
private $_pairs = array(
'(' => ')',
'{' => '}',
'[' => ']',
'"' => '"',
"'" => "'",
'//' => "\n",
'#' => "\n",
'/*' => '*/',
'<<<' => '_heredoc_special_case_'
);
private $_initials;
public function __construct() {
$this->_initials = '/^(' . implode('|', array_map(array($this, 'quote'), array_keys($this->_pairs))) . ')/';
}
/**
* Break the $buffer into chunks, with one for each highest-level construct possible.
*
* If the buffer is incomplete, returns an empty array.
*
* @param string $buffer
*
* @return array
*/
public function statements($buffer) {
$result = $this->_createResult($buffer);
while (strlen($result->buffer) > 0) {
$this->_resetResult($result);
if ($result->state == '<<<') {
if (!$this->_initializeHeredoc($result)) {
continue;
}
}
$rules = array('_scanEscapedChar', '_scanRegion', '_scanStateEntrant', '_scanWsp', '_scanChar');
foreach ($rules as $method) {
if ($this->$method($result)) {
break;
}
}
if ($result->stop) {
break;
}
}
if (!empty($result->statements) && trim($result->stmt) === '' && strlen($result->buffer) == 0) {
$this->_combineStatements($result);
$this->_prepareForDebug($result);
return $result->statements;
}
}
public function quote($token) {
return preg_quote($token, '/');
}
// -- Private Methods
private function _createResult($buffer) {
$result = new \stdClass();
$result->buffer = $buffer;
$result->stmt = '';
$result->state = null;
$result->states = array();
$result->statements = array();
$result->stop = false;
return $result;
}
private function _resetResult($result) {
$result->stop = false;
$result->state = end($result->states);
$result->terminator = $result->state
? '/^(.*?' . preg_quote($this->_pairs[$result->state], '/') . ')/s'
: null
;
}
private function _combineStatements($result) {
$combined = array();
foreach ($result->statements as $scope) {
if (trim($scope) == ';' || substr(trim($scope), -1) != ';') {
$combined[] = ((string) array_pop($combined)) . $scope;
} else {
$combined[] = $scope;
}
}
$result->statements = $combined;
}
private function _prepareForDebug($result) {
$result->statements []= $this->_prepareDebugStmt(array_pop($result->statements));
}
private function _initializeHeredoc($result) {
if (preg_match('/^([\'"]?)([a-z_][a-z0-9_]*)\\1/i', $result->buffer, $match)) {
$docId = $match[2];
$result->stmt .= $match[0];
$result->buffer = substr($result->buffer, strlen($match[0]));
$result->terminator = '/^(.*?\n' . $docId . ');?\n/s';
return true;
} else {
return false;
}
}
private function _scanWsp($result) {
if (preg_match('/^\s+/', $result->buffer, $match)) {
if (!empty($result->statements) && $result->stmt === '') {
$result->statements[] = array_pop($result->statements) . $match[0];
} else {
$result->stmt .= $match[0];
}
$result->buffer = substr($result->buffer, strlen($match[0]));
return true;
} else {
return false;
}
}
private function _scanEscapedChar($result) {
if (($result->state == '"' || $result->state == "'")
&& preg_match('/^[^' . $result->state . ']*?\\\\./s', $result->buffer, $match)) {
$result->stmt .= $match[0];
$result->buffer = substr($result->buffer, strlen($match[0]));
return true;
} else {
return false;
}
}
private function _scanRegion($result) {
if (in_array($result->state, array('"', "'", '<<<', '//', '#', '/*'))) {
if (preg_match($result->terminator, $result->buffer, $match)) {
$result->stmt .= $match[1];
$result->buffer = substr($result->buffer, strlen($match[1]));
array_pop($result->states);
} else {
$result->stop = true;
}
return true;
} else {
return false;
}
}
private function _scanStateEntrant($result) {
if (preg_match($this->_initials, $result->buffer, $match)) {
$result->stmt .= $match[0];
$result->buffer = substr($result->buffer, strlen($match[0]));
$result->states[] = $match[0];
return true;
} else {
return false;
}
}
private function _scanChar($result) {
$chr = substr($result->buffer, 0, 1);
$result->stmt .= $chr;
$result->buffer = substr($result->buffer, 1);
if ($result->state && $chr == $this->_pairs[$result->state]) {
array_pop($result->states);
}
if (empty($result->states) && ($chr == ';' || $chr == '}')) {
if (!$this->_isLambda($result->stmt) || $chr == ';') {
$result->statements[] = $result->stmt;
$result->stmt = '';
}
}
return true;
}
private function _isLambda($input) {
return preg_match(
'/^([^=]*?=\s*)?function\s*\([^\)]*\)\s*(use\s*\([^\)]*\)\s*)?\s*\{.*\}\s*;?$/is',
trim($input)
);
}
private function _isReturnable($input) {
$input = trim($input);
if (substr($input, -1) == ';' && substr($input, 0, 1) != '{') {
return $this->_isLambda($input) || !preg_match(
'/^(' .
'echo|print|exit|die|goto|global|include|include_once|require|require_once|list|' .
'return|do|for|foreach|while|if|function|namespace|class|interface|abstract|switch|' .
'declare|throw|try|unset' .
')\b/i',
$input
);
} else {
return false;
}
}
private function _prepareDebugStmt($input) {
if ($this->_isReturnable($input) && !preg_match('/^\s*return/i', $input)) {
$input = sprintf('return %s', $input);
}
return $input;
}
}