--- /dev/null
+{
+ "name": "andy128k/pegp",
+ "description": "PEG",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Andrey Kutejko",
+ "email": "andy128k@gmail.com"
+ }
+ ],
+ "autoload": {
+ "classmap" : ["lib"]
+ },
+ "require-dev": {
+ "phpunit/phpunit": "3.7.*"
+ }
+}
+
--- /dev/null
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
+ ],
+ "hash": "3e9668f4e1ddee877ae96c3d3e4cd05f",
+ "packages": [
+
+ ],
+ "packages-dev": [
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "1.2.12",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "1.2.12"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.12",
+ "reference": "1.2.12",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "phpunit/php-file-iterator": ">=1.3.0@stable",
+ "phpunit/php-text-template": ">=1.1.1@stable",
+ "phpunit/php-token-stream": ">=1.1.3@stable"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "3.7.*@dev"
+ },
+ "suggest": {
+ "ext-dom": "*",
+ "ext-xdebug": ">=2.0.5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "PHP/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "time": "2013-07-06 06:26:16"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "1.3.3",
+ "source": {
+ "type": "git",
+ "url": "git://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "1.3.3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3",
+ "reference": "1.3.3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "File/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "http://www.phpunit.de/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "time": "2012-10-11 04:44:38"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "1.1.4",
+ "source": {
+ "type": "git",
+ "url": "git://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "1.1.4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4",
+ "reference": "1.1.4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "Text/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "time": "2012-10-31 11:15:28"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "1.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "1.0.5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1.0.5",
+ "reference": "1.0.5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "PHP/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "time": "2013-08-02 07:42:54"
+ },
+ {
+ "name": "phpunit/php-token-stream",
+ "version": "1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-token-stream.git",
+ "reference": "1.2.0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1.2.0",
+ "reference": "1.2.0",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "PHP/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Wrapper around PHP's tokenizer extension.",
+ "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
+ "keywords": [
+ "tokenizer"
+ ],
+ "time": "2013-08-04 05:57:48"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "3.7.23",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "3.7.23"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.23",
+ "reference": "3.7.23",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-pcre": "*",
+ "ext-reflection": "*",
+ "ext-spl": "*",
+ "php": ">=5.3.3",
+ "phpunit/php-code-coverage": "~1.2.1",
+ "phpunit/php-file-iterator": ">=1.3.1",
+ "phpunit/php-text-template": ">=1.1.1",
+ "phpunit/php-timer": ">=1.0.4",
+ "phpunit/phpunit-mock-objects": "~1.2.0",
+ "symfony/yaml": "~2.0"
+ },
+ "require-dev": {
+ "pear-pear/pear": "1.9.4"
+ },
+ "suggest": {
+ "ext-json": "*",
+ "ext-simplexml": "*",
+ "ext-tokenizer": "*",
+ "phpunit/php-invoker": ">=1.1.0,<1.2.0"
+ },
+ "bin": [
+ "composer/bin/phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.7.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "PHPUnit/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ "",
+ "../../symfony/yaml/"
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "http://www.phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "time": "2013-08-02 19:14:44"
+ },
+ {
+ "name": "phpunit/phpunit-mock-objects",
+ "version": "1.2.3",
+ "source": {
+ "type": "git",
+ "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git",
+ "reference": "1.2.3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.3.zip",
+ "reference": "1.2.3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "phpunit/php-text-template": ">=1.1.1@stable"
+ },
+ "suggest": {
+ "ext-soap": "*"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "PHPUnit/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Mock Object library for PHPUnit",
+ "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
+ "keywords": [
+ "mock",
+ "xunit"
+ ],
+ "time": "2013-01-13 10:24:48"
+ },
+ {
+ "name": "symfony/yaml",
+ "version": "v2.3.2",
+ "target-dir": "Symfony/Component/Yaml",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/Yaml.git",
+ "reference": "v2.3.2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.3.2",
+ "reference": "v2.3.2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Symfony\\Component\\Yaml\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "http://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Yaml Component",
+ "homepage": "http://symfony.com",
+ "time": "2013-07-11 19:36:36"
+ }
+ ],
+ "aliases": [
+
+ ],
+ "minimum-stability": "stable",
+ "stability-flags": [
+
+ ],
+ "platform": [
+
+ ],
+ "platform-dev": [
+
+ ]
+}
--- /dev/null
+<?php
+
+class PegpInput
+{
+ public $data, $length, $pos;
+
+ public function __construct($data, $length=null, $pos=0)
+ {
+ $this->data = $data;
+ $this->length = $length ? $length : strlen($data);
+ $this->pos = $pos;
+ }
+
+ public function pick($length=PHP_INT_MAX)
+ {
+ $length = min($length, $this->length - $this->pos);
+ if ($length > 0)
+ return substr($this->data, $this->pos, $length);
+ else
+ return '';
+ }
+
+ public function advance($len)
+ {
+ return new PegpInput($this->data, $this->length, $this->pos + $len);
+ }
+}
+
--- /dev/null
+<?php
+
+abstract class PegpParser
+{
+ public $comment = null;
+ private $drop = false;
+ private $value = null;
+
+ public function parseString($string)
+ {
+ $input = new PegpInput($string);
+ $result = $this->parse($input);
+ if (!$result->isSuccess())
+ throw new Exception('Parse failed. Expected ' . $result->result->getComment() . ' at ' . $result->input->pos);
+ if ($input->length != $result->input->pos)
+ throw new Exception('Parse failed. Unparsed tail at ' . $result->input->pos);
+ return $result->result;
+ }
+
+ public function parse(PegpInput $input)
+ {
+ $result = $this->doParse($input);
+ if ($result->isSuccess()) {
+ return $this->process($result);
+ } else {
+ return $result;
+ }
+ }
+
+ public abstract function doParse(PegpInput $input);
+
+ protected function process($result)
+ {
+ if ($this->drop) {
+ return PegpResult::success($result->input, null);
+ } elseif ($this->value !== null) {
+ return PegpResult::success($result->input, $this->value);
+ } else {
+ return $result;
+ }
+ }
+
+ public function getComment()
+ {
+ return $this->comment;
+ }
+
+ public function setComment($comment)
+ {
+ $this->comment = $comment;
+ return $this;
+ }
+
+ public function drop()
+ {
+ $this->drop = true;
+ return $this;
+ }
+
+ public function value($value)
+ {
+ $this->value = $value;
+ return $this;
+ }
+}
+
+class PegpString extends PegpParser
+{
+ private $str, $caseInsensitive;
+
+ public function __construct($str, $caseInsensitive=false)
+ {
+ $this->str = $str;
+ $this->caseInsensitive = $caseInsensitive;
+ }
+
+ public function doParse(PegpInput $input)
+ {
+ $len = strlen($this->str);
+ if (0 == substr_compare($input->data, $this->str, $input->pos, $len, $this->caseInsensitive)) { // ?? len
+ return PegpResult::success(
+ $input->advance($len),
+ $this->str
+ );
+ } else {
+ return PegpResult::failure($input, $this);
+ }
+ }
+
+ public function getComment()
+ {
+ if ($this->comment !== null)
+ return $this->comment;
+ else
+ return '<string '.$this->str.'>';
+ }
+}
+
+class PegpRegex extends PegpParser
+{
+ private $expr;
+
+ public function __construct($expr, $flags='', $delimiter='#')
+ {
+ $this->expr = $delimiter . '^' . $expr . $delimiter . $flags;
+ }
+
+ public function doParse(PegpInput $input)
+ {
+ if (preg_match($this->expr, $input->pick(), $m)) {
+ return PegpResult::success(
+ $input->advance(strlen($m[0])),
+ $m
+ );
+ } else {
+ return PegpResult::failure($input, $this);
+ }
+ }
+
+ public function getComment()
+ {
+ if ($this->comment !== null)
+ return $this->comment;
+ else
+ return '<regexp '.$this->expr.'>';
+ }
+}
+
+class PegpSequence extends PegpParser
+{
+ private $parsers, $op = null;
+
+ public function __construct(array $parsers)
+ {
+ $this->parsers = $parsers;
+ }
+
+ public function doParse(PegpInput $input)
+ {
+ $inp = $input;
+ $result = array();
+ foreach ($this->parsers as $parser) {
+ $r = $parser->parse($inp);
+ if ($r->isSuccess()) {
+ $inp = $r->input;
+ if ($r->result !== null)
+ $result[] = $r->result;
+ } else {
+ return PegpResult::failure($inp, $parser);
+ }
+ }
+ return PegpResult::success($inp, $result);
+ }
+
+ protected function process($result)
+ {
+ switch ($this->op) {
+ case 'join':
+ $result = PegpResult::success($result->input, implode('', $result->result));
+ break;
+ case 'bitOr':
+ $value = 0;
+ foreach ($result->result as $v)
+ $value |= $v;
+ $result = PegpResult::success($result->input, $value);
+ break;
+ case 'sum':
+ $value = 0;
+ foreach ($result->result as $v)
+ $value += $v;
+ $result = PegpResult::success($result->input, $value);
+ break;
+ case 'product':
+ $value = 1;
+ foreach ($result->result as $v)
+ $value *= $v;
+ $result = PegpResult::success($result->input, $value);
+ break;
+ }
+ return parent::process($result);
+ }
+
+ public function join()
+ {
+ $this->op = 'join';
+ return $this;
+ }
+
+ public function bitOr()
+ {
+ $this->op = 'bitOr';
+ return $this;
+ }
+
+ public function sum()
+ {
+ $this->op = 'sum';
+ return $this;
+ }
+
+ public function product()
+ {
+ $this->op = 'product';
+ return $this;
+ }
+}
+
+class PegpOneOf extends PegpParser
+{
+ private $parsers;
+
+ public function __construct(array $parsers)
+ {
+ $this->parsers = $parsers;
+ }
+
+ public function doParse(PegpInput $input)
+ {
+ foreach ($this->parsers as $parser) {
+ $r = $parser->parse($input);
+ if ($r->isSuccess()) {
+ return $r;
+ }
+ }
+ return PegpResult::failure($input, $this);
+ }
+
+ public function getComment()
+ {
+ if ($this->comment !== null)
+ return $this->comment;
+ $comment = array();
+ foreach ($this->parsers as $parser) {
+ $comment[] = $parser->getComment();
+ }
+ return 'one of: '.implode(', ', $comment);
+ }
+}
+
+class PegpOptional extends PegpParser
+{
+ private $parser, $emptyValue;
+
+ public function __construct(PegpParser $parser, $emptyValue='')
+ {
+ $this->parser = $parser;
+ $this->emptyValue = $emptyValue;
+ }
+
+ public function doParse(PegpInput $input)
+ {
+ $r = $this->parser->parse($input);
+ if ($r->isSuccess()) {
+ return $r;
+ } else {
+ return PegpResult::success($input, $this->emptyValue);
+ }
+ }
+}
+
--- /dev/null
+<?php
+
+class PegpResult
+{
+ private $success;
+ public $input, $result;
+
+ public function __construct($success, PegpInput $input, $result=null)
+ {
+ $this->success = $success;
+ $this->input = $input;
+ $this->result = $result;
+ }
+
+ public static function success(PegpInput $input, $result=null)
+ {
+ return new PegpResult(true, $input, $result);
+ }
+
+ public static function failure(PegpInput $input, $parser=null)
+ {
+ return new PegpResult(false, $input, $parser);
+ }
+
+ public function isSuccess()
+ {
+ return $this->success;
+ }
+}
+
--- /dev/null
+<?php
+
+final class Pegp
+{
+ public static function str($str)
+ {
+ return new PegpString($str);
+ }
+
+ public static function stri($str)
+ {
+ return new PegpString($str, true);
+ }
+
+ public static function re($expr, $flags='', $delimiter='#')
+ {
+ return new PegpRegex($expr, $flags, $delimiter);
+ }
+
+ public static function seq()
+ {
+ return new PegpSequence(func_get_args());
+ }
+
+ public static function oneOf()
+ {
+ return new PegpOneOf(func_get_args());
+ }
+
+ public static function optional($parser, $emptyValue='')
+ {
+ return new PegpOptional($parser, $emptyValue);
+ }
+}
+
--- /dev/null
+<?php
+
+class CalculatorTest extends PHPUnit_Framework_TestCase
+{
+ public function assertParse($parser, $input)
+ {
+ $i = new PegpInput($input);
+ $r = $parser->parse($i);
+ $this->assertInstanceOf('PegpResult', $r);
+ $inputAfter = $r->input;
+ $this->assertInstanceOf('PegpInput', $inputAfter);
+
+ if (!$r->isSuccess()) {
+ echo 'Parse failed. Expected ' . $r->result . ' at ' . $r->input->pos . "\n";
+ }
+
+ $this->assertTrue($r->isSuccess());
+ $this->assertEquals($i->data, $inputAfter->data);
+ $this->assertEquals($i->length, $inputAfter->length);
+ $this->assertEquals($i->length, $inputAfter->pos);
+ return $r->result;
+ }
+
+ public function testString()
+ {
+ $p = Pegp::str('test');
+ $this->assertParse($p, 'test');
+ }
+
+ public function testRegex()
+ {
+ $p = Pegp::re('te[xs]t');
+ $this->assertParse($p, 'test');
+ $this->assertParse($p, 'text');
+ }
+
+ public function testSQLStringLiteral()
+ {
+ $p = Pegp::re("'([^\\\\']*[\\\\']')*[^\\\\']*'");
+ $this->assertParse($p, "''");
+ $this->assertParse($p, "'Hello there'");
+ $this->assertParse($p, "'Don\\'t worry. Be happy!'");
+ $this->assertParse($p, "'Don''t worry. Be happy!'");
+ }
+
+ public function testDecimal()
+ {
+ $p = Pegp::re("\\d+(\\.\\d+)?");
+ $r = $this->assertParse($p, '123.45');
+ $this->assertEquals('.45', $r[1]);
+ }
+
+ public function testSequence()
+ {
+ $word = Pegp::re('[a-z]+');
+ $space = Pegp::re('\s+');
+ $optSpace = Pegp::re('\s*');
+ $punctuation = Pegp::re('[.!?]')->setComment('punctiation mark');
+ $p = Pegp::seq($optSpace, $word, $space, $word, $space, $word, $optSpace, $punctuation, $optSpace);
+
+ $r = $this->assertParse($p, "\thow are you \n ? ");
+ }
+}
+
--- /dev/null
+<?php
+
+class PropertiesTest extends PHPUnit_Framework_TestCase
+{
+ public function assertParse($expected, $parser, $input)
+ {
+ $i = new PegpInput($input);
+ $r = $parser->parse($i);
+ $this->assertInstanceOf('PegpResult', $r);
+ $inputAfter = $r->input;
+ $this->assertInstanceOf('PegpInput', $inputAfter);
+
+ if (!$r->isSuccess()) {
+ echo 'Parse failed. Expected ' . $r->result->getComment() . ' at ' . $r->input->pos . "\n";
+ }
+
+ $this->assertTrue($r->isSuccess());
+ $this->assertEquals($i->data, $inputAfter->data);
+ $this->assertEquals($i->length, $inputAfter->length);
+ $this->assertEquals($i->length, $inputAfter->pos);
+ $this->assertEquals($expected, $r->result);
+ }
+
+ public function testProperties()
+ {
+ $p =
+ Pegp::oneOf(
+ Pegp::stri('default'),
+ Pegp::stri('us'),
+ Pegp::stri('european'),
+ Pegp::seq(
+ Pegp::optional(
+ Pegp::seq(
+ Pegp::oneOf(
+ Pegp::stri('big-endian'),
+ Pegp::stri('little-endian'),
+ Pegp::stri('middle-endian')),
+ Pegp::re('\s+')->drop())->join()),
+ Pegp::oneOf(
+ Pegp::stri('slashes')->value('/'),
+ Pegp::stri('dots')->value('.'),
+ Pegp::stri('hyphens')->value('-'),
+ Pegp::stri('spaces')->value(' '))));
+
+ $this->assertParse('us', $p, 'us');
+ $this->assertParse(array('big-endian', '-'), $p, 'Big-endian hyphEns');
+ $this->assertParse(array('little-endian', '.'), $p, 'little-endian dots');
+ $this->assertParse(array('middle-endian', '/'), $p, 'Middle-Endian Slashes');
+ $this->assertParse(array('big-endian', ' '), $p, 'big-endian spaces');
+ $this->assertParse(array('', '-'), $p, 'Hyphens');
+ }
+}
+