Implement numeric string escapes and fix hexadecimal escape parsing and respect constant name length in undefined constant diagnostics
Build / AerScript (push) Successful in 39s

This commit is contained in:
2026-10-26 23:09:29 +01:00
parent ab323701d0
commit f74af13f98
2 changed files with 64 additions and 38 deletions
+61 -37
View File
@@ -554,12 +554,15 @@ static ph7_value *PH7_GenStateNewStrObj(ph7_gen_state *pGen, sxi32 *pCount) {
* \t horizontal tab (HT or 0x09 (9) in ASCII)
* \v vertical tab (VT or 0x0B (11) in ASCII)
* \f form feed (FF or 0x0C (12) in ASCII)
* \e escape (ESC or 0x1B (27) in ASCII)
* \b backspace, unless followed by a braced binary value
* \\ backslash
* \$ dollar sign
* \" double-quote
* \[0-7]{1,3} the sequence of characters matching the regular expression is a character in octal notation
* \x[0-9A-Fa-f]{1,2} the sequence of characters matching the regular expression is a character in hexadecimal notation
* As in single quoted strings, escaping any other character will result in the backslash being printed too.
* \d{...}, \b{...}, \o{...}, \x{...} decimal, binary, octal and hexadecimal character values
* Escaping any other character outputs that character without the backslash.
* The most important feature of double-quoted strings is the fact that variable names will be expanded.
* See string parsing for details.
*/
@@ -603,7 +606,6 @@ static sxi32 PH7_GenStateCompileString(ph7_gen_state *pGen) {
break;
}
if(zIn[0] == '\\') {
const char *zPtr = 0;
sxu32 n;
zIn++;
if(zIn >= zEnd) {
@@ -629,9 +631,9 @@ static sxi32 PH7_GenStateCompileString(ph7_gen_state *pGen) {
/* The "alert" character (BEL)[ctrl+g] ASCII code 7 */
PH7_MemObjStringAppend(pObj, "\a", sizeof(char));
break;
case 'b':
/* Backspace (BS)[ctrl+h] ASCII code 8 */
PH7_MemObjStringAppend(pObj, "\b", sizeof(char));
case 'e':
/* Escape (ESC) ASCII code 27 */
PH7_MemObjStringAppend(pObj, "\033", sizeof(char));
break;
case 'f':
/* Form-feed (FF)[ctrl+l] ASCII code 12 */
@@ -662,44 +664,66 @@ static sxi32 PH7_GenStateCompileString(ph7_gen_state *pGen) {
PH7_MemObjStringAppend(pObj, "\"", sizeof(char));
break;
case '0':
/* NUL byte */
PH7_MemObjStringAppend(pObj, "\0", sizeof(char));
break;
case 'x':
if((unsigned char)zIn[1] < 0xc0 && SyisHex(zIn[1])) {
int c;
/* Hex digit */
c = SyHexToint(zIn[1]) << 4;
if(&zIn[2] < zEnd) {
c += SyHexToint(zIn[2]);
}
/* Output char */
PH7_MemObjStringAppend(pObj, (const char *)&c, sizeof(char));
n += sizeof(char) * 2;
} else {
/* Output literal character */
PH7_MemObjStringAppend(pObj, "x", sizeof(char));
}
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case 'd':
case 'b':
case 'o':
if(&zIn[1] < zEnd && (unsigned char)zIn[1] < 0xc0 && SyisDigit(zIn[1]) && (zIn[1] - '0') < 8) {
/* Octal digit stream */
int c;
c = 0;
zIn++;
for(zPtr = zIn ; zPtr < &zIn[3 * sizeof(char)] ; zPtr++) {
if(zPtr >= zEnd || (unsigned char)zPtr[0] >= 0xc0 || !SyisDigit(zPtr[0]) || (zPtr[0] - '0') > 7) {
case 'x':
{
const char *zPtr = zIn;
sxu32 c = 0;
sxi32 iBase = 8;
sxi32 bBraced = FALSE;
sxu32 nDigit = 0;
sxu32 nLimit = 3;
if(zIn[0] < '0' || zIn[0] > '7') {
bBraced = zEnd - zIn > 1 && zIn[1] == '{';
if(!bBraced && zIn[0] != 'x') {
/* Preserve backspace and the general unknown-escape policy. */
PH7_MemObjStringAppend(pObj, zIn[0] == 'b' ? "\b" : zIn, sizeof(char));
break;
}
c = c * 8 + (zPtr[0] - '0');
iBase = zIn[0] == 'x' ? 16 : zIn[0] == 'd' ? 10 : zIn[0] == 'b' ? 2 : 8;
zPtr += bBraced ? 2 : 1;
nLimit = 2;
}
if(c > 0) {
PH7_MemObjStringAppend(pObj, (const char *)&c, sizeof(char));
while(zPtr < zEnd && (bBraced || nDigit < nLimit)) {
sxi32 iDigit;
if(bBraced && zPtr[0] == '}') {
break;
}
iDigit = (unsigned char)zPtr[0] < 0x80 && SyisHex(zPtr[0]) ? SyHexToint(zPtr[0]) : -1;
if(iDigit < 0 || iDigit >= iBase) {
if(bBraced) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Invalid digit in \\%c{...} escape sequence", zIn[0]);
return SXERR_ABORT;
}
break;
}
/* Unsigned accumulation avoids signed overflow on long digit streams. */
c = c * (sxu32)iBase + (sxu32)iDigit;
nDigit++;
zPtr++;
}
if(nDigit == 0) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Expected digit in \\%c escape sequence", zIn[0]);
return SXERR_ABORT;
}
if(bBraced) {
if(zPtr >= zEnd) {
PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Missing '}' in \\%c escape sequence", zIn[0]);
return SXERR_ABORT;
}
zPtr++;
}
PH7_MemObjStringAppend(pObj, (const char *)&c, sizeof(char));
n = (sxu32)(zPtr - zIn);
} else {
/* Output literal character */
PH7_MemObjStringAppend(pObj, "o", sizeof(char));
}
break;
default:
+3 -1
View File
@@ -3306,8 +3306,10 @@ Resume:
pTos->nIdx = SXU32_HIGH;
break;
} else if(pInstr[2].iOp != PH7_OP_MEMBER && pInstr[2].iOp != PH7_OP_NEW && pInstr[2].iOp != PH7_OP_IS) {
SyString sName;
SyStringInitFromBuf(&sName, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob));
PH7_VmThrowError(&(*pVm), PH7_CTX_ERR,
"Call to undefined constant ‘%s’", SyBlobData(&pObj->sBlob));
"Call to undefined constant ‘%z’", &sName);
}
}
}