Skip to content

Commit

Permalink
fixing
Browse files Browse the repository at this point in the history
  • Loading branch information
marcghaly committed May 15, 2023
1 parent 3c7a5ac commit 0a8d0cc
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 8 deletions.
120 changes: 120 additions & 0 deletions classes/dataflow_lexer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

namespace tool_dataflows;

use Symfony\Component\ExpressionLanguage\Token;
use Symfony\Component\ExpressionLanguage\SyntaxError;
use Symfony\Component\ExpressionLanguage\TokenStream;

/**
* Class adding modification to Symfony Lexer to suit dataflow needs.
*
* @package tool_dataflows
* @author Ghaly Marc-Alexandre <marc-alexandreghaly@catalyst-ca.net>
* @copyright Catalyst IT, 2023
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class dataflow_lexer extends \Symfony\Component\ExpressionLanguage\Lexer {
/**
* Tokenizes an expression.
*
* @param string $expression The expression to tokenize
*
* @return TokenStream A token stream instance
*
* @throws SyntaxError
*/
public function tokenize($expression)
{
$expression = str_replace(["\r", "\n", "\t", "\v", "\f"], ' ', $expression);
$cursor = 0;
$tokens = [];
$brackets = [];
$end = \strlen($expression);

while ($cursor < $end) {
if (' ' == $expression[$cursor]) {
++$cursor;

continue;
}

if (preg_match('/[0-9]+(?:\.[0-9]+)?/A', $expression, $match, 0, $cursor)) {
// Numbers.
// Floats.
$number = (float) $match[0];
if (preg_match('/^[0-9]+$/', $match[0]) && $number <= \PHP_INT_MAX) {
// Integers lower than the maximum.
$number = (int) $match[0];
}
$tokens[] = new Token(Token::NUMBER_TYPE, $number, $cursor + 1);
$cursor += \strlen($match[0]);
} elseif (preg_match("/{'(\W[a-zA-Z_\x7f-\xff][a-zA-Z0-9_.\x7f-\xff]*)'}/A", $expression, $match, 0, $cursor)) {
// Names litteral.
$tokens[] = new Token(Token::NAME_TYPE, $match[1], $cursor + 1);
$cursor += \strlen($match[0]);
} elseif (false !== strpos('([{', $expression[$cursor])) {
// Opening bracket.
$brackets[] = [$expression[$cursor], $cursor];

$tokens[] = new Token(Token::PUNCTUATION_TYPE, $expression[$cursor], $cursor + 1);
++$cursor;
} elseif (false !== strpos(')]}', $expression[$cursor])) {
// Closing bracket.
if (empty($brackets)) {
throw new SyntaxError(sprintf('Unexpected "%s".', $expression[$cursor]), $cursor, $expression);
}

list($expect, $cur) = array_pop($brackets);
if ($expression[$cursor] != strtr($expect, '([{', ')]}')) {
throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $cur, $expression);
}

$tokens[] = new Token(Token::PUNCTUATION_TYPE, $expression[$cursor], $cursor + 1);
++$cursor;
} elseif (preg_match('/"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As', $expression, $match, 0, $cursor)) {
// Strings.
$tokens[] = new Token(Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)), $cursor + 1);
$cursor += \strlen($match[0]);
} elseif (preg_match('/(?<=^|[\s(])not in(?=[\s(])|\!\=\=|(?<=^|[\s(])not(?=[\s(])|(?<=^|[\s(])and(?=[\s(])|\=\=\=|\>\=|(?<=^|[\s(])or(?=[\s(])|\<\=|\*\*|\.\.|(?<=^|[\s(])in(?=[\s(])|&&|\|\||(?<=^|[\s(])matches|\=\=|\!\=|\*|~|%|\/|\>|\||\!|\^|&|\+|\<|\-/A', $expression, $match, 0, $cursor)) {
// Operators.
$tokens[] = new Token(Token::OPERATOR_TYPE, $match[0], $cursor + 1);
$cursor += \strlen($match[0]);
} elseif (false !== strpos('.,?:', $expression[$cursor])) {
// Punctuation.
$tokens[] = new Token(Token::PUNCTUATION_TYPE, $expression[$cursor], $cursor + 1);
++$cursor;
} elseif (preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A', $expression, $match, 0, $cursor)) {
// Names.
$tokens[] = new Token(Token::NAME_TYPE, $match[0], $cursor + 1);
$cursor += \strlen($match[0]);
} else {
// Unlexable.
throw new SyntaxError(sprintf('Unexpected character "%s".', $expression[$cursor]), $cursor, $expression);
}
}

$tokens[] = new Token(Token::EOF_TYPE, null, $cursor + 1);

if (!empty($brackets)) {
list($expect, $cur) = array_pop($brackets);
throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $cur, $expression);
}

return new TokenStream($tokens, $expression);
}
}
6 changes: 3 additions & 3 deletions classes/parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

namespace tool_dataflows;

use tool_dataflows\dataflow_lexer;
use Symfony\Component\Cache\Adapter\ApcuAdapter;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\Lexer;
use Symfony\Component\ExpressionLanguage\Node;
use Symfony\Component\ExpressionLanguage\Token;
use Symfony\Component\ExpressionLanguage\TokenStream;
Expand Down Expand Up @@ -80,9 +80,9 @@ private function __construct() {
*
* @return Lexer
*/
private function get_lexer(): Lexer {
private function get_lexer(): dataflow_lexer {
if (is_null($this->lexer)) {
$this->lexer = new Lexer();
$this->lexer = new dataflow_lexer();
}
return $this->lexer;
}
Expand Down
3 changes: 2 additions & 1 deletion vendor/symfony/expression-language/ExpressionLanguage.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheAdapter;
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface;
use tool_dataflows\dataflow_lexer;

/**
* Allows to compile and evaluate expressions written in your own DSL.
Expand Down Expand Up @@ -152,7 +153,7 @@ protected function registerFunctions()
private function getLexer()
{
if (null === $this->lexer) {
$this->lexer = new Lexer();
$this->lexer = new dataflow_lexer();
}

return $this->lexer;
Expand Down
4 changes: 0 additions & 4 deletions vendor/symfony/expression-language/Lexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@ public function tokenize($expression)
}
$tokens[] = new Token(Token::NUMBER_TYPE, $number, $cursor + 1);
$cursor += \strlen($match[0]);
} elseif (preg_match("/{'(\W[a-zA-Z_\x7f-\xff][a-zA-Z0-9_.\x7f-\xff]*)'}/A", $expression, $match, 0, $cursor)) {
// names litteral
$tokens[] = new Token(Token::NAME_TYPE, $match[1], $cursor + 1);
$cursor += \strlen($match[0]);
} elseif (false !== strpos('([{', $expression[$cursor])) {
// opening bracket
$brackets[] = [$expression[$cursor], $cursor];
Expand Down

0 comments on commit 0a8d0cc

Please sign in to comment.