Skip to content

Commit

Permalink
Merge branch 'master' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
marcioAlmada committed Feb 27, 2017
2 parents d20c1fc + 1f4d4ee commit b2705d7
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ sudo: false
before_script:
- composer self-update
- composer require satooshi/php-coveralls:dev-master --no-update --dev
- composer install --dev --prefer-source
- composer install --prefer-source

script:
- php vendor/bin/phpunit
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"php": "7.*",
"ext-mbstring": "*",
"ext-tokenizer": "*",
"nikic/php-parser": "^2.0"
"nikic/php-parser": "^2.1|^3.0"
},
"autoload": {
"files": [
Expand Down
15 changes: 1 addition & 14 deletions src/Error.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,7 @@ function message() : string {

$messages = [];
foreach ($errors as $prefix => $expected) {
$messages[] = $prefix . sprintf(
self::EXPECTED,
implode(
' or ',
array_unique(
array_map(
function(Token $t) {
return $t->dump();
},
$expected->all()
)
)
)
);
$messages[] = $prefix . sprintf(self::EXPECTED, (string) $expected);
}

return implode(PHP_EOL, $messages);
Expand Down
20 changes: 18 additions & 2 deletions src/Expansion.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ private function compile(array $expansion, Map $context) : TokenStream {
(
rtoken('/^·\w+|···\w+$/')->as('label')
,
optional(token('?'))->as('optional')
,
operator('···')
,
optional
Expand All @@ -124,7 +126,8 @@ private function compile(array $expansion, Map $context) : TokenStream {
braces()->as('expansion')
)
->onCommit(function(Ast $result) use($cg) {
$this->lookupContext($result->label, $cg->context, self::E_UNDEFINED_EXPANSION);
if (null !== $result->optional)
$this->lookupContext($result->label, $cg->context, self::E_UNDEFINED_EXPANSION);
$this->constant = false;
})
,
Expand Down Expand Up @@ -204,6 +207,8 @@ private function mutate(TokenStream $ts, Ast $context, Engine $engine) : TokenSt
(
rtoken('/^·\w+|···\w+$/')->as('label')
,
optional(token('?'))->as('optional')
,
operator('···')
,
optional
Expand All @@ -217,7 +222,12 @@ private function mutate(TokenStream $ts, Ast $context, Engine $engine) : TokenSt
->onCommit(function(Ast $result) use($states) {
$cg = $states->current();

$context = $cg->this->lookupContext($result->{'label'}, $cg->context, self::E_UNDEFINED_EXPANSION);
if (null !== $result->optional)
$context = $cg->this->lookupContextOptional($result->{'label'}, $cg->context);
else
$context = $cg->this->lookupContext($result->{'label'}, $cg->context, self::E_UNDEFINED_EXPANSION);

if ($context === null) return;

$delimiters = $result->{'delimiters'};

Expand Down Expand Up @@ -326,4 +336,10 @@ private function lookupContext(Token $token, Context $context, string $error) /*

return $result;
}

private function lookupContextOptional(Token $token, Context $context) /*: Token | []Token*/ {
$symbol = (string) $token;

return $context->get($symbol);
}
}
27 changes: 26 additions & 1 deletion src/Expected.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class Expected {

protected $tokens;
protected $tokens, $negation = false;

function __construct(Token ...$tokens) {
$this->tokens = $tokens;
Expand All @@ -18,8 +18,33 @@ function all() : array {
return $this->tokens;
}

function negate() : self {
$expected = clone $this;
$expected->negation = true;

return $expected;
}

function __toString() : string {
return
($this->negation ? 'not ' : '') .
implode(
' or ' . ($this->negation ? 'not ' : ''),
array_unique(
array_map(
function(Token $t) {
return $t->dump();
},
$this->all()
)
)
)
;
}

function raytrace() : string {
return
($this->negation ? 'not ' : '') .
implode(
' | ',
array_map(
Expand Down
2 changes: 0 additions & 2 deletions src/Token.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class Token implements \JsonSerializable {
const
ANY = 1021,
NONE = 1032,
MATCH = 1043,
OPERATOR = 1054,
CLOAKED = 1065
;
Expand All @@ -27,7 +26,6 @@ class Token implements \JsonSerializable {
const TOKENS = [
self::ANY => 'ANY',
self::NONE => 'NONE',
self::MATCH => 'MATCH',
self::OPERATOR => 'OPERATOR',
self::CLOAKED => 'CLOAKED'
];
Expand Down
12 changes: 12 additions & 0 deletions src/expanders.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ function stringify(TokenStream $ts) : TokenStream {
;
}

function unvar(TokenStream $ts) : TokenStream {
$str = preg_replace('/^\$+/', '', (string) $ts);

return
TokenStream::fromSequence(
new Token(
T_CONSTANT_ENCAPSED_STRING, $str
)
)
;
}

function concat(TokenStream $ts) : TokenStream {
$ts->reset();
$buffer = '';
Expand Down
7 changes: 4 additions & 3 deletions src/parsers.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,13 @@ protected function parser(TokenStream $ts, string $regexp) /*: Result|null*/
return new Ast($this->label, $token);
}

return $this->error($ts);
if ($this->errorLevel === Error::ENABLED)
return new Error(new Expected(new Token(T_STRING, "matching '{$regexp}'")), $ts->current(), $ts->last());
}

function expected() : Expected
{
return new Expected(new Token(Token::MATCH, $this->stack[0]));
return new Expected(new Token(T_STRING), new Token(T_VARIABLE));
}

function isFallible() : bool
Expand Down Expand Up @@ -874,7 +875,7 @@ protected function parser(TokenStream $ts, Parser $parser) /*: Result|null*/

function expected() : Expected
{
return new Expected;
return $this->stack[0]->expected()->negate();
}

function isFallible() : bool
Expand Down
28 changes: 27 additions & 1 deletion tests/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ function testRtokenOnError() {
$this->parseError(
$ts,
rtoken('/^T_\w+$/'),
"Unexpected T_STRING(T_) on line 1, expected MATCH(/^T_\w+$/)."
"Unexpected T_STRING(T_) on line 1, expected T_STRING(matching '/^T_\w+$/')."
);
}

Expand Down Expand Up @@ -208,6 +208,32 @@ function testOptional() {
$this->parseSuccess($ts, optional(token(T_STRING, 'baz')), "");
}

function testNot() {
$ts = TokenStream::fromSource("<?php foo bar null ");
$this->parseSuccess($ts, token(T_OPEN_TAG), "T_OPEN_TAG(<?php )");
$this->parseSuccess($ts, repeat(chain(not(token(T_STRING, 'null')), token(T_STRING))), "T_STRING(foo), T_STRING(bar)");

$ts = TokenStream::fromSource("<?php foo bar null baz");
$this->parseSuccess($ts, token(T_OPEN_TAG), "T_OPEN_TAG(<?php )");
$this->parseSuccess($ts, repeat(chain(not(token(T_STRING, 'null')), token(T_STRING))), "T_STRING(foo), T_STRING(bar)");

$ts = TokenStream::fromSource("<?php null foo bar");
$this->parseSuccess($ts, token(T_OPEN_TAG), "T_OPEN_TAG(<?php )");
$this->parseError(
$ts,
repeat(chain(not(token(T_STRING, 'null')), token(T_STRING))),
"Unexpected T_STRING(null) on line 1, expected not T_STRING(null)."
);

$ts = TokenStream::fromSource("<?php null foo bar");
$this->parseSuccess($ts, token(T_OPEN_TAG), "T_OPEN_TAG(<?php )");
$this->parseError(
$ts,
repeat(chain(not(either(token(T_STRING, 'null'), token(T_STRING, 'true'), token(T_STRING, 'false'))), token(T_STRING))),
"Unexpected T_STRING(null) on line 1, expected not T_STRING(null) or not T_STRING(true) or not T_STRING(false)."
);
}

function testRepeat() {
$ts = TokenStream::fromSource("<?php foo bar baz 1 2 3 @ ");

Expand Down
133 changes: 133 additions & 0 deletions tests/phpt/property_accessors.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
--TEST--
General property --pretty-print
--FILE--
<?php

macro {
·ns()·class {
···body
}
} >> {
·class {
use \Pre\AccessorsTrait;

···body
}
}

macro {
private T_VARIABLE·variable {
·repeat
(
·either
(
·chain
(
get,
·optional(·chain(·token(':'), ·ns()·_))·getter_return_type,
·between(·token('{'), ·layer(), ·token('}'))·getter_body
)
·getter
,
·chain
(
set,
·token('('),
·layer()·setter_args,
·token(')'),
·optional(·chain(·token(':'), ·ns()·_))·setter_return_type,
·between(·token('{'), ·layer(), ·token('}'))·setter_body
)
·setter
,
·chain
(
unset,
·optional(·chain(·token(':'), ·ns()·_))·unsetter_return_type,
·between(·token('{'), ·layer(), ·token('}'))·unsetter_body
)
·unsetter
)
)
·accessors
};
} >> {
private T_VARIABLE·variable;

·accessors ··· {
·setter ?··· {
private function ··concat(__set_ ··unvar(T_VARIABLE·variable))(·setter_args) ·setter_return_type {
·setter_body
}

}

·getter ?··· {
private function ··concat(__get_ ··unvar(T_VARIABLE·variable))() ·getter_return_type {
·getter_body
}
}

·unsetter ?··· {
private function ··concat(__unset_ ··unvar(T_VARIABLE·variable))() ·unsetter_return_type {
·unsetter_body
}
}
}
}

namespace App;

class Sprocket
{
private $type {
set(string $value) {
$this->type = $value;
}

get :string {
return $this->type;
}

unset {
$this->type = '';
}
};

private $name {
get :string {
return $this->name;
}
};
}

?>
--EXPECTF--
<?php

namespace App;

class Sprocket
{
use \Pre\AccessorsTrait;
private $type;
private function __set_type(string $value)
{
$this->type = $value;
}
private function __get_type() : string
{
return $this->type;
}
private function __unset_type()
{
$this->type = '';
}
private $name;
private function __get_name() : string
{
return $this->name;
}
}

?>

0 comments on commit b2705d7

Please sign in to comment.