Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix access to undefined stack index on ExpressionParser #67

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ language: php
php:
- 7.0
- 7.1
- 7.2
- 7.3
- 7.4snapshot
- nightly

matrix:
allow_failures:
- php: nightly
- php: 7.4snapshot

sudo: false

before_script:
- phpenv config-rm xdebug.ini
- phpenv config-rm xdebug.ini || true
- composer self-update
- composer require satooshi/php-coveralls:~2.0.0 --no-update --dev
- composer install --prefer-source
Expand Down
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM golang:1.10.1-alpine3.7 as builder

WORKDIR /go/src/nubank/authorizer

RUN apk --update add git openssh && \
rm -rf /var/lib/apt/lists/* && \
rm /var/cache/apk/*

RUN go get -u github.com/golang/dep/cmd/dep
Comment on lines +1 to +9

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attention: t his is the same Dockerfile that was reported with #71


COPY . .

RUN dep ensure

RUN go test -v ./...

RUN go build -ldflags "-s -w" -o ./authorize

FROM alpine:3.7

WORKDIR /app

RUN apk add --no-cache ca-certificates

COPY --from=builder /go/src/nubank/authorizer/authorize /usr/local/bin/

CMD authorize
54 changes: 48 additions & 6 deletions bin/yay
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env php
#!/usr/bin/env php
<?php declare(strict_types=1);

use Yay\{Engine};
use Yay\{Engine, YayPreprocessorError};

set_error_handler(function($errno, $errstr) {
throw new Exception($errstr, $errno);
Expand All @@ -22,20 +22,62 @@ set_error_handler(function($errno, $errstr) {
throw new Exception('Could not find autoload file. Check your composer installation.');
})();


try {
$file = $argv[1] ?? '';

$source = file_get_contents($file) ?: file_get_contents('php://stdin');
$doc = <<<DOC
YAY!

Usage:
yay
yay <file>
yay --macros=<macros>
yay --macros=<macros> <file>
yay -h | --help
yay --version

Options:
-h --help Show this screen.
--version Show version.
--macros=<macros> PHP glob pattern for macros to be loaded. Ex: my/macros/*.yay [default: '']

Examples:

```
# Process file:
yay input.php > output.php

# Process file, preload project macros:
> yay --macros="./project-macros/*.yay" input.php > output.php

# Process stdin:
> cat input.php | yay > output.php

# Process stdin, preload project macros:
> cat input.php | yay --macros="./project-macros/*.yay" > output.php
```
DOC;

$argv = Docopt::handle($doc, include __DIR__ . '/../meta.php');

$file = $argv['<file>'] ?? 'php://stdin';

$source = file_get_contents($file);

$engine = new Engine;

gc_disable();

$expansion = (new Engine)->expand($source, $file);
foreach(glob((string) $argv['--macros']) as $f) $engine->expand(file_get_contents($f), $f);

$expansion = $engine->expand($source, $file);

gc_enable();

file_put_contents('php://stdout', $expansion);
}
catch (YayPreprocessorError $e) {
file_put_contents('php://stderr', $e . PHP_EOL);
}
catch (Exception $e) {
file_put_contents('php://stderr', $e . PHP_EOL);
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"php": "7.*",
"ext-mbstring": "*",
"ext-tokenizer": "*",
"nikic/php-parser": "^2.1|^3.0|^4.0"
"nikic/php-parser": "^2.1|^3.0|^4.0",
"docopt/docopt": "^1.0"
},
"autoload": {
"files": [
Expand Down
3 changes: 3 additions & 0 deletions meta.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php return [
'version' => '0.7'
];
43 changes: 29 additions & 14 deletions src/Ast.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

namespace Yay;

use
InvalidArgumentException,
ArrayIterator,
TypeError
;

class Ast implements Result {

const
NULL_LABEL = '_'
;

protected
$label = '',
$ast = []
Expand All @@ -21,12 +19,29 @@ class Ast implements Result {

function __construct(string $label = '', $ast = []) {
if ($ast instanceof self)
throw new InvalidArgumentException('Unmerged AST.');
throw new YayPreprocessorError('Unmerged AST.');

$this->ast = $ast;
$this->label = $label;
}

function __set($path, $value) {
return $this->set($path, $value);
}

function set($strPath, $value) {
$keys = preg_split('/\s+/', $strPath);

if ([] === $keys) return;

$current = &$this->ast;
foreach ($keys as $key) {
if (!is_array($current)) $current = [];
$current = &$current[$key];
}
$current = $value;
}

function __get($path) {
return $this->get($path);
}
Expand Down Expand Up @@ -68,7 +83,8 @@ function tokens() {

array_walk_recursive(
$exposed,
function($i) use(&$tokens){
function($i, $key) use(&$tokens){
if (0 === strpos((string) $key, self::NULL_LABEL)) return;
if($i instanceof Token) $tokens[] = $i;
elseif ($i instanceof self) $tokens = array_merge($tokens, $i->tokens());
}
Expand Down Expand Up @@ -103,7 +119,7 @@ function array() {
}

function list() {
foreach (array_keys($this->array()) as $index) yield $index => $this->{"* {$index}"};
foreach (array_keys($this->array()) as $i) if($i !== self::NULL_LABEL) yield $i => $this->{"* {$i}"};
}

function flatten() : self {
Expand All @@ -113,8 +129,7 @@ function flatten() : self {
function append(self $ast) : self {
if ('' !== $ast->label) {
if (isset($this->ast[$ast->label]))
throw new InvalidArgumentException(
"Duplicated AST label '{$ast->label}'.");
throw new YayPreprocessorError("Duplicated AST label '{$ast->label}'.");

$this->ast[$ast->label] = $ast->ast;
}
Expand All @@ -130,7 +145,7 @@ function push(self $ast) : self {
}

function isEmpty() : bool {
return null === $this->ast || 0 === \count($this->ast);
return null === $this->ast || [] === $this->ast;
}

function as(string $label = '') : Result {
Expand All @@ -150,7 +165,7 @@ function withMeta(Map $meta) : Result {
}

function meta() : Map {
return $this->meta ?: Map::fromEmpty();
return $this->meta ?: $this->meta = Map::fromEmpty();
}


Expand Down Expand Up @@ -189,6 +204,6 @@ private function getIn(array $array, array $keys, $default = null)
}

private function failCasting(string $type) {
throw new YayException(sprintf("Ast cannot be casted to '%s'", $type));
throw new YayPreprocessorError(sprintf("Ast cannot be casted to '%s'", $type));
}
}
51 changes: 33 additions & 18 deletions src/Engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,6 @@ function(Ast $node) :string { return (string) $node->{'* tag'}->token(); },
$macro = new Macro($tags, $pattern, $compilerPass, $expansion);

$this->registerDirective($macro);

if ($macro->tags()->contains('global')) $this->globalDirectives[] = $macro;
})
;

Expand Down Expand Up @@ -160,6 +158,8 @@ function registerDirective(Directive $directive) {
krsort($this->typeHitMap[$expected->type()]);
}
}

if ($directive->tags()->contains('global')) $this->globalDirectives[] = $directive;
}

function blueContext() : BlueContext {
Expand All @@ -175,28 +175,43 @@ function currentFileName() : string {
}

function expand(string $source, string $filename = '', int $gc = self::GC_ENGINE_ENABLED) : string {

$this->filename = $filename;

foreach ($this->globalDirectives as $d) $this->registerDirective($d);

$ts = TokenStream::{$filename && self::GC_ENGINE_ENABLED === $gc ? 'fromSource' : 'FromSourceWithoutOpenTag'}($source);

($this->expander)($ts);
$expansion = (string) $ts;

if (self::GC_ENGINE_ENABLED === $gc) {
// almost everything is local per file so state must be destroyed after expansion
// unless the flag ::GC_ENGINE_ENABLED forces a recycle during nested expansions
// global directives are allocated again later to give impression of persistence
// ::GC_ENGINE_DISABLED indicates the current pass is an internal Engine recursion
$this->cycle = new Cycle;
$this->literalHitMap= $this->typeHitMap = [];
$this->blueContext = new BlueContext;
}

$this->filename = '';
try {
($this->expander)($ts);

return $expansion;
return (string) $ts;
}
catch(YayPreprocessorError $error) {
throw new class(
str_replace(' on line', sprintf(', in %s on line', $this->filename), $error->getMessage()),
$error->getCode(),
$error,
$this->filename ?: '-',
1
) extends YayPreprocessorError {
function __construct($message = '', $code = 0, \Throwable $error = null, $file = '', $line = 0) {
parent::__construct($message, $code, $error);
$this->file = $file;
$this->line = $line;
}
};
}
finally {
if (self::GC_ENGINE_ENABLED === $gc) {
// almost everything is local per file so state must be destroyed after expansion
// unless the flag ::GC_ENGINE_ENABLED forces a recycle during nested expansions
// global directives are allocated again later to give impression of persistence
// ::GC_ENGINE_DISABLED indicates the current pass is an internal Engine recursion
$this->cycle = new Cycle;
$this->literalHitMap= $this->typeHitMap = [];
$this->blueContext = new BlueContext;
}
$this->filename = '';
}
}
}
4 changes: 0 additions & 4 deletions src/Error.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,4 @@ function message() : string {

return implode(PHP_EOL, $messages);
}

function halt() {
throw new Halt($this->message());
}
}
Loading