3 namespace Behat\Transliterator;
5 use RollingCurl\Request;
6 use RollingCurl\RollingCurl;
8 use Yaoi\Command\Option;
10 use Yaoi\String\Lexer\Parsed;
11 use Yaoi\String\Lexer\Parser;
12 use Yaoi\String\Lexer\Renderer;
13 use Yaoi\String\Lexer\Token;
14 use Yaoi\String\StringValue;
15 use Yaoi\String\Parser as StringParser;
18 * Tool for converting char tables for Behat/Transliterator from Perl to PHP
21 class SyncTool extends Command
23 const LIB_VERSION = '1.27';
29 private $nonQuestionBoxFound;
32 public function __construct()
42 $this->tokenizer = new Parser();
43 $this->tokenizer->addLineStopper('#');
44 $this->tokenizer->addQuote('qq{', '}', $escape);
45 $this->tokenizer->addQuote('q{', '}', $escape);
46 $this->tokenizer->addQuote('"', '"');
47 $this->tokenizer->addQuote("'", "'");
48 $this->tokenizer->addBracket('[', ']');
49 $this->tokenizer->addDelimiter(';');
51 $this->renderer = new Renderer();
53 ->setBindKey('-~z', 'z~-')
55 ->keepBoundaries('[');
58 public static function setUpDefinition(\Yaoi\Command\Definition $definition, $options)
60 $definition->name = 'update-data';
61 $definition->description = 'Tool for converting char tables for Behat/Transliterator from Perl to PHP';
64 public function performAction()
66 $rollingCurl = new RollingCurl();
68 foreach ($this->getPerlTablesUrlList() as $url) {
69 $rollingCurl->get($url);
72 $rollingCurl->setCallback(function (Request $request, RollingCurl $rollingCurl) {
73 $this->response->addContent($request->getUrl());
74 $content = $request->getResponseText();
75 $this->parsePerlTable($content);
80 private function removePhpCharTable($phpFilePath, $reason)
82 $this->response->addContent($reason);
83 if (file_exists($phpFilePath)) {
84 if (unlink($phpFilePath)) {
85 $this->response->success('Deleted');
87 $this->response->error('Failed to delete');
90 $this->response->success('No PHP file, skipped');
94 private function pushItem($item)
96 if ($this->itemIndex >= 16) {
97 $this->phpTable = trim($this->phpTable);
98 $this->phpTable .= "\n";
103 $item = new StringValue($item);
104 if ($item->starts('\x') || $item->starts('\n')) {
105 $this->phpTable .= '"' . $item . '", ';
106 $this->nonQuestionBoxFound = true;
108 // TODO check if this hack should be removed for chinese letters
109 if ($item->value === '[?] ') {
110 $item->value = '[?]';
114 if ($item->value !== '[?]') {
115 $this->nonQuestionBoxFound = true;
118 $this->phpTable .= "'" . str_replace(array('\\', '\''), array('\\\\', '\\\''), $item) . "', ";
122 private function tokenizePerlTable($content)
124 $tokens = $this->tokenizer->tokenize($content);
126 $expression = $this->renderer->getExpression($tokens);
127 $statement = $expression->getStatement();
128 /** @var Parsed[] $binds */
129 $binds = $expression->getBinds();
131 $parser = new StringParser($statement);
132 $block = (string)$parser->inner('$Text::Unidecode::Char[', ']');
134 throw new \Exception('Block not found');
136 $this->block = $this->renderer->getExpression($binds[$block])->getStatement();
138 $itemsBind = (string)$parser->inner('[', ']');
144 $items = $binds[$itemsBind];
150 private function parsePerlTable($content)
152 $items = $this->tokenizePerlTable($content);
154 $phpFilePath = __DIR__ . '/data/' . substr($this->block, 1) . '.php';
156 $this->removePhpCharTable($phpFilePath, 'Empty char table for block ' . $this->block);
160 $this->phpTable = <<<PHP
162 \$UTF8_TO_ASCII[$this->block] = array(
166 $itemsExpression = $this->renderer->getExpression($items);
167 $itemsStatement = $itemsExpression->getStatement();
168 $itemsBinds = $itemsExpression->getBinds();
170 $itemsStatement = explode(',', $itemsStatement);
171 $this->itemIndex = 0;
172 $this->nonQuestionBoxFound = false;
173 foreach ($itemsStatement as $item) {
179 if (isset($itemsBinds[$item])) {
180 /** @var Token $token */
181 $token = $itemsBinds[$item];
182 $item = $token->unEscapedContent;
185 $this->pushItem($item);
188 if ($this->nonQuestionBoxFound) {
189 $this->phpTable = trim($this->phpTable) . "\n" . ');' . "\n";
190 if (file_put_contents($phpFilePath, $this->phpTable)) {
191 $this->response->success('Block ' . $this->block . ' converted to ' . $phpFilePath);
193 $this->response->error('Failed to save ' . $phpFilePath);
196 $this->removePhpCharTable($phpFilePath, 'Block ' . $this->block . ' contains only [?]');
201 private function getPerlTablesUrlList()
203 $client = new Client();
205 $page = $client->fetch('http://cpansearch.perl.org/src/SBURKE/Text-Unidecode-' . self::LIB_VERSION . '/lib/Text/Unidecode/');
206 foreach (StringParser::create($page)->innerAll('.pm">', '</a>') as $xXXpm) {
207 $list[] = 'http://cpansearch.perl.org/src/SBURKE/Text-Unidecode-' . self::LIB_VERSION . '/lib/Text/Unidecode/'