diff --git a/engine/api.c b/engine/api.c index b48f024..3dd7fd3 100644 --- a/engine/api.c +++ b/engine/api.c @@ -1776,6 +1776,21 @@ int ph7_value_bool(ph7_value *pVal, int iBool) { MemObjSetType(pVal, MEMOBJ_BOOL); return PH7_OK; } +/* + * [CAPIREF: ph7_value_char()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int ph7_value_char(ph7_value *pVal, int cValue) { + /* Invalidate any prior representation */ + PH7_MemObjRelease(pVal); + if(cValue >= 0 && cValue <= 255) { + pVal->x.iVal = cValue; + } else { + pVal->x.iVal = 0; + } + MemObjSetType(pVal, MEMOBJ_CHAR); + return PH7_OK; +} /* * [CAPIREF: ph7_value_null()] * Please refer to the official documentation for function purpose and expected parameters. @@ -1892,6 +1907,13 @@ int ph7_value_is_float(ph7_value *pVal) { int ph7_value_is_bool(ph7_value *pVal) { return (pVal->iFlags & MEMOBJ_BOOL) ? TRUE : FALSE; } +/* + * [CAPIREF: ph7_value_is_char()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int ph7_value_is_char(ph7_value *pVal) { + return (pVal->iFlags & MEMOBJ_CHAR) ? TRUE : FALSE; +} /* * [CAPIREF: ph7_value_is_void()] * Please refer to the official documentation for function purpose and expected parameters. diff --git a/engine/lexer.c b/engine/lexer.c index 30ac00c..03a2268 100644 --- a/engine/lexer.c +++ b/engine/lexer.c @@ -225,7 +225,7 @@ static sxi32 TokenizeAerScript(SyStream *pStream, SyToken *pToken, void *pUserDa pTmp = (SyToken *)SySetPeek(pTokSet); if(pTmp->nType & PH7_TK_KEYWORD) { sxi32 nID = SX_PTR_TO_INT(pTmp->pUserData); - if((sxu32)nID & (PH7_KEYWORD_ARRAY | PH7_KEYWORD_INT | PH7_KEYWORD_FLOAT | PH7_KEYWORD_STRING | PH7_KEYWORD_OBJECT | PH7_KEYWORD_BOOL | PH7_KEYWORD_VOID)) { + if((sxu32)nID & (PH7_KEYWORD_ARRAY | PH7_KEYWORD_INT | PH7_KEYWORD_FLOAT | PH7_KEYWORD_STRING | PH7_KEYWORD_OBJECT | PH7_KEYWORD_BOOL | PH7_KEYWORD_CHAR | PH7_KEYWORD_VOID)) { pTmp = (SyToken *)SySetAt(pTokSet, pTokSet->nUsed - 2); if(pTmp->nType & PH7_TK_LPAREN) { /* Merge the three tokens '(' 'TYPE' ')' into a single one */ @@ -234,6 +234,8 @@ static sxi32 TokenizeAerScript(SyStream *pStream, SyToken *pToken, void *pUserDa zTypeCast = "(float)"; } else if(nID & PH7_KEYWORD_BOOL) { zTypeCast = "(bool)"; + } else if(nID & PH7_KEYWORD_CHAR) { + zTypeCast = "(char)"; } else if(nID & PH7_KEYWORD_STRING) { zTypeCast = "(string)"; } else if(nID & PH7_KEYWORD_ARRAY) { diff --git a/engine/memobj.c b/engine/memobj.c index c3988ab..86676bc 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -228,6 +228,8 @@ static ph7_real MemObjRealValue(ph7_value *pObj) { static sxi32 MemObjStringValue(SyBlob *pOut, ph7_value *pObj, sxu8 bStrictBool) { if(pObj->iFlags & MEMOBJ_REAL) { SyBlobFormat(&(*pOut), "%.15g", pObj->x.rVal); + } else if(pObj->iFlags & MEMOBJ_CHAR) { + SyBlobFormat(&(*pOut), "%c", pObj->x.iVal); } else if(pObj->iFlags & MEMOBJ_INT) { SyBlobFormat(&(*pOut), "%qd", pObj->x.iVal); /* %qd (BSD quad) is equivalent to %lld in the libc printf */ @@ -239,6 +241,8 @@ static sxi32 MemObjStringValue(SyBlob *pOut, ph7_value *pObj, sxu8 bStrictBool) SyBlobAppend(&(*pOut), "FALSE", sizeof("FALSE") - 1); } } + } else if(pObj->iFlags & MEMOBJ_CHAR) { + SyBlobFormat(&(*pOut), "%c", pObj->x.iVal); } else if(pObj->iFlags & MEMOBJ_HASHMAP) { SyBlobAppend(&(*pOut), "Array", sizeof("Array") - 1); PH7_HashmapUnref((ph7_hashmap *)pObj->x.pOther); @@ -334,6 +338,33 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) { /* NOT REACHED */ return 0; } +/* + * Return the char representation of a given ph7_value. + * This function never fail and always return SXRET_OK. + */ +static ph7_real MemObjCharValue(ph7_value *pObj) { + sxi32 iFlags; + iFlags = pObj->iFlags; + if(iFlags & (MEMOBJ_REAL | MEMOBJ_HASHMAP | MEMOBJ_RES | MEMOBJ_NULL | MEMOBJ_VOID)) { + return 0; + } else if(iFlags & MEMOBJ_INT) { + if(pObj->x.iVal >= 0 && pObj->x.iVal <= 255) { + return pObj->x.iVal; + } else { + return 0; + } + } else if(iFlags & MEMOBJ_STRING) { + SyString sString; + SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); + if(sString.nByte == 0) { + /* Empty string */ + return 0; + } + return (int) sString.zString[0]; + } + /* NOT REACHED */ + return 0; +} /* * Convert a ph7_value to type integer.Invalidate any prior representations. */ @@ -374,6 +405,16 @@ PH7_PRIVATE sxi32 PH7_MemObjToBool(ph7_value *pObj) { } return SXRET_OK; } +PH7_PRIVATE sxi32 PH7_MemObjToChar(ph7_value *pObj) { + if((pObj->iFlags & MEMOBJ_CHAR) == 0) { + /* Preform the conversion */ + pObj->x.iVal = MemObjCharValue(&(*pObj)); + /* Invalidate any prior representations */ + SyBlobRelease(&pObj->sBlob); + MemObjSetType(pObj, MEMOBJ_CHAR); + } + return SXRET_OK; +} /* * Convert a ph7_value to type void.Invalidate any prior representations. */ @@ -1161,6 +1202,8 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "array(string, "; } else if(pVal->iFlags & MEMOBJ_BOOL) { zType = "array(bool, "; + } else if(pVal->iFlags & MEMOBJ_CHAR) { + zType = "array(char, "; } else if(pVal->iFlags & MEMOBJ_RES) { zType = "array(resource, "; } else if(pVal->iFlags & MEMOBJ_VOID) { @@ -1176,6 +1219,8 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "string"; } else if(pVal->iFlags & MEMOBJ_BOOL) { zType = "bool"; + } else if(pVal->iFlags & MEMOBJ_CHAR) { + zType = "char"; } else if(pVal->iFlags & MEMOBJ_RES) { zType = "resource"; } else if(pVal->iFlags & MEMOBJ_VOID) { diff --git a/engine/parser.c b/engine/parser.c index c410525..9f7051e 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -178,6 +178,7 @@ static const ph7_expr_op aOpTable[] = { /* Cast operators */ { {"(int)", sizeof("(int)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_INT }, { {"(bool)", sizeof("(bool)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_BOOL }, + { {"(char)", sizeof("(char)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_CHAR }, { {"(string)", sizeof("(string)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_STR }, { {"(float)", sizeof("(float)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_REAL }, { {"(array)", sizeof("(array)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_ARRAY}, diff --git a/engine/vm.c b/engine/vm.c index de50e7b..14f24fb 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2205,6 +2205,23 @@ static sxi32 VmByteCodeExec( PH7_MemObjToBool(pTos); } break; + /* + * CVT_CHAR: * * * + * + * Force the top of the stack to be a char. + */ + case PH7_OP_CVT_CHAR: +#ifdef UNTRUST + if(pTos < pStack) { + goto Abort; + } +#endif + if((pTos->iFlags & MEMOBJ_CHAR) == 0) { + PH7_MemObjToChar(pTos); + } + /* Invalidate any prior representation */ + MemObjSetType(pTos, MEMOBJ_CHAR); + break; /* * CVT_NULL: * * * * diff --git a/include/ph7int.h b/include/ph7int.h index 2f6e5e1..8b8fc27 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1435,6 +1435,7 @@ enum ph7_vm_op { PH7_OP_SWAP, /* Stack swap */ PH7_OP_YIELD, /* Stack yield */ PH7_OP_CVT_BOOL, /* Boolean cast */ + PH7_OP_CVT_CHAR, /* Char cast */ PH7_OP_CVT_NUMC, /* Numeric (integer,real or both) type cast */ PH7_OP_INCR, /* Increment ++ */ PH7_OP_DECR, /* Decrement -- */