525 lines
12 KiB
PHP
525 lines
12 KiB
PHP
<?php
|
|
|
|
// Copyright 2006 James Tauber and contributors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
/**
|
|
* This call makes three things happen:.
|
|
*
|
|
* 1) a global error handler for php errors that causes an exception to be
|
|
* thrown instead of standard php error handling.
|
|
*
|
|
* 2) a global exception handler for any exceptions that are somehow not
|
|
* caught by the application code.
|
|
*
|
|
* 3) error_reporting is set to E_STRICT, so that even notices cause an
|
|
* exception to be thrown. This way we are forced to deal with even
|
|
* the minor issues during development, and hopefully fewer issues
|
|
*/
|
|
require_once dirname(__FILE__).DIRECTORY_SEPARATOR.'strict_mode.php';
|
|
init_strict_mode();
|
|
|
|
|
|
|
|
// iteration from Bob Ippolito's Iteration in JavaScript
|
|
// pyjs_extend from Kevin Lindsey's Inteheritance Tutorial (http://www.kevlindev.com/tutorials/javascript/inheritance/)
|
|
|
|
// type functions from Douglas Crockford's Remedial Javascript: http://www.crockford.com/javascript/remedial.html
|
|
function pyjslib_isObject($a)
|
|
{
|
|
return is_object($a);
|
|
}
|
|
|
|
function pyjslib_isFunction($a)
|
|
{
|
|
return is_function($a);
|
|
}
|
|
|
|
function pyjslib_isString($a)
|
|
{
|
|
return is_string($a);
|
|
}
|
|
|
|
function pyjslib_isNull($a)
|
|
{
|
|
return is_null($a);
|
|
}
|
|
|
|
function pyjslib_isArray($a)
|
|
{
|
|
return is_array($a);
|
|
}
|
|
|
|
function pyjslib_isUndefined($a)
|
|
{
|
|
return !isset($a);
|
|
}
|
|
|
|
function pyjslib_isIteratable($a)
|
|
{
|
|
return $a instanceof Traversable;
|
|
}
|
|
|
|
function pyjslib_isNumber($a)
|
|
{
|
|
return is_numeric($a);
|
|
}
|
|
|
|
function pyjslib_int($a)
|
|
{
|
|
return (int) $a;
|
|
}
|
|
|
|
function pyjslib_str($val)
|
|
{
|
|
return (string) $val;
|
|
}
|
|
|
|
function pyjslib_del_slice(&$list, $from, $to, $step = 1)
|
|
{
|
|
if ($from <= 0) {
|
|
$from = 0;
|
|
}
|
|
if ($to === null) {
|
|
$to = count($list);
|
|
}
|
|
if ($step <= 0) {
|
|
$step = 1;
|
|
}
|
|
for ($i = $from; $i < $to; $i += $step) {
|
|
unset($list[$i]);
|
|
}
|
|
}
|
|
|
|
function pyjslib_array_slice($list, $from, $to, $step = 1)
|
|
{
|
|
$newlist = [];
|
|
if ($from <= 0) {
|
|
$from = 0;
|
|
}
|
|
if ($to === null) {
|
|
$to = count($list);
|
|
}
|
|
if ($step <= 0) {
|
|
$step = 1;
|
|
}
|
|
for ($i = $from; $i < $to; $i += $step) {
|
|
$newlist[] = $list[$i];
|
|
}
|
|
|
|
return $newlist;
|
|
}
|
|
|
|
|
|
// taken from mochikit: range( [start,] stop[, step] )
|
|
function pyjslib_range($start, $stop = null, $step = 1)
|
|
{
|
|
if ($stop === null) {
|
|
$stop = $start;
|
|
$start = 0;
|
|
}
|
|
if ($stop <= $start && $step < 0) {
|
|
$arr = range($stop, $start, -$step);
|
|
array_pop($arr);
|
|
|
|
return array_reverse($arr, false);
|
|
}
|
|
if ($step > 1 && $step > ($stop - $start)) {
|
|
$arr = [$start];
|
|
} else {
|
|
$arr = range($start, $stop, $step);
|
|
array_pop($arr);
|
|
}
|
|
|
|
return $arr;
|
|
}
|
|
|
|
function pyjslib_filter($callback, $iterable)
|
|
{
|
|
$a = [];
|
|
foreach ($iterable as $item) {
|
|
if (call_user_func($callback, $item)) {
|
|
$a[] = $item;
|
|
}
|
|
}
|
|
|
|
return $a;
|
|
}
|
|
|
|
function pyjslib_globals()
|
|
{
|
|
return $GLOBALS;
|
|
}
|
|
|
|
|
|
function pyjslib_map($callable)
|
|
{
|
|
$done = false;
|
|
$call_cnt = 0;
|
|
$results = [];
|
|
|
|
$params = func_get_args();
|
|
array_shift($params);
|
|
|
|
while (!$done) {
|
|
$func_args = [];
|
|
$found = false;
|
|
for ($i = 0; $i < count($params); $i++) {
|
|
$func_args[] = @$params[$i][$call_cnt];
|
|
if (count($params[$i]) > $call_cnt + 1) {
|
|
$found = true;
|
|
}
|
|
}
|
|
if (!$found) {
|
|
$done = true;
|
|
}
|
|
$results[] = call_user_func_array($callable, $func_args);
|
|
$call_cnt++;
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
function pyjslib_zip()
|
|
{
|
|
$params = func_get_args();
|
|
if (count($params) === 1) { // this case could be probably cleaner
|
|
// single iterable passed
|
|
$result = [];
|
|
foreach ($params[0] as $item) {
|
|
$result[] = [$item];
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
$result = call_user_func_array('array_map', array_merge([null], $params));
|
|
$length = min(array_map('count', $params));
|
|
|
|
return array_slice($result, 0, $length);
|
|
}
|
|
|
|
function pyjslib_is_assoc($arr)
|
|
{
|
|
return array_keys($arr) !== range(0, count($arr) - 1);
|
|
}
|
|
|
|
function pyjslib_dict($arg = null)
|
|
{
|
|
if ($arg === null) {
|
|
return [];
|
|
}
|
|
if (pyjslib_is_assoc($arg)) {
|
|
return $arg;
|
|
}
|
|
$dict = [];
|
|
foreach ($arg as $a) {
|
|
if (count($a) == 2) {
|
|
$dict[$a[0]] = $a[1];
|
|
}
|
|
}
|
|
|
|
return $dict;
|
|
}
|
|
|
|
function pyjslib_printWorker($objs, $nl, $multi_arg, $depth = 1)
|
|
{
|
|
$buf = '';
|
|
if (is_array($objs) && $multi_arg && $depth == 1) {
|
|
$cnt = 0;
|
|
foreach ($objs as $obj) {
|
|
if ($cnt++ > 0) {
|
|
$buf .= ' ';
|
|
}
|
|
$buf .= pyjslib_printWorker($obj, $nl, $multi_arg, $depth + 1);
|
|
}
|
|
} elseif (is_bool($objs)) {
|
|
$buf = $objs ? 'True' : 'False';
|
|
} elseif (is_null($objs)) {
|
|
$buf = 'None';
|
|
} elseif (is_float($objs)) {
|
|
$buf = (int) $objs;
|
|
} elseif (is_string($objs) && ($multi_arg && $depth > 2 || (!$multi_arg && $depth > 1))) {
|
|
$buf = "'$objs'";
|
|
} elseif (is_array($objs)) {
|
|
$buf = '[';
|
|
$cnt = 0;
|
|
foreach ($objs as $obj) {
|
|
$val = pyjslib_printWorker($obj, $nl, false, $depth + 1);
|
|
if ($cnt++ > 0) {
|
|
$buf .= ', ';
|
|
}
|
|
$buf .= $val;
|
|
}
|
|
$buf .= ']';
|
|
// $buf = '[' . implode( ", ", $objs ) . ']';
|
|
} else {
|
|
$buf = $objs;
|
|
}
|
|
if ($depth == 1 && (!strlen($buf) || $buf[strlen($buf) - 1] != "\n")) {
|
|
$buf .= $nl ? "\n" : ' ';
|
|
}
|
|
|
|
return $buf;
|
|
}
|
|
|
|
function pyjslib_repr($obj)
|
|
{
|
|
return pyjslib_printWorker($obj, false, false);
|
|
}
|
|
|
|
function pyjslib_print($objs, $multi_arg = false)
|
|
{
|
|
echo pyjslib_printWorker($objs, false, $multi_arg);
|
|
}
|
|
|
|
function pyjslib_printnl($objs, $multi_arg = false)
|
|
{
|
|
echo pyjslib_printWorker($objs, true, $multi_arg);
|
|
}
|
|
|
|
function py2php_kwargs_function_call($funcname, $ordered, $named)
|
|
{
|
|
if ($funcname == 'array' || $funcname == 'pyjslib_dict') {
|
|
return $named;
|
|
}
|
|
|
|
$num_ordered = count($ordered);
|
|
$count = 1;
|
|
|
|
$refFunc = new ReflectionFunction($funcname);
|
|
foreach ($refFunc->getParameters() as $param) {
|
|
if ($param->isVariadic()) {
|
|
$ordered[$count - 1] = $named;
|
|
break;
|
|
}
|
|
//invokes ReflectionParameter::__toString
|
|
if ($count > $num_ordered) {
|
|
$name = $param->name;
|
|
$default = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null;
|
|
$ordered[] = @$named[$name] ?: $default;
|
|
}
|
|
|
|
$count++;
|
|
}
|
|
//var_dump($ordered);
|
|
return call_user_func_array($funcname, $ordered);
|
|
}
|
|
|
|
function py2php_kwargs_method_call($obj, $method, $ordered, $named)
|
|
{
|
|
$num_ordered = count($ordered);
|
|
$count = 1;
|
|
|
|
$refFunc = new ReflectionMethod($obj, $method);
|
|
foreach ($refFunc->getParameters() as $param) {
|
|
//invokes ReflectionParameter::__toString
|
|
if ($count > $num_ordered) {
|
|
$name = $param->name;
|
|
$default = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null;
|
|
$ordered[] = @$named[$name] ?: $default;
|
|
}
|
|
|
|
$count++;
|
|
}
|
|
|
|
$callable = [$obj, $method];
|
|
|
|
return call_user_func_array($callable, $ordered);
|
|
}
|
|
|
|
class IOError extends Exception
|
|
{
|
|
}
|
|
|
|
class ValueError extends Exception
|
|
{
|
|
}
|
|
|
|
|
|
function pyjslib_open($name, $mode = 'r', $buffering = null)
|
|
{
|
|
return new pyjslib_file($name, $mode, $buffering);
|
|
}
|
|
|
|
class pyjslib_file implements Iterator
|
|
{
|
|
private $fh = false;
|
|
private $current_line = null;
|
|
|
|
// public attributes of python file class.
|
|
public $closed = true;
|
|
public $encoding = null;
|
|
public $errors = [];
|
|
public $mode = null;
|
|
public $newlines = null;
|
|
public $softspace = false;
|
|
|
|
public function __construct($name_or_fd, $mode = 'r', $buffering = null)
|
|
{
|
|
if (is_resource($name_or_fd)) {
|
|
$this->fh = $name_or_fd;
|
|
$this->closed = false;
|
|
$meta = stream_get_meta_data($name_or_df);
|
|
$this->mode = $meta['mode'];
|
|
|
|
return;
|
|
}
|
|
$name = $name_or_fd;
|
|
try {
|
|
$this->fh = fopen($name, $mode);
|
|
if (!$this->fh) {
|
|
throw new Exception("Could not open $name");
|
|
}
|
|
$this->closed = false;
|
|
$this->mode = $mode;
|
|
} catch (Exception $e) {
|
|
throw new IOError($e->getMessage(), $e->getCode());
|
|
}
|
|
}
|
|
|
|
public function close()
|
|
{
|
|
if ($this->fh) {
|
|
fclose($this->fh);
|
|
$this->fh = null;
|
|
$this->closed = true;
|
|
}
|
|
}
|
|
|
|
public function flush()
|
|
{
|
|
if (!$this->fh) {
|
|
throw new ValueError('File is closed.');
|
|
}
|
|
fflush($this->fh);
|
|
}
|
|
|
|
public function fileno()
|
|
{
|
|
if (!$this->fh) {
|
|
throw new ValueError('File is closed.');
|
|
}
|
|
|
|
return $this->fh;
|
|
}
|
|
|
|
public function isatty()
|
|
{
|
|
if (!$this->fh) {
|
|
throw new ValueError('File is closed.');
|
|
}
|
|
|
|
return posix_isatty($this->fh);
|
|
}
|
|
|
|
/* ---
|
|
* Begin PHP Iterator implementation
|
|
* ---
|
|
*/
|
|
public function rewind()
|
|
{
|
|
fseek($this->fh, 0);
|
|
$this->line = 0;
|
|
}
|
|
|
|
public function current()
|
|
{
|
|
if (!$this->current_line) {
|
|
$this->current_line = fgets($this->fh);
|
|
}
|
|
|
|
return $this->current_line;
|
|
}
|
|
|
|
public function key()
|
|
{
|
|
return $this->line;
|
|
}
|
|
|
|
public function next()
|
|
{
|
|
$this->current(); // ensure current line has been retrieved.
|
|
$this->current_line = fgets($this->fh);
|
|
$this->line++;
|
|
|
|
return $this->current_line;
|
|
}
|
|
|
|
public function valid()
|
|
{
|
|
return $this->fh != false && !feof($this->fh);
|
|
}
|
|
|
|
/* ---
|
|
* End PHP Iterator implementation
|
|
* ---
|
|
*/
|
|
|
|
public function read($size = null)
|
|
{
|
|
if ($size !== null) {
|
|
return fread($this->fh, $size);
|
|
}
|
|
|
|
return stream_get_contents($this->fh);
|
|
}
|
|
|
|
public function readline($size = null)
|
|
{
|
|
return fgets($this->fh, $size);
|
|
}
|
|
|
|
public function readlines($sizehint = null)
|
|
{
|
|
$len = 0;
|
|
$lines = [];
|
|
while ($line = fgets($this->fh)) {
|
|
$len += strlen($line);
|
|
$lines[] = $line;
|
|
if ($sizehint && $len >= $sizehint) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $lines;
|
|
}
|
|
|
|
public function seek($offset, $whence = SEEK_SET)
|
|
{
|
|
return fseek($this->fh, $offset, $whence);
|
|
}
|
|
|
|
public function tell()
|
|
{
|
|
return ftell($this->fh);
|
|
}
|
|
|
|
public function truncate($size)
|
|
{
|
|
$rc = ftruncate($this->fh, $size);
|
|
}
|
|
|
|
public function write($str)
|
|
{
|
|
fwrite($this->fh, $str);
|
|
}
|
|
|
|
public function writelines($sequence)
|
|
{
|
|
foreach ($sequence as $line) {
|
|
$this->write($line);
|
|
}
|
|
}
|
|
}
|