From 801ce595f95dc18131d088f1151d88da2ee1b53d Mon Sep 17 00:00:00 2001 From: Nikolaos Dimopoulos Date: Fri, 10 Apr 2026 18:55:57 -0500 Subject: [PATCH] additional fixes for phql statements --- resources/files/parser.php | 12 +++++++----- src/Scanner/Opcode.php | 22 +++++++++++----------- src/Scanner/Scanner.php | 31 ++++++++++++++++++------------- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/resources/files/parser.php b/resources/files/parser.php index 1da7db0..702ca65 100644 --- a/resources/files/parser.php +++ b/resources/files/parser.php @@ -3992,9 +3992,11 @@ private function yy_reduce(int $yyruleno): void break; case 20: case 27: - case 38: $yygotominor = []; break; + case 38: + $yygotominor = null; + break; case 10: case 17: case 41: @@ -5202,18 +5204,18 @@ function phql_ret_placeholder_zval(array &$ret, int $type, ?Token $value = null) $ret['value'] = $value->getValue() ?? null; } -function phql_ret_raw_qualified_name(array &$ret, string $tokenA, ?string $tokenB = null): void +function phql_ret_raw_qualified_name(array &$ret, Token $tokenA, ?Token $tokenB = null): void { $ret = []; $ret['type'] = Opcode::PHQL_T_RAW_QUALIFIED; if ($tokenB !== null) { /* Two-part qualified name: domain + name */ - $ret['domain'] = $tokenA; // equivalent to phql_add_assoc_stringl(..., "domain", A->token, ...) - $ret['name'] = $tokenB; // equivalent to phql_add_assoc_stringl(..., "name", B->token, ...) + $ret['domain'] = $tokenA->getValue(); + $ret['name'] = $tokenB->getValue(); } else { /* Single-part name */ - $ret['name'] = $tokenA; + $ret['name'] = $tokenA->getValue(); } } diff --git a/src/Scanner/Opcode.php b/src/Scanner/Opcode.php index fcdb592..c0047dc 100644 --- a/src/Scanner/Opcode.php +++ b/src/Scanner/Opcode.php @@ -6,7 +6,7 @@ class Opcode { - public const PHQL_T_ADD = '+'; + public const PHQL_T_ADD = 43; // ord('+') /* Literals & Identifiers */ public const PHQL_T_AGAINST = 276; @@ -18,10 +18,10 @@ class Opcode /* Operators */ public const PHQL_T_BETWEEN = 331; public const PHQL_T_BETWEEN_NOT = 332; - public const PHQL_T_BITWISE_AND = '&'; - public const PHQL_T_BITWISE_NOT = '~'; - public const PHQL_T_BITWISE_OR = '|'; - public const PHQL_T_BITWISE_XOR = '^'; + public const PHQL_T_BITWISE_AND = 38; // ord('&') + public const PHQL_T_BITWISE_NOT = 126; // ord('~') + public const PHQL_T_BITWISE_OR = 124; // ord('|') + public const PHQL_T_BITWISE_XOR = 94; // ord('^') public const PHQL_T_BPLACEHOLDER = 277; public const PHQL_T_BY = 311; public const PHQL_T_CASE = 409; @@ -34,7 +34,7 @@ class Opcode public const PHQL_T_DELETE = 303; public const PHQL_T_DESC = 328; public const PHQL_T_DISTINCT = 330; - public const PHQL_T_DIV = '/'; + public const PHQL_T_DIV = 47; // ord('/') public const PHQL_T_DOMAINALL = 353; public const PHQL_T_DOT = '.'; public const PHQL_T_DOUBLE = 259; @@ -51,7 +51,7 @@ class Opcode public const PHQL_T_FROM = 304; public const PHQL_T_FULL = 325; public const PHQL_T_FULLJOIN = 364; - public const PHQL_T_GREATER = '>'; + public const PHQL_T_GREATER = 62; // ord('>') public const PHQL_T_GREATEREQUAL = 272; public const PHQL_T_GROUP = 313; public const PHQL_T_HAVING = 314; @@ -76,11 +76,11 @@ class Opcode public const PHQL_T_LIKE = 268; public const PHQL_T_LIMIT = 312; public const PHQL_T_MINUS = 367; - public const PHQL_T_MOD = '%'; - public const PHQL_T_MUL = '*'; + public const PHQL_T_MOD = 37; // ord('%') + public const PHQL_T_MUL = 42; // ord('*') public const PHQL_T_NILIKE = 357; public const PHQL_T_NLIKE = 351; - public const PHQL_T_NOT = '!'; + public const PHQL_T_NOT = 33; // ord('!') public const PHQL_T_NOTEQUALS = 270; public const PHQL_T_NOTIN = 323; /** Placeholders */ @@ -102,7 +102,7 @@ class Opcode public const PHQL_T_SPLACEHOLDER = 274; public const PHQL_T_STARALL = 352; public const PHQL_T_STRING = 260; - public const PHQL_T_SUB = '-'; + public const PHQL_T_SUB = 45; // ord('-') public const PHQL_T_SUBQUERY = 407; public const PHQL_T_THEN = 413; public const PHQL_T_TRUE = 334; diff --git a/src/Scanner/Scanner.php b/src/Scanner/Scanner.php index 18f758c..3ac9cca 100644 --- a/src/Scanner/Scanner.php +++ b/src/Scanner/Scanner.php @@ -34,8 +34,9 @@ public function scanForToken(): int return self::PHQL_SCANNER_RETCODE_EOF; } - $q = $yycursor; - $token = $this->token; + $q = $yycursor; + $yymarker = $yycursor; + $token = $this->token; $token->value = null; $token->opcode = null; $token->len = 0; @@ -780,18 +781,21 @@ public function scanForToken(): int break 2; } case 41: + // Use $yymarker (PPMARKER in C re2c) as token start. + // Keyword save-point states (e.g. NOT at state 176) overwrite $yymarker, + // so identifiers like "Notes" yield the post-keyword suffix ("es"). $token->opcode = Opcode::PHQL_T_IDENTIFIER; - if (($yycursor - $q) > 1) { - if ($yyinput[$q] === '\\') { - $token->value = substr($yyinput, $q + 1, $yycursor - $q - 1); - $token->len = $yycursor - $q - 1; + if (($yycursor - $yymarker) > 1) { + if ($yyinput[$yymarker] === '\\') { + $token->value = substr($yyinput, $yymarker + 1, $yycursor - $yymarker - 1); + $token->len = $yycursor - $yymarker - 1; } else { - $token->value = substr($yyinput, $q, $yycursor - $q); - $token->len = $yycursor - $q; + $token->value = substr($yyinput, $yymarker, $yycursor - $yymarker); + $token->len = $yycursor - $yymarker; } } else { - $token->value = substr($yyinput, $q, $yycursor - $q); - $token->len = $yycursor - $q; + $token->value = substr($yyinput, $yymarker, $yycursor - $yymarker); + $token->len = $yycursor - $yymarker; } $q = $yycursor; $this->state->setCursor($yycursor); @@ -2697,10 +2701,11 @@ public function scanForToken(): int } case 138: // Bracket-enclosed identifier: [name] or [First Name] - // Strip the opening [ and closing ] from the value + // Use $yymarker (set by state 56 after '[', updated by state 193 after '\]') + // so that escaped-bracket sequences correctly yield the post-escape substring. $token->opcode = Opcode::PHQL_T_IDENTIFIER; - $token->value = substr($yyinput, $q + 1, $yycursor - $q - 2); - $token->len = $yycursor - $q - 2; + $token->value = substr($yyinput, $yymarker, $yycursor - $yymarker - 1); + $token->len = $yycursor - $yymarker - 1; $q = $yycursor; $this->state->setCursor($yycursor); return 0;