Skip to content

Commit 0a8d0cc

Browse files
committed
fixing
1 parent 3c7a5ac commit 0a8d0cc

File tree

4 files changed

+125
-8
lines changed

4 files changed

+125
-8
lines changed

classes/dataflow_lexer.php

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
<?php
2+
// This file is part of Moodle - http://moodle.org/
3+
//
4+
// Moodle is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// Moodle is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16+
17+
namespace tool_dataflows;
18+
19+
use Symfony\Component\ExpressionLanguage\Token;
20+
use Symfony\Component\ExpressionLanguage\SyntaxError;
21+
use Symfony\Component\ExpressionLanguage\TokenStream;
22+
23+
/**
24+
* Class adding modification to Symfony Lexer to suit dataflow needs.
25+
*
26+
* @package tool_dataflows
27+
* @author Ghaly Marc-Alexandre <[email protected]>
28+
* @copyright Catalyst IT, 2023
29+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30+
*/
31+
class dataflow_lexer extends \Symfony\Component\ExpressionLanguage\Lexer {
32+
/**
33+
* Tokenizes an expression.
34+
*
35+
* @param string $expression The expression to tokenize
36+
*
37+
* @return TokenStream A token stream instance
38+
*
39+
* @throws SyntaxError
40+
*/
41+
public function tokenize($expression)
42+
{
43+
$expression = str_replace(["\r", "\n", "\t", "\v", "\f"], ' ', $expression);
44+
$cursor = 0;
45+
$tokens = [];
46+
$brackets = [];
47+
$end = \strlen($expression);
48+
49+
while ($cursor < $end) {
50+
if (' ' == $expression[$cursor]) {
51+
++$cursor;
52+
53+
continue;
54+
}
55+
56+
if (preg_match('/[0-9]+(?:\.[0-9]+)?/A', $expression, $match, 0, $cursor)) {
57+
// Numbers.
58+
// Floats.
59+
$number = (float) $match[0];
60+
if (preg_match('/^[0-9]+$/', $match[0]) && $number <= \PHP_INT_MAX) {
61+
// Integers lower than the maximum.
62+
$number = (int) $match[0];
63+
}
64+
$tokens[] = new Token(Token::NUMBER_TYPE, $number, $cursor + 1);
65+
$cursor += \strlen($match[0]);
66+
} elseif (preg_match("/{'(\W[a-zA-Z_\x7f-\xff][a-zA-Z0-9_.\x7f-\xff]*)'}/A", $expression, $match, 0, $cursor)) {
67+
// Names litteral.
68+
$tokens[] = new Token(Token::NAME_TYPE, $match[1], $cursor + 1);
69+
$cursor += \strlen($match[0]);
70+
} elseif (false !== strpos('([{', $expression[$cursor])) {
71+
// Opening bracket.
72+
$brackets[] = [$expression[$cursor], $cursor];
73+
74+
$tokens[] = new Token(Token::PUNCTUATION_TYPE, $expression[$cursor], $cursor + 1);
75+
++$cursor;
76+
} elseif (false !== strpos(')]}', $expression[$cursor])) {
77+
// Closing bracket.
78+
if (empty($brackets)) {
79+
throw new SyntaxError(sprintf('Unexpected "%s".', $expression[$cursor]), $cursor, $expression);
80+
}
81+
82+
list($expect, $cur) = array_pop($brackets);
83+
if ($expression[$cursor] != strtr($expect, '([{', ')]}')) {
84+
throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $cur, $expression);
85+
}
86+
87+
$tokens[] = new Token(Token::PUNCTUATION_TYPE, $expression[$cursor], $cursor + 1);
88+
++$cursor;
89+
} elseif (preg_match('/"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As', $expression, $match, 0, $cursor)) {
90+
// Strings.
91+
$tokens[] = new Token(Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)), $cursor + 1);
92+
$cursor += \strlen($match[0]);
93+
} 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)) {
94+
// Operators.
95+
$tokens[] = new Token(Token::OPERATOR_TYPE, $match[0], $cursor + 1);
96+
$cursor += \strlen($match[0]);
97+
} elseif (false !== strpos('.,?:', $expression[$cursor])) {
98+
// Punctuation.
99+
$tokens[] = new Token(Token::PUNCTUATION_TYPE, $expression[$cursor], $cursor + 1);
100+
++$cursor;
101+
} elseif (preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A', $expression, $match, 0, $cursor)) {
102+
// Names.
103+
$tokens[] = new Token(Token::NAME_TYPE, $match[0], $cursor + 1);
104+
$cursor += \strlen($match[0]);
105+
} else {
106+
// Unlexable.
107+
throw new SyntaxError(sprintf('Unexpected character "%s".', $expression[$cursor]), $cursor, $expression);
108+
}
109+
}
110+
111+
$tokens[] = new Token(Token::EOF_TYPE, null, $cursor + 1);
112+
113+
if (!empty($brackets)) {
114+
list($expect, $cur) = array_pop($brackets);
115+
throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $cur, $expression);
116+
}
117+
118+
return new TokenStream($tokens, $expression);
119+
}
120+
}

classes/parser.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616

1717
namespace tool_dataflows;
1818

19+
use tool_dataflows\dataflow_lexer;
1920
use Symfony\Component\Cache\Adapter\ApcuAdapter;
2021
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
2122
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
22-
use Symfony\Component\ExpressionLanguage\Lexer;
2323
use Symfony\Component\ExpressionLanguage\Node;
2424
use Symfony\Component\ExpressionLanguage\Token;
2525
use Symfony\Component\ExpressionLanguage\TokenStream;
@@ -80,9 +80,9 @@ private function __construct() {
8080
*
8181
* @return Lexer
8282
*/
83-
private function get_lexer(): Lexer {
83+
private function get_lexer(): dataflow_lexer {
8484
if (is_null($this->lexer)) {
85-
$this->lexer = new Lexer();
85+
$this->lexer = new dataflow_lexer();
8686
}
8787
return $this->lexer;
8888
}

vendor/symfony/expression-language/ExpressionLanguage.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Cache\Adapter\ArrayAdapter;
1616
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheAdapter;
1717
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface;
18+
use tool_dataflows\dataflow_lexer;
1819

1920
/**
2021
* Allows to compile and evaluate expressions written in your own DSL.
@@ -152,7 +153,7 @@ protected function registerFunctions()
152153
private function getLexer()
153154
{
154155
if (null === $this->lexer) {
155-
$this->lexer = new Lexer();
156+
$this->lexer = new dataflow_lexer();
156157
}
157158

158159
return $this->lexer;

vendor/symfony/expression-language/Lexer.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ public function tokenize($expression)
5050
}
5151
$tokens[] = new Token(Token::NUMBER_TYPE, $number, $cursor + 1);
5252
$cursor += \strlen($match[0]);
53-
} elseif (preg_match("/{'(\W[a-zA-Z_\x7f-\xff][a-zA-Z0-9_.\x7f-\xff]*)'}/A", $expression, $match, 0, $cursor)) {
54-
// names litteral
55-
$tokens[] = new Token(Token::NAME_TYPE, $match[1], $cursor + 1);
56-
$cursor += \strlen($match[0]);
5753
} elseif (false !== strpos('([{', $expression[$cursor])) {
5854
// opening bracket
5955
$brackets[] = [$expression[$cursor], $cursor];

0 commit comments

Comments
 (0)