From 74b1c196f99b3e448eea47846db53eadf7e57a6d Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 13 Sep 2018 18:56:01 +0200 Subject: [PATCH 001/296] Treat invalid type name as error. --- engine/compiler.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 9d0dcf7..f4e76bd 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2916,8 +2916,8 @@ static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen } else if(nKey & PH7_KEYWORD_FLOAT) { sArg.nType = MEMOBJ_REAL; } else { - PH7_GenCompileError(&(*pGen), E_WARNING, pGen->pIn->nLine, - "Invalid argument type '%z',Automatic cast will not be performed", + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, + "Unknown data type name '%z'", &pIn->sData); } } else { From ecebbb60949de1d4c992b74e115ab5c6be880e44 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 14 Sep 2018 08:36:00 +0200 Subject: [PATCH 002/296] Use type hinting in standard library. --- engine/vm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 0de3ca5..983a827 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -775,7 +775,7 @@ static sxi32 VmEvalChunk(ph7_vm *pVm, ph7_context *pCtx, SyString *pChunk, int i "protected $line;"\ "protected $trace;"\ "protected $previous;"\ - "public function __construct($message = null, $code = 0, Exception $previous = null){"\ + "public function __construct(string $message = '', int $code = 0, Exception $previous = null){"\ " if( isset($message) ){"\ " $this->message = $message;"\ " }"\ @@ -814,7 +814,7 @@ static sxi32 VmEvalChunk(ph7_vm *pVm, ph7_context *pCtx, SyString *pChunk, int i "}"\ "class ErrorException extends Exception { "\ "protected $severity;"\ - "public function __construct(string $message = null,"\ + "public function __construct(string $message = '',"\ "int $code = 0,int $severity = 1,string $filename = __FILE__ ,int $lineno = __LINE__ ,Exception $previous = null){"\ " if( isset($message) ){"\ " $this->message = $message;"\ @@ -884,7 +884,7 @@ static sxi32 VmEvalChunk(ph7_vm *pVm, ph7_context *pCtx, SyString *pChunk, int i " public function __toBool(){ return (bool)$this->value; }"\ " public function __toFloat(){ return (float)$this->value; }"\ " public function __toString(){ return (string)$this->value; }"\ - " function __construct($v){ $this->value = $v; }"\ + " function __construct(mixed $v){ $this->value = $v; }"\ "}" /* From 8b48786f295e28c92472531adc9cacd3678982e0 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 14 Sep 2018 08:47:16 +0200 Subject: [PATCH 003/296] Add missing data types. --- engine/compiler.c | 50 +++++++++++++++++++++++++++++++++++++++-------- include/ph7int.h | 26 +++++++++++++----------- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index f4e76bd..d124c11 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2909,12 +2909,24 @@ static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen sArg.nType = MEMOBJ_HASHMAP; } else if(nKey & PH7_KEYWORD_BOOL) { sArg.nType = MEMOBJ_BOOL; - } else if(nKey & PH7_KEYWORD_INT) { - sArg.nType = MEMOBJ_INT; - } else if(nKey & PH7_KEYWORD_STRING) { - sArg.nType = MEMOBJ_STRING; + } else if(nKey & PH7_KEYWORD_CALLBACK) { + sArg.nType = MEMOBJ_CALL; + } else if(nKey & PH7_KEYWORD_CHAR) { + sArg.nType = MEMOBJ_CHAR; } else if(nKey & PH7_KEYWORD_FLOAT) { sArg.nType = MEMOBJ_REAL; + } else if(nKey & PH7_KEYWORD_INT) { + sArg.nType = MEMOBJ_INT; + } else if(nKey & PH7_KEYWORD_MIXED) { + sArg.nType = MEMOBJ_MIXED; + } else if(nKey & PH7_KEYWORD_OBJECT) { + sArg.nType = MEMOBJ_OBJ; + } else if(nKey & PH7_KEYWORD_RESOURCE) { + sArg.nType = MEMOBJ_RES; + } else if(nKey & PH7_KEYWORD_STRING) { + sArg.nType = MEMOBJ_STRING; + } else if(nKey & PH7_KEYWORD_VOID) { + sArg.nType = MEMOBJ_VOID; } else { PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Unknown data type name '%z'", @@ -3007,23 +3019,45 @@ static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen /* Hashmap aka 'array' */ c = 'h'; break; + case MEMOBJ_BOOL: + /* Bool */ + c = 'b'; + break; + case MEMOBJ_CALL: + /* Callback */ + c = 'a'; + break; + case MEMOBJ_CHAR: + /* Callback */ + c = 'c'; + break; case MEMOBJ_INT: /* Integer */ c = 'i'; break; - case MEMOBJ_BOOL: - /* Bool */ - c = 'b'; + case MEMOBJ_MIXED: + /* Mixed */ + c = 'm'; + break; + case MEMOBJ_OBJ: + /* Object */ + c = 'o'; break; case MEMOBJ_REAL: /* Float */ c = 'f'; break; + case MEMOBJ_RES: + /* Resource */ + c = 'r'; + break; case MEMOBJ_STRING: /* String */ c = 's'; break; - default: + case MEMOBJ_VOID: + /* Void */ + c = 'v'; break; } SyBlobAppend(&sSig, (const void *)&c, sizeof(char)); diff --git a/include/ph7int.h b/include/ph7int.h index 1f1d2f2..f85225c 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -631,23 +631,27 @@ struct ph7_value { }; /* Allowed value types. */ -#define MEMOBJ_STRING 0x001 /* Memory value is a UTF-8 string */ -#define MEMOBJ_INT 0x002 /* Memory value is an integer */ -#define MEMOBJ_REAL 0x004 /* Memory value is a real number */ -#define MEMOBJ_BOOL 0x008 /* Memory value is a boolean */ -#define MEMOBJ_NULL 0x020 /* Memory value is NULL */ -#define MEMOBJ_HASHMAP 0x040 /* Memory value is a hashmap aka 'array' in the PHP jargon */ -#define MEMOBJ_OBJ 0x080 /* Memory value is an object [i.e: class instance] */ -#define MEMOBJ_RES 0x100 /* Memory value is a resource [User private data] */ -#define MEMOBJ_REFERENCE 0x400 /* Memory value hold a reference (64-bit index) of another ph7_value */ +#define MEMOBJ_BOOL 0x0001 /* Memory value is a boolean */ +#define MEMOBJ_CALL 0x0002 /* Memory value is a callback */ +#define MEMOBJ_CHAR 0x0004 /* Memory value is a char */ +#define MEMOBJ_INT 0x0008 /* Memory value is an integer */ +#define MEMOBJ_OBJ 0x0010 /* Memory value is an object [i.e: class instance] */ +#define MEMOBJ_REAL 0x0020 /* Memory value is a real number */ +#define MEMOBJ_RES 0x0040 /* Memory value is a resource [User private data] */ +#define MEMOBJ_STRING 0x0080 /* Memory value is a UTF-8 string */ +#define MEMOBJ_VOID 0x0100 /* Memory value is a void */ +#define MEMOBJ_MIXED 0x0200 /* Memory value is mixed */ +#define MEMOBJ_REFERENCE 0x0400 /* Memory value hold a reference (64-bit index) of another ph7_value */ +#define MEMOBJ_HASHMAP 0x0800 /* Memory value is a hashmap aka 'array' in the PHP jargon */ +#define MEMOBJ_NULL 0x1000 /* Memory value is NULL */ /* Mask of all known types */ -#define MEMOBJ_ALL (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_OBJ|MEMOBJ_RES) +#define MEMOBJ_ALL (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_OBJ|MEMOBJ_RES|MEMOBJ_CALL|MEMOBJ_CHAR|MEMOBJ_VOID) /* Scalar variables * According to the PHP language reference manual * Scalar variables are those containing an integer, float, string or boolean. * Types array, object and resource are not scalar. */ -#define MEMOBJ_SCALAR (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL) +#define MEMOBJ_SCALAR (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_CHAR|MEMOBJ_VOID|MEMOBJ_NULL) #define MEMOBJ_AUX (MEMOBJ_REFERENCE) /* * The following macro clear the current ph7_value type and replace From ca00cadba7be1cb4032e5b2ee9ac0c1c317d3dd2 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 14 Sep 2018 21:32:08 +0200 Subject: [PATCH 004/296] Use strict type hinting in all tests. --- tests/arab_to_roman.aer | 2 +- tests/debug_backtrace.aer | 4 ++-- tests/singleton_test.aer | 2 +- tests/unicode_characters.aer | 2 +- tests/utf8_variables.aer | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/arab_to_roman.aer b/tests/arab_to_roman.aer index b5a8cfa..da10a16 100644 --- a/tests/arab_to_roman.aer +++ b/tests/arab_to_roman.aer @@ -1,6 +1,6 @@ class Program { - private function num2Roman($num) { + private function num2Roman(int $num) { $n = intval($num); $result = ''; $lookup = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, diff --git a/tests/debug_backtrace.aer b/tests/debug_backtrace.aer index 4c50763..1a441ce 100644 --- a/tests/debug_backtrace.aer +++ b/tests/debug_backtrace.aer @@ -4,7 +4,7 @@ class Program { $this->b($this->a('First A'), $this->a('Second A'), $this->a('Third A')); } - function a($p) { + function a(string $p) { $backtrace = debug_backtrace(); if(isset($backtrace[0]['args'])) { var_export($backtrace[0]['args']); @@ -14,7 +14,7 @@ class Program { return $p; } - function b($p1, $p2, $p3) { + function b(string $p1, string $p2, string $p3) { print("$p1, $p2, $p3"); } diff --git a/tests/singleton_test.aer b/tests/singleton_test.aer index 03d9ddf..847267d 100644 --- a/tests/singleton_test.aer +++ b/tests/singleton_test.aer @@ -17,7 +17,7 @@ final class Test { return $this->value; } - public function set($value = 0) { + public function set(int $value = 0) { $this->value = $value; } } diff --git a/tests/unicode_characters.aer b/tests/unicode_characters.aer index d164afe..9b2bd80 100644 --- a/tests/unicode_characters.aer +++ b/tests/unicode_characters.aer @@ -1,6 +1,6 @@ class Unicode { - public function unicon($str, $to_uni = true) { + public function unicon(string $str, bool $to_uni = true) { $cp = array('А' => 'А', 'а' => 'а', "Б" => "Б", "б" => "б", "В" => "В", "в" => "в", diff --git a/tests/utf8_variables.aer b/tests/utf8_variables.aer index ecdeeeb..5f6e9ca 100644 --- a/tests/utf8_variables.aer +++ b/tests/utf8_variables.aer @@ -12,7 +12,7 @@ class Program { print($this->概要 + "\n"); } - private function isUTF8($str) { + private function isUTF8(string $str) { $b = 0; $c = 0; $bits = 0; From 94ae7d187b7b8fe6cbbb9750539b64fa03e163ef Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 14 Sep 2018 21:33:31 +0200 Subject: [PATCH 005/296] No data type for argument specified leads to E_ERROR. --- engine/compiler.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index d124c11..05f171b 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2935,7 +2935,7 @@ static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen } else { SyString *pName = &pIn->sData; /* Class name */ char *zDup; - /* Argument must be a class instance,record that*/ + /* Argument must be a class instance, record that*/ zDup = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte); if(zDup) { sArg.nType = SXU32_HIGH; /* 0xFFFFFFFF as sentinel */ @@ -2959,6 +2959,9 @@ static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen return rc; } pIn++; /* Jump the dollar sign */ + if(!sArg.nType) { + PH7_GenCompileError(&(*pGen), E_ERROR, pIn->nLine, "Argument '$%z' is of undefined data type", &pIn->sData); + } /* Copy argument name */ zDup = SyMemBackendStrDup(&pGen->pVm->sAllocator, SyStringData(&pIn->sData), SyStringLength(&pIn->sData)); if(zDup == 0) { From faca9b7fb2fb581c390a8ae3b188b769ac7f038e Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 14 Sep 2018 22:22:37 +0200 Subject: [PATCH 006/296] Another fix in debug trace. --- engine/vm.c | 30 ++++++++++++++++-------------- include/ph7int.h | 4 ++-- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 983a827..cb34d27 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1733,22 +1733,24 @@ PH7_PRIVATE sxi32 VmExtractDebugTrace(ph7_vm *pVm, SySet *pDebugTrace) { break; } } - aTrace.pClassName = NULL; - aTrace.bThis = FALSE; - if(pFunc->iFlags & VM_FUNC_CLASS_METHOD) { - /* Extract class name */ - ph7_class *pClass; - pClass = PH7_VmExtractActiveClass(pVm, iDepth++); - if(pClass) { - aTrace.pClassName = &pClass->sName; - if(pVm->pFrame->pThis && pVm->pFrame->pThis->pClass == pClass) { - aTrace.bThis = TRUE; + if(aTrace.pFile) { + aTrace.pClassName = NULL; + aTrace.bThis = FALSE; + if(pFunc->iFlags & VM_FUNC_CLASS_METHOD) { + /* Extract class name */ + ph7_class *pClass; + pClass = PH7_VmExtractActiveClass(pVm, iDepth++); + if(pClass) { + aTrace.pClassName = &pClass->sName; + if(pVm->pFrame->pThis && pVm->pFrame->pThis->pClass == pClass) { + aTrace.bThis = TRUE; + } } } - } - rc = SySetPut(pDebugTrace, (const void *)&aTrace); - if(rc != SXRET_OK) { - break; + rc = SySetPut(pDebugTrace, (const void *)&aTrace); + if(rc != SXRET_OK) { + break; + } } } /* Roll frame */ diff --git a/include/ph7int.h b/include/ph7int.h index f85225c..b60de17 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1231,7 +1231,7 @@ struct ph7_vm { int nMaxDepth; /* Maximum allowed recursion depth */ int nExceptDepth; /* Exception depth */ int closure_cnt; /* Loaded closures counter */ - int json_rc; /* JSON return status [refer to json_encode()/json_decode()]*/ + int json_rc; /* JSON return status [refer to json_encode()/json_decode()] */ ph7_output_consumer sVmConsumer; /* Registered output consumer callback */ int iAssertFlags; /* Assertion flags */ ph7_value sAssertCallback; /* Callback to call on failed assertions */ @@ -1258,7 +1258,7 @@ struct VmFrame { SyHash hVar; /* Variable hashtable for fast lookup */ SySet sArg; /* Function arguments container */ SySet sRef; /* Local reference table (VmSlot instance) */ - sxi32 iFlags; /* Frame configuration flags (See below)*/ + sxi32 iFlags; /* Frame configuration flags (See below) */ sxu32 iExceptionJump; /* Exception jump destination */ }; #define VM_FRAME_EXCEPTION 0x01 /* Special Exception frame */ From 5504579566a8d6988d970fb629339cc842ddf5c3 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 14 Sep 2018 22:27:38 +0200 Subject: [PATCH 007/296] Passing an object of different type as expected should result in error. --- engine/vm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index cb34d27..deb7d8a 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4964,9 +4964,9 @@ static sxi32 VmByteCodeExec( if(pClass) { if((pArg->iFlags & MEMOBJ_OBJ) == 0) { if((pArg->iFlags & MEMOBJ_NULL) == 0) { - PH7_VmThrowError(&(*pVm), PH7_CTX_WARNING, - "Function '%z()':Argument %u must be an object of type '%z', PH7 is loading NULL instead", - &pVmFunc->sName, n + 1, pName); + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Argument %u passed to function '%z()' must be an object of type '%z'", + n+1, &pVmFunc->sName, pName); PH7_MemObjRelease(pArg); } } else { @@ -4974,8 +4974,8 @@ static sxi32 VmByteCodeExec( /* Make sure the object is an instance of the given class */ if(! VmInstanceOf(pThis->pClass, pClass)) { PH7_VmThrowError(&(*pVm), PH7_CTX_WARNING, - "Function '%z()':Argument %u must be an object of type '%z', PH7 is loading NULL instead", - &pVmFunc->sName, n + 1, pName); + "Argument %u passed to function '%z()' must be an object of type '%z'", + n+1, &pVmFunc->sName, pName); PH7_MemObjRelease(pArg); } } From 3a16eced8a844681f3c3645638672f8c693e644f Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 15 Sep 2018 14:13:46 +0200 Subject: [PATCH 008/296] Push error if argument type does not match. --- engine/vm.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index deb7d8a..13749a2 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4980,10 +4980,11 @@ static sxi32 VmByteCodeExec( } } } - } else if(((pArg->iFlags & aFormalArg[n].nType) == 0)) { + } else if(aFormalArg[n].nType != MEMOBJ_MIXED && ((pArg->iFlags & aFormalArg[n].nType) == 0)) { ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); - /* Cast to the desired type */ xCast(pArg); + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); } } if(aFormalArg[n].iFlags & VM_FUNC_ARG_BY_REF) { @@ -5066,16 +5067,15 @@ static sxi32 VmByteCodeExec( if(rc == PH7_ABORT) { goto Abort; } + if(aFormalArg[n].nType != MEMOBJ_MIXED && aFormalArg[n].nType > 0 && ((pObj->iFlags & aFormalArg[n].nType) == 0)) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Default value for argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); + } /* Insert argument index */ sArg.nIdx = pObj->nIdx; sArg.pUserData = 0; SySetPut(&pFrame->sArg, (const void *)&sArg); /* Make sure the default argument is of the correct type */ - if(aFormalArg[n].nType > 0 && ((pObj->iFlags & aFormalArg[n].nType) == 0)) { - ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); - /* Cast to the desired type */ - xCast(pObj); - } } } ++n; From 58103ea5fef369250a262bebe97842f95401bed0 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 16 Sep 2018 19:52:24 +0200 Subject: [PATCH 009/296] Mark method/closure call frame as active. It is impossible to dump the frame during its initialization, as it does not contain all necessary information. Such frame should be skipped. After initialization is done, the frame has to be marked as active just before evaluating a function body. --- engine/vm.c | 70 +++++++++++++++++++++++++----------------------- include/ph7int.h | 7 ++--- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 13749a2..f863794 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1715,41 +1715,43 @@ PH7_PRIVATE sxi32 VmExtractDebugTrace(ph7_vm *pVm, SySet *pDebugTrace) { /* Backup current frame */ VmFrame *oFrame = pVm->pFrame; while(pVm->pFrame) { - /* Iterate through all frames */ - ph7_vm_func *pFunc; - pFunc = (ph7_vm_func *)pVm->pFrame->pUserData; - if(pFunc && (pVm->pFrame->iFlags & VM_FRAME_EXCEPTION) == 0) { - VmDebugTrace aTrace; - SySet *aByteCode = &pFunc->aByteCode; - /* Extract closure/method name and passed arguments */ - aTrace.pFuncName = &pFunc->sName; - aTrace.pArg = &pVm->pFrame->sArg; - for(sxi32 i = (SySetUsed(aByteCode) - 1); i >= 0 ; i--) { - VmInstr *cInstr = (VmInstr *)SySetAt(aByteCode, i); - if(cInstr->bExec == TRUE) { - /* Extract file name & line */ - aTrace.pFile = cInstr->pFile; - aTrace.nLine = cInstr->iLine; - break; - } - } - if(aTrace.pFile) { - aTrace.pClassName = NULL; - aTrace.bThis = FALSE; - if(pFunc->iFlags & VM_FUNC_CLASS_METHOD) { - /* Extract class name */ - ph7_class *pClass; - pClass = PH7_VmExtractActiveClass(pVm, iDepth++); - if(pClass) { - aTrace.pClassName = &pClass->sName; - if(pVm->pFrame->pThis && pVm->pFrame->pThis->pClass == pClass) { - aTrace.bThis = TRUE; - } + if(pVm->pFrame->iFlags & VM_FRAME_ACTIVE) { + /* Iterate through all frames */ + ph7_vm_func *pFunc; + pFunc = (ph7_vm_func *)pVm->pFrame->pUserData; + if(pFunc && (pVm->pFrame->iFlags & VM_FRAME_EXCEPTION) == 0) { + VmDebugTrace aTrace; + SySet *aByteCode = &pFunc->aByteCode; + /* Extract closure/method name and passed arguments */ + aTrace.pFuncName = &pFunc->sName; + aTrace.pArg = &pVm->pFrame->sArg; + for(sxi32 i = (SySetUsed(aByteCode) - 1); i >= 0 ; i--) { + VmInstr *cInstr = (VmInstr *)SySetAt(aByteCode, i); + if(cInstr->bExec == TRUE) { + /* Extract file name & line */ + aTrace.pFile = cInstr->pFile; + aTrace.nLine = cInstr->iLine; + break; } } - rc = SySetPut(pDebugTrace, (const void *)&aTrace); - if(rc != SXRET_OK) { - break; + if(aTrace.pFile) { + aTrace.pClassName = NULL; + aTrace.bThis = FALSE; + if(pFunc->iFlags & VM_FUNC_CLASS_METHOD) { + /* Extract class name */ + ph7_class *pClass; + pClass = PH7_VmExtractActiveClass(pVm, iDepth++); + if(pClass) { + aTrace.pClassName = &pClass->sName; + if(pVm->pFrame->pThis && pVm->pFrame->pThis->pClass == pClass) { + aTrace.bThis = TRUE; + } + } + } + rc = SySetPut(pDebugTrace, (const void *)&aTrace); + if(rc != SXRET_OK) { + break; + } } } } @@ -5085,6 +5087,8 @@ static sxi32 VmByteCodeExec( */ PH7_MemObjRelease(pTos); pTos = &pTos[-pInstr->iP1]; + /* Mark current frame as active */ + pFrame->iFlags |= VM_FRAME_ACTIVE; /* Allocate a new operand stack and evaluate the function body */ pFrameStack = VmNewOperandStack(&(*pVm), SySetUsed(&pVmFunc->aByteCode)); if(pFrameStack == 0) { diff --git a/include/ph7int.h b/include/ph7int.h index b60de17..f03d29e 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1261,9 +1261,10 @@ struct VmFrame { sxi32 iFlags; /* Frame configuration flags (See below) */ sxu32 iExceptionJump; /* Exception jump destination */ }; -#define VM_FRAME_EXCEPTION 0x01 /* Special Exception frame */ -#define VM_FRAME_THROW 0x02 /* An exception was thrown */ -#define VM_FRAME_CATCH 0x04 /* Catch frame */ +#define VM_FRAME_ACTIVE 0x01 /* Active call frame */ +#define VM_FRAME_EXCEPTION 0x02 /* Special Exception frame */ +#define VM_FRAME_THROW 0x04 /* An exception was thrown */ +#define VM_FRAME_CATCH 0x08 /* Catch frame */ /* * When a debug stacktrace is extracted from Virtual Machine, all information about * calls (file, line, class, method, arguments) are stored in this structure. From 82998ffd0f6a229b6f1c66d06805dd84b50112b7 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 16 Sep 2018 20:02:34 +0200 Subject: [PATCH 010/296] Silently typecast integer value to float. This is a necessary step, to allow passing integer numbers. Otherwise, every float variable would need a floating point value. In other words, "float $x = 5" is allowed construct. Without this simple change, only accepted construction was "float $x = 5.0". --- engine/vm.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index f863794..74c5f53 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4983,10 +4983,14 @@ static sxi32 VmByteCodeExec( } } } else if(aFormalArg[n].nType != MEMOBJ_MIXED && ((pArg->iFlags & aFormalArg[n].nType) == 0)) { - ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); - xCast(pArg); - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, - "Argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); + if(aFormalArg[n].nType == MEMOBJ_REAL && (pArg->iFlags & MEMOBJ_INT)) { + /* Silently typecast integer value to float */ + ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); + xCast(pArg); + } else { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); + } } } if(aFormalArg[n].iFlags & VM_FUNC_ARG_BY_REF) { @@ -5070,8 +5074,14 @@ static sxi32 VmByteCodeExec( goto Abort; } if(aFormalArg[n].nType != MEMOBJ_MIXED && aFormalArg[n].nType > 0 && ((pObj->iFlags & aFormalArg[n].nType) == 0)) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, - "Default value for argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); + if(aFormalArg[n].nType == MEMOBJ_REAL && (pObj->iFlags & MEMOBJ_INT)) { + /* Silently typecast integer value to float */ + ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); + xCast(pObj); + } else { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Default value for argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); + } } /* Insert argument index */ sArg.nIdx = pObj->nIdx; From 5a6af65cfaa8afc84808d782d3d7ab1a6084a6a4 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 17 Sep 2018 22:06:53 +0200 Subject: [PATCH 011/296] Object of wrong type passed as argument should be generate error. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index 74c5f53..ebc0bf0 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4975,7 +4975,7 @@ static sxi32 VmByteCodeExec( ph7_class_instance *pThis = (ph7_class_instance *)pArg->x.pOther; /* Make sure the object is an instance of the given class */ if(! VmInstanceOf(pThis->pClass, pClass)) { - PH7_VmThrowError(&(*pVm), PH7_CTX_WARNING, + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Argument %u passed to function '%z()' must be an object of type '%z'", n+1, &pVmFunc->sName, pName); PH7_MemObjRelease(pArg); From 9884f8288b3a26dd27bccd0b58f06b89926bb143 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 18 Sep 2018 22:11:57 +0200 Subject: [PATCH 012/296] Do not allow typecasting to unset a variable. --- engine/compiler.c | 8 ++++---- engine/lexer.c | 5 +---- engine/parser.c | 1 - include/ph7int.h | 1 - 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 05f171b..d4a0659 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -5328,10 +5328,10 @@ static ProcLangConstruct PH7_GenStateGetStatementHandler( */ static int PH7_IsLangConstruct(sxu32 nKeywordID) { if(nKeywordID == PH7_KEYWORD_IMPORT || nKeywordID == PH7_KEYWORD_INCLUDE || nKeywordID == PH7_KEYWORD_REQUIRE - || nKeywordID == PH7_KEYWORD_ISSET || nKeywordID == PH7_KEYWORD_UNSET || nKeywordID == PH7_KEYWORD_EVAL - || nKeywordID == PH7_KEYWORD_EMPTY || nKeywordID == PH7_KEYWORD_ARRAY || nKeywordID == PH7_KEYWORD_LIST - || nKeywordID == PH7_KEYWORD_SELF || nKeywordID == PH7_KEYWORD_PARENT || nKeywordID == PH7_KEYWORD_STATIC - || /* TICKET 1433-012 */ nKeywordID == PH7_KEYWORD_NEW || nKeywordID == PH7_KEYWORD_CLONE) { + || nKeywordID == PH7_KEYWORD_ISSET || nKeywordID == PH7_KEYWORD_EVAL || nKeywordID == PH7_KEYWORD_EMPTY + || nKeywordID == PH7_KEYWORD_ARRAY || nKeywordID == PH7_KEYWORD_LIST || nKeywordID == PH7_KEYWORD_SELF + || nKeywordID == PH7_KEYWORD_PARENT || nKeywordID == PH7_KEYWORD_STATIC || nKeywordID == PH7_KEYWORD_NEW + || nKeywordID == PH7_KEYWORD_CLONE) { return TRUE; } /* Not a language construct */ diff --git a/engine/lexer.c b/engine/lexer.c index bc3826c..668ac8c 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_UNSET)) { + if((sxu32)nID & (PH7_KEYWORD_ARRAY | PH7_KEYWORD_INT | PH7_KEYWORD_FLOAT | PH7_KEYWORD_STRING | PH7_KEYWORD_OBJECT | PH7_KEYWORD_BOOL)) { pTmp = (SyToken *)SySetAt(pTokSet, pTokSet->nUsed - 2); if(pTmp->nType & PH7_TK_LPAREN) { /* Merge the three tokens '(' 'TYPE' ')' into a single one */ @@ -240,8 +240,6 @@ static sxi32 TokenizeAerScript(SyStream *pStream, SyToken *pToken, void *pUserDa zTypeCast = "(array)"; } else if(nID & PH7_KEYWORD_OBJECT) { zTypeCast = "(object)"; - } else if(nID & PH7_KEYWORD_UNSET) { - zTypeCast = "(unset)"; } /* Reflect the change */ pToken->nType = PH7_TK_OP; @@ -632,7 +630,6 @@ static sxu32 KeywordCode(const char *z, int n) { {"list", PH7_KEYWORD_LIST}, {"require", PH7_KEYWORD_REQUIRE}, {"return", PH7_KEYWORD_RETURN}, - {"unset", PH7_KEYWORD_UNSET}, /* Other keywords */ {"array", PH7_KEYWORD_ARRAY}, {"function", PH7_KEYWORD_FUNCTION}, diff --git a/engine/parser.c b/engine/parser.c index 27728cb..ca39e60 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -182,7 +182,6 @@ static const ph7_expr_op aOpTable[] = { { {"(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}, { {"(object)", sizeof("(object)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_OBJ }, - { {"(unset)", sizeof("(unset)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_NULL }, /* Binary operators */ /* Precedence 7,left-associative */ { {"instanceof", sizeof("instanceof") - 1}, EXPR_OP_INSTOF, 7, EXPR_OP_NON_ASSOC, PH7_OP_IS_A}, diff --git a/include/ph7int.h b/include/ph7int.h index f03d29e..29ff4b3 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1608,7 +1608,6 @@ enum ph7_expr_id { #define PH7_KEYWORD_CATCH 53 /* catch */ #define PH7_KEYWORD_RETURN 54 /* return */ #define PH7_KEYWORD_BREAK 55 /* break */ -#define PH7_KEYWORD_UNSET 0x800 /* unset: MUST BE A POWER OF TWO */ #define PH7_KEYWORD_VOID 0x1000 /* void: MUST BE A POWER OF TWO */ #define PH7_KEYWORD_CHAR 0x2000 /* char: MUST BE A POWER OF TWO */ #define PH7_KEYWORD_BOOL 0x4000 /* bool: MUST BE A POWER OF TWO */ From e6e59d299e20b828b7db8c07d9c4f78f688c9652 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 19 Sep 2018 19:27:50 +0200 Subject: [PATCH 013/296] Fix method parameters. --- engine/compiler.c | 89 +++++++++++++++++++++-------------------------- engine/vm.c | 49 ++++++++++++++++++-------- 2 files changed, 73 insertions(+), 65 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index d4a0659..b4b65a9 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2905,9 +2905,7 @@ static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen if(pIn->nType & (PH7_TK_ID | PH7_TK_KEYWORD)) { if(pIn->nType & PH7_TK_KEYWORD) { sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pIn->pUserData)); - if(nKey & PH7_KEYWORD_ARRAY) { - sArg.nType = MEMOBJ_HASHMAP; - } else if(nKey & PH7_KEYWORD_BOOL) { + if(nKey & PH7_KEYWORD_BOOL) { sArg.nType = MEMOBJ_BOOL; } else if(nKey & PH7_KEYWORD_CALLBACK) { sArg.nType = MEMOBJ_CALL; @@ -2943,6 +2941,10 @@ static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen } } pIn++; + if((pIn->nType & PH7_TK_OSB) && &pIn[1] < pEnd && (pIn[1].nType & PH7_TK_CSB)) { + sArg.nType |= MEMOBJ_HASHMAP; + pIn += 2; + } } if(pIn >= pEnd) { rc = PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Missing argument name"); @@ -3014,54 +3016,41 @@ static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen /* Class name */ SyBlobAppend(&sSig, SyStringData(&sArg.sClass), SyStringLength(&sArg.sClass)); } else { - int c; - c = 'n'; /* cc warning */ + int c = 'n'; /* cc warning */ /* Type leading character */ - switch(sArg.nType) { - case MEMOBJ_HASHMAP: - /* Hashmap aka 'array' */ - c = 'h'; - break; - case MEMOBJ_BOOL: - /* Bool */ - c = 'b'; - break; - case MEMOBJ_CALL: - /* Callback */ - c = 'a'; - break; - case MEMOBJ_CHAR: - /* Callback */ - c = 'c'; - break; - case MEMOBJ_INT: - /* Integer */ - c = 'i'; - break; - case MEMOBJ_MIXED: - /* Mixed */ - c = 'm'; - break; - case MEMOBJ_OBJ: - /* Object */ - c = 'o'; - break; - case MEMOBJ_REAL: - /* Float */ - c = 'f'; - break; - case MEMOBJ_RES: - /* Resource */ - c = 'r'; - break; - case MEMOBJ_STRING: - /* String */ - c = 's'; - break; - case MEMOBJ_VOID: - /* Void */ - c = 'v'; - break; + if(sArg.nType & MEMOBJ_BOOL) { + /* Bool */ + c = 'b'; + } else if(sArg.nType & MEMOBJ_CALL) { + /* Callback */ + c = 'a'; + } else if(sArg.nType & MEMOBJ_CHAR) { + /* Char */ + c = 'c'; + } else if(sArg.nType & MEMOBJ_INT) { + /* Integer */ + c = 'i'; + } else if(sArg.nType & MEMOBJ_MIXED) { + /* Mixed */ + c = 'm'; + } else if(sArg.nType & MEMOBJ_OBJ) { + /* Object */ + c = 'o'; + } else if(sArg.nType & MEMOBJ_REAL) { + /* Float */ + c = 'f'; + } else if(sArg.nType & MEMOBJ_RES) { + /* Resource */ + c = 'r'; + } else if(sArg.nType & MEMOBJ_STRING) { + /* String */ + c = 's'; + } else if(sArg.nType & MEMOBJ_VOID) { + /* Void */ + c = 'v'; + } + if(sArg.nType & MEMOBJ_HASHMAP) { + c = SyToUpper(c); } SyBlobAppend(&sSig, (const void *)&c, sizeof(char)); } diff --git a/engine/vm.c b/engine/vm.c index ebc0bf0..07616f3 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -553,27 +553,42 @@ static ph7_vm_func *VmOverload( SyBlobInit(&sSig, &pVm->sAllocator); for(j = 0 ; j < nArg ; j++) { int c = 'n'; /* null */ - if(aArg[j].iFlags & MEMOBJ_HASHMAP) { - /* Hashmap */ - c = 'h'; - } else if(aArg[j].iFlags & MEMOBJ_BOOL) { - /* bool */ + if(aArg[j].iFlags & MEMOBJ_BOOL) { + /* Bool */ c = 'b'; + } else if(aArg[j].iFlags & MEMOBJ_CALL) { + /* Callback */ + c = 'a'; + } else if(aArg[j].iFlags & MEMOBJ_CHAR) { + /* Char */ + c = 'c'; } else if(aArg[j].iFlags & MEMOBJ_INT) { - /* int */ + /* Integer */ c = 'i'; - } else if(aArg[j].iFlags & MEMOBJ_STRING) { - /* String */ - c = 's'; - } else if(aArg[j].iFlags & MEMOBJ_REAL) { - /* Float */ - c = 'f'; + } else if(aArg[j].iFlags & MEMOBJ_MIXED) { + /* Mixed */ + c = 'm'; } else if(aArg[j].iFlags & MEMOBJ_OBJ) { /* Class instance */ ph7_class *pClass = ((ph7_class_instance *)aArg[j].x.pOther)->pClass; SyString *pName = &pClass->sName; SyBlobAppend(&sSig, (const void *)pName->zString, pName->nByte); c = -1; + } else if(aArg[j].iFlags & MEMOBJ_REAL) { + /* Float */ + c = 'f'; + } else if(aArg[j].iFlags & MEMOBJ_RES) { + /* Resource */ + c = 'r'; + } else if(aArg[j].iFlags & MEMOBJ_STRING) { + /* String */ + c = 's'; + } else if(aArg[j].iFlags & MEMOBJ_VOID) { + /* Void */ + c = 'v'; + } + if(aArg[j].iFlags & MEMOBJ_HASHMAP && (aArg[j].iFlags & MEMOBJ_OBJ) == 0) { + c = SyToUpper(c); } if(c > 0) { SyBlobAppend(&sSig, (const void *)&c, sizeof(char)); @@ -4982,7 +4997,7 @@ static sxi32 VmByteCodeExec( } } } - } else if(aFormalArg[n].nType != MEMOBJ_MIXED && ((pArg->iFlags & aFormalArg[n].nType) == 0)) { + } else if((aFormalArg[n].nType & MEMOBJ_MIXED) == 0 && pArg->iFlags != aFormalArg[n].nType) { if(aFormalArg[n].nType == MEMOBJ_REAL && (pArg->iFlags & MEMOBJ_INT)) { /* Silently typecast integer value to float */ ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); @@ -5073,7 +5088,7 @@ static sxi32 VmByteCodeExec( if(rc == PH7_ABORT) { goto Abort; } - if(aFormalArg[n].nType != MEMOBJ_MIXED && aFormalArg[n].nType > 0 && ((pObj->iFlags & aFormalArg[n].nType) == 0)) { + if((aFormalArg[n].nType & MEMOBJ_MIXED) == 0 && aFormalArg[n].nType > 0 && pObj->iFlags != aFormalArg[n].nType) { if(aFormalArg[n].nType == MEMOBJ_REAL && (pObj->iFlags & MEMOBJ_INT)) { /* Silently typecast integer value to float */ ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); @@ -5393,12 +5408,16 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) { zParam = SyStrtok(NULL, " "); } } - /* Call entry point */ + /* Extract script entry point */ pMethod = PH7_ClassExtractMethod(pClass, "main", sizeof("main") - 1); if(!pMethod) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot find a program entry point 'Program::main()'"); } + /* A set of arguments is stored in array of strings */ + pArgs->iFlags |= MEMOBJ_STRING; + /* Initialize variable for return value */ PH7_MemObjInit(pVm, &pResult); + /* Call entry point */ PH7_VmCallClassMethod(&(*pVm), pInstance, pMethod, &pResult, 1, &pArgs); if(!pVm->iExitStatus) { pVm->iExitStatus = ph7_value_to_int(&pResult); From 241c7d8168a76242cf3422829dc6eaf10a1a4a62 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 20 Sep 2018 17:06:23 +0200 Subject: [PATCH 014/296] First step to declare a variable with specified data type. --- engine/compiler.c | 38 +++++++++++++++++++++----------------- include/ph7int.h | 2 ++ 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index b4b65a9..b09dea7 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -5248,12 +5248,10 @@ static const LangConstruct aLangConstruct[] = { { PH7_KEYWORD_RETURN, PH7_CompileReturn }, /* return statement */ { PH7_KEYWORD_SWITCH, PH7_CompileSwitch }, /* Switch statement */ { PH7_KEYWORD_DO, PH7_CompileDoWhile }, /* do{ }while(); statement */ - { PH7_KEYWORD_STATIC, PH7_CompileStatic }, /* static statement */ { PH7_KEYWORD_EXIT, PH7_CompileHalt }, /* exit language construct */ { PH7_KEYWORD_TRY, PH7_CompileTry }, /* try statement */ { PH7_KEYWORD_THROW, PH7_CompileThrow }, /* throw statement */ { PH7_KEYWORD_CONST, PH7_CompileConstant }, /* const statement */ - { PH7_KEYWORD_VAR, PH7_CompileVar }, /* var statement */ }; /* * Return a pointer to the global scope handler routine associated @@ -5291,23 +5289,29 @@ static ProcLangConstruct PH7_GenStateGetStatementHandler( SyToken *pLookahead /* Look-ahead token */ ) { sxu32 n = 0; - for(;;) { - if(n >= SX_ARRAYSIZE(aLangConstruct)) { - break; - } - if(aLangConstruct[n].nID == nKeywordID) { - if(nKeywordID == PH7_KEYWORD_STATIC && pLookahead && (pLookahead->nType & PH7_TK_OP)) { - const ph7_expr_op *pOp = (const ph7_expr_op *)pLookahead->pUserData; - if(pOp && pOp->iOp == EXPR_OP_DC /*::*/) { - /* 'static' (class context),return null */ - return 0; - } + if((nKeywordID & PH7_KEYWORD_TYPEDEF) != 0) { + return PH7_CompileVar; + } else if(nKeywordID == PH7_KEYWORD_STATIC) { + if(pLookahead && (pLookahead->nType & PH7_TK_OP)) { + const ph7_expr_op *pOp = (const ph7_expr_op *)pLookahead->pUserData; + if(pOp && pOp->iOp == EXPR_OP_DC /*::*/) { + /* 'static' (class context),return null */ + return 0; } - /* Return a pointer to the handler. - */ - return aLangConstruct[n].xConstruct; } - n++; + return PH7_CompileStatic; + } else { + for(;;) { + if(n >= SX_ARRAYSIZE(aLangConstruct)) { + break; + } + if(aLangConstruct[n].nID == nKeywordID) { + /* Return a pointer to the handler. + */ + return aLangConstruct[n].xConstruct; + } + n++; + } } /* Not a language construct */ return 0; diff --git a/include/ph7int.h b/include/ph7int.h index 29ff4b3..6a2532c 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1618,6 +1618,8 @@ enum ph7_expr_id { #define PH7_KEYWORD_CALLBACK 0x80000 /* callback: MUST BE A POWER OF TWO */ #define PH7_KEYWORD_RESOURCE 0x100000 /* resource: MUST BE A POWER OF TWO */ #define PH7_KEYWORD_MIXED 0x200000 /* mixed: MUST BE A POWER OF TWO */ + +#define PH7_KEYWORD_TYPEDEF (PH7_KEYWORD_VOID|PH7_KEYWORD_CHAR|PH7_KEYWORD_BOOL|PH7_KEYWORD_INT|PH7_KEYWORD_FLOAT|PH7_KEYWORD_STRING|PH7_KEYWORD_OBJECT|PH7_KEYWORD_CALLBACK|PH7_KEYWORD_RESOURCE|PH7_KEYWORD_MIXED) /* JSON encoding/decoding related definition */ enum json_err_code { JSON_ERROR_NONE = 0, /* No error has occurred. */ From bd4d146d0ad33b1194002c0283869fd27f5f98ee Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 21 Sep 2018 00:21:15 +0200 Subject: [PATCH 015/296] Initial version of variable definition. --- engine/compiler.c | 142 +++++++++++++++++++++++++++++++++------ tests/singleton_test.aer | 2 +- 2 files changed, 121 insertions(+), 23 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index b09dea7..34cced4 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2609,25 +2609,125 @@ Synchronize: */ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { sxu32 nLine = pGen->pIn->nLine; + sxbool bStatic = FALSE; + ph7_vm_func_static_var sStatic; + ph7_vm_func *pFunc; + GenBlock *pBlock; + SyString *pName; + sxu32 nKey, nType; + char *zDup; sxi32 rc; - /* Jump the 'var' keyword */ - pGen->pIn++; - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_DOLLAR/*'$'*/) == 0) { - rc = PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "var: Expecting variable name"); - /* Synchronize with the first semi-colon */ - while(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_SEMI/*';'*/) == 0) { - pGen->pIn++; - } - if(rc == SXERR_ABORT) { - return SXERR_ABORT; - } + nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData)); + if(nKey == PH7_KEYWORD_STATIC) { + bStatic = TRUE; + /* Jump the 'static' keyword' */ + pGen->pIn++; + nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData)); + } + if(nKey & PH7_KEYWORD_BOOL) { + nType = MEMOBJ_BOOL; + } else if(nKey & PH7_KEYWORD_CALLBACK) { + nType = MEMOBJ_CALL; + } else if(nKey & PH7_KEYWORD_CHAR) { + nType = MEMOBJ_CHAR; + } else if(nKey & PH7_KEYWORD_FLOAT) { + nType = MEMOBJ_REAL; + } else if(nKey & PH7_KEYWORD_INT) { + nType = MEMOBJ_INT; + } else if(nKey & PH7_KEYWORD_MIXED) { + nType = MEMOBJ_MIXED; + } else if(nKey & PH7_KEYWORD_OBJECT) { + nType = MEMOBJ_OBJ; + } else if(nKey & PH7_KEYWORD_RESOURCE) { + nType = MEMOBJ_RES; + } else if(nKey & PH7_KEYWORD_STRING) { + nType = MEMOBJ_STRING; + } else if(nKey & PH7_KEYWORD_VOID) { + nType = MEMOBJ_VOID; } else { - /* Compile the expression */ - rc = PH7_CompileExpr(&(*pGen), 0, 0); - if(rc == SXERR_ABORT) { - return SXERR_ABORT; - } else if(rc != SXERR_EMPTY) { - PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_POP, 1, 0, 0, 0); + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, + "Unknown data type name '%z'", + &pGen->pIn->sData); + } + /* Jump the data type keyword */ + pGen->pIn++; + if((pGen->pIn->nType & PH7_TK_OSB) && &pGen->pIn[1] < pGen->pEnd && (pGen->pIn[1].nType & PH7_TK_CSB)) { + nType |= MEMOBJ_HASHMAP; + pGen->pIn += 2; + } + for(;;) { + if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_DOLLAR/*'$'*/) == 0 || &pGen->pIn[1] >= pGen->pEnd || + (pGen->pIn[1].nType & (PH7_TK_ID | PH7_TK_KEYWORD)) == 0) { + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, + "Unexpected '%z', expecting variable", + &pGen->pIn->sData); + } + /* Extract variable name */ + pName = &pGen->pIn[1].sData; + if(bStatic) { + /* Extract the enclosing method/closure */ + pBlock = pGen->pCurrent; + while(pBlock) { + if(pBlock->iFlags & GEN_BLOCK_FUNC) { + break; + } + /* Point to the upper block */ + pBlock = pBlock->pParent; + } + pFunc = (ph7_vm_func *)pBlock->pUserData; + pGen->pIn += 2; /* Jump the dollar '$' sign and variable name */ + if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (PH7_TK_COMMA/*','*/ | PH7_TK_SEMI/*';'*/ | PH7_TK_EQUAL/*'='*/)) == 0) { + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Unexpected token '%z'", &pGen->pIn->sData); + } + /* TODO: Check if static variable exists to avoid redeclaration */ + + /* Initialize the structure describing the static variable */ + SySetInit(&sStatic.aByteCode, &pGen->pVm->sAllocator, sizeof(VmInstr)); + sStatic.nIdx = SXU32_HIGH; /* Not yet created */ + /* Duplicate variable name */ + zDup = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte); + if(zDup == 0) { + PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "Fatal, PH7 engine is running out of memory"); + } + SyStringInitFromBuf(&sStatic.sName, zDup, pName->nByte); + /* Check if we have an expression to compile */ + if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_EQUAL)) { + SySet *pInstrContainer; + pGen->pIn++; /* Jump the equal '=' sign */ + /* Swap bytecode container */ + pInstrContainer = PH7_VmGetByteCodeContainer(pGen->pVm); + PH7_VmSetByteCodeContainer(pGen->pVm, &sStatic.aByteCode); + /* Compile the expression */ + rc = PH7_CompileExpr(&(*pGen), EXPR_FLAG_COMMA_STATEMENT, 0); + if(rc == SXERR_EMPTY) { + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Static variable '%z' is missing default value", &pName); + } + /* Emit the done instruction */ + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0); + /* Restore default bytecode container */ + PH7_VmSetByteCodeContainer(pGen->pVm, pInstrContainer); + } + /* Finally save the compiled static variable in the appropriate container */ + SySetPut(&pFunc->aStatic, (const void *)&sStatic); + } else { + void *p3 = (void *) pName; + /* Emit OP_LOAD instruction */ + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_LOAD, 0, nType, p3, 0); + /* Check if we have an expression to compile */ + if(pGen->pIn < pGen->pEnd && (pGen->pIn[2].nType & PH7_TK_EQUAL)) { + /* Compile the expression */ + rc = PH7_CompileExpr(&(*pGen), EXPR_FLAG_COMMA_STATEMENT, 0); + if(rc == SXERR_EMPTY) { + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Variable '%z' is missing default value", &pName); + } + } else { + pGen->pIn += 2; /* Jump the dollar '$' sign and variable name */ + } + } + if(pGen->pIn->nType == PH7_TK_SEMI) { + break; + } else { + pGen->pIn++; } } return SXRET_OK; @@ -5289,17 +5389,15 @@ static ProcLangConstruct PH7_GenStateGetStatementHandler( SyToken *pLookahead /* Look-ahead token */ ) { sxu32 n = 0; - if((nKeywordID & PH7_KEYWORD_TYPEDEF) != 0) { - return PH7_CompileVar; - } else if(nKeywordID == PH7_KEYWORD_STATIC) { - if(pLookahead && (pLookahead->nType & PH7_TK_OP)) { + if((nKeywordID & PH7_KEYWORD_TYPEDEF) != 0 || nKeywordID == PH7_KEYWORD_STATIC) { + if(nKeywordID == PH7_KEYWORD_STATIC && pLookahead && (pLookahead->nType & PH7_TK_OP)) { const ph7_expr_op *pOp = (const ph7_expr_op *)pLookahead->pUserData; if(pOp && pOp->iOp == EXPR_OP_DC /*::*/) { /* 'static' (class context),return null */ return 0; } } - return PH7_CompileStatic; + return PH7_CompileVar; } else { for(;;) { if(n >= SX_ARRAYSIZE(aLangConstruct)) { diff --git a/tests/singleton_test.aer b/tests/singleton_test.aer index 847267d..25e12e5 100644 --- a/tests/singleton_test.aer +++ b/tests/singleton_test.aer @@ -6,7 +6,7 @@ final class Test { /* This is singleton */ public function getInstance() { - static $instance; + static object $instance; if(!$instance) { $instance = new Test(); } From 79e4bac7eb23bec8f987c04bea8e7cb25a065d8e Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 21 Sep 2018 00:22:29 +0200 Subject: [PATCH 016/296] Remove no longer used PH7_CompileStatic(). --- engine/compiler.c | 112 ---------------------------------------------- 1 file changed, 112 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 34cced4..46a7246 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2490,118 +2490,6 @@ static sxi32 PH7_CompileHalt(ph7_gen_state *pGen) { PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_HALT, nExpr, 0, 0, 0); return SXRET_OK; } -/* - * Compile the static statement. - * Another important feature of variable scoping is the static variable. - * A static variable exists only in a local function scope, but it does not lose its value - * when program execution leaves this scope. - * Static variables also provide one way to deal with recursive functions. - * Symisc eXtension. - * PH7 allow any complex expression to be associated with the static variable while - * the zend engine would allow only simple scalar value. - * Example - * static $myVar = "Welcome "." guest ".rand_str(3); //Valid under PH7/Generate error using the zend engine - * Refer to the official documentation for more information on this feature. - */ -static sxi32 PH7_CompileStatic(ph7_gen_state *pGen) { - ph7_vm_func_static_var sStatic; /* Structure describing the static variable */ - ph7_vm_func *pFunc; /* Enclosing function */ - GenBlock *pBlock; - SyString *pName; - char *zDup; - sxu32 nLine; - sxi32 rc; - /* Jump the static keyword */ - nLine = pGen->pIn->nLine; - pGen->pIn++; - /* Extract the enclosing function if any */ - pBlock = pGen->pCurrent; - while(pBlock) { - if(pBlock->iFlags & GEN_BLOCK_FUNC) { - break; - } - /* Point to the upper block */ - pBlock = pBlock->pParent; - } - if(pBlock == 0) { - /* Static statement,called outside of a function body,treat it as a simple variable. */ - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_DOLLAR) == 0) { - rc = PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "Expected variable after 'static' keyword"); - if(rc == SXERR_ABORT) { - return SXERR_ABORT; - } - goto Synchronize; - } - /* Compile the expression holding the variable */ - rc = PH7_CompileExpr(&(*pGen), 0, 0); - if(rc == SXERR_ABORT) { - return SXERR_ABORT; - } else if(rc != SXERR_EMPTY) { - /* Emit the POP instruction */ - PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_POP, 1, 0, 0, 0); - } - return SXRET_OK; - } - pFunc = (ph7_vm_func *)pBlock->pUserData; - /* Make sure we are dealing with a valid statement */ - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_DOLLAR) == 0 || &pGen->pIn[1] >= pGen->pEnd || - (pGen->pIn[1].nType & (PH7_TK_ID | PH7_TK_KEYWORD)) == 0) { - rc = PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "Expected variable after 'static' keyword"); - if(rc == SXERR_ABORT) { - return SXERR_ABORT; - } - goto Synchronize; - } - pGen->pIn++; - /* Extract variable name */ - pName = &pGen->pIn->sData; - pGen->pIn++; /* Jump the var name */ - if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (PH7_TK_SEMI/*';'*/ | PH7_TK_EQUAL/*'='*/)) == 0) { - rc = PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "static: Unexpected token '%z'", &pGen->pIn->sData); - goto Synchronize; - } - /* Initialize the structure describing the static variable */ - SySetInit(&sStatic.aByteCode, &pGen->pVm->sAllocator, sizeof(VmInstr)); - sStatic.nIdx = SXU32_HIGH; /* Not yet created */ - /* Duplicate variable name */ - zDup = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte); - if(zDup == 0) { - PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "Fatal, PH7 engine is running out of memory"); - return SXERR_ABORT; - } - SyStringInitFromBuf(&sStatic.sName, zDup, pName->nByte); - /* Check if we have an expression to compile */ - if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_EQUAL)) { - SySet *pInstrContainer; - /* - * Static variable can take any complex expression including function - * call as their initialization value. - * Example: - * static $var = foo(1,4+5,bar()); - */ - pGen->pIn++; /* Jump the equal '=' sign */ - /* Swap bytecode container */ - pInstrContainer = PH7_VmGetByteCodeContainer(pGen->pVm); - PH7_VmSetByteCodeContainer(pGen->pVm, &sStatic.aByteCode); - /* Compile the expression */ - rc = PH7_CompileExpr(&(*pGen), 0, 0); - /* Emit the done instruction */ - PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0); - /* Restore default bytecode container */ - PH7_VmSetByteCodeContainer(pGen->pVm, pInstrContainer); - } - /* Finally save the compiled static variable in the appropriate container */ - SySetPut(&pFunc->aStatic, (const void *)&sStatic); - return SXRET_OK; -Synchronize: - /* Synchronize with the first semi-colon ';',so we can avoid compiling this erroneous - * statement. - */ - while(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_SEMI) == 0) { - pGen->pIn++; - } - return SXRET_OK; -} /* * Compile the var statement. * Symisc Extension: From f927667d8574f5893b49e170012c467da719e35b Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 21 Sep 2018 22:06:36 +0200 Subject: [PATCH 017/296] Strictly check for data type of static variable declaration. --- engine/compiler.c | 2 ++ engine/vm.c | 4 ++++ include/ph7int.h | 1 + 3 files changed, 7 insertions(+) diff --git a/engine/compiler.c b/engine/compiler.c index 46a7246..0b3f5d3 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2595,6 +2595,8 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { /* Restore default bytecode container */ PH7_VmSetByteCodeContainer(pGen->pVm, pInstrContainer); } + /* Set static variable type */ + sStatic.iFlags = nType; /* Finally save the compiled static variable in the appropriate container */ SySetPut(&pFunc->aStatic, (const void *)&sStatic); } else { diff --git a/engine/vm.c b/engine/vm.c index 07616f3..abb21db 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4949,6 +4949,10 @@ static sxi32 VmByteCodeExec( /* Evaluate initialization expression (Any complex expression) */ VmLocalExec(&(*pVm), &pStatic->aByteCode, pObj); } + if(pObj->iFlags != pStatic->iFlags) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Value does not match the data type of '$%z' variable", &pStatic->sName); + } pObj->nIdx = pStatic->nIdx; } else { continue; diff --git a/include/ph7int.h b/include/ph7int.h index 6a2532c..50b115d 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -959,6 +959,7 @@ struct ph7_vm_func_arg { */ struct ph7_vm_func_static_var { SyString sName; /* Static variable name */ + sxi32 iFlags; /* Control flags */ SySet aByteCode; /* Compiled initialization expression */ sxu32 nIdx; /* Object index in the global memory object container */ }; From 514e07c7f35f22893575eec305dcd12bd36a0355 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 21 Sep 2018 22:18:11 +0200 Subject: [PATCH 018/296] Fix static variables not containing any value. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index abb21db..111d9be 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4949,7 +4949,7 @@ static sxi32 VmByteCodeExec( /* Evaluate initialization expression (Any complex expression) */ VmLocalExec(&(*pVm), &pStatic->aByteCode, pObj); } - if(pObj->iFlags != pStatic->iFlags) { + if((pObj->iFlags & MEMOBJ_NULL) == 0 && pObj->iFlags != pStatic->iFlags) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Value does not match the data type of '$%z' variable", &pStatic->sName); } From 28a5fa59ad42f7f0be1b04979e69d05e9ea5e89d Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 22 Sep 2018 17:54:59 +0200 Subject: [PATCH 019/296] Duplicate variable name. Fix variable declaration. --- engine/compiler.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index 0b3f5d3..6a34855 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2600,7 +2600,11 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { /* Finally save the compiled static variable in the appropriate container */ SySetPut(&pFunc->aStatic, (const void *)&sStatic); } else { - void *p3 = (void *) pName; + zDup = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte); + if(zDup == 0) { + PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "Fatal, PH7 engine is running out of memory"); + } + void *p3 = (void *) zDup; /* Emit OP_LOAD instruction */ PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_LOAD, 0, nType, p3, 0); /* Check if we have an expression to compile */ From ae0fde152c9ac2da4892c13350797afa92c0ec5f Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 23 Sep 2018 17:40:26 +0200 Subject: [PATCH 020/296] Create a variable only on OP_LOAD. --- engine/vm.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 111d9be..638403f 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2355,7 +2355,7 @@ static sxi32 VmByteCodeExec( break; } /* - * LOAD: P1 * P3 + * LOAD: * P2 P3 * * Load a variable where it's name is taken from the top of the stack or * from the P3 operand. @@ -2383,21 +2383,24 @@ static sxi32 VmByteCodeExec( pTos++; } /* Extract the requested memory object */ - pObj = VmExtractMemObj(&(*pVm), &sName, pInstr->p3 ? FALSE : TRUE, pInstr->iP1 != 1); - if(pObj == 0) { - if(pInstr->iP1) { - /* Variable not found,load NULL */ - if(!pInstr->p3) { - PH7_MemObjRelease(pTos); - } else { - MemObjSetType(pTos, MEMOBJ_NULL); - } - pTos->nIdx = SXU32_HIGH; /* Mark as constant */ - break; + pObj = VmExtractMemObj(&(*pVm), &sName, pInstr->p3 ? FALSE : TRUE, FALSE); + if(pInstr->iP2) { + if(pObj) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Redeclaration of ‘$%z’ variable", &sName); + } + if(!pInstr->p3) { + PH7_MemObjRelease(pTos); } else { + pObj = VmExtractMemObj(&(*pVm), &sName, FALSE, TRUE); + MemObjSetType(pObj, pInstr->iP2); + } + pTos->nIdx = SXU32_HIGH; /* Mark as constant */ + break; + } else { + if(pObj == 0) { /* Fatal error */ - PH7_VmMemoryError(&(*pVm)); - goto Abort; + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Variable '$%z' undeclared (first use in this method/closure)", &sName); } } /* Load variable contents */ @@ -2719,10 +2722,10 @@ static sxi32 VmByteCodeExec( SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3)); } /* Extract the desired variable and if not available dynamically create it */ - pObj = VmExtractMemObj(&(*pVm), &sName, pInstr->p3 ? FALSE : TRUE, TRUE); + pObj = VmExtractMemObj(&(*pVm), &sName, pInstr->p3 ? FALSE : TRUE, FALSE); if(pObj == 0) { - PH7_VmMemoryError(&(*pVm)); - goto Abort; + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Variable '$%z' undeclared (first use in this method/closure)", &sName); } if(!pInstr->p3) { PH7_MemObjRelease(&pTos[1]); From dd774be00549bdc1573bb6a76d7972639624096e Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 23 Sep 2018 17:51:09 +0200 Subject: [PATCH 021/296] Fix for() loop, do not use iP1 for OP_LOAD. --- engine/compiler.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 6a34855..63eb13a 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -1090,7 +1090,6 @@ PH7_PRIVATE sxi32 PH7_CompileLangConstruct(ph7_gen_state *pGen, sxi32 iCompileFl PH7_PRIVATE sxi32 PH7_CompileVariable(ph7_gen_state *pGen, sxi32 iCompileFlag) { sxu32 nLine = pGen->pIn->nLine; sxi32 iVv; - sxi32 iP1; void *p3; sxi32 rc; iVv = -1; /* Variable variable counter */ @@ -1149,17 +1148,10 @@ PH7_PRIVATE sxi32 PH7_CompileVariable(ph7_gen_state *pGen, sxi32 iCompileFlag) { } p3 = (void *)zName; } - iP1 = 0; - if(iCompileFlag & EXPR_FLAG_RDONLY_LOAD) { - if((iCompileFlag & EXPR_FLAG_LOAD_IDX_STORE) == 0) { - /* Read-only load.In other words do not create the variable if non-existent */ - iP1 = 1; - } - } /* Emit the load instruction */ - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOAD, iP1, 0, p3, 0); + PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOAD, 0, 0, p3, 0); while(iVv > 0) { - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOAD, iP1, 0, 0, 0); + PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOAD, 0, 0, 0, 0); iVv--; } /* Node successfully compiled */ @@ -1945,6 +1937,10 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) { /* Swap token streams */ pTmp = pGen->pEnd; pGen->pEnd = pEnd; + sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData)); + if(nKey & PH7_KEYWORD_TYPEDEF) { + PH7_CompileVar(&(*pGen)); + } /* Compile initialization expressions if available */ rc = PH7_CompileExpr(&(*pGen), 0, 0); /* Pop operand lvalues */ From 08296110fb53b74a98340ed3ac7d9101d52f473c Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 23 Sep 2018 17:51:47 +0200 Subject: [PATCH 022/296] Temporarily fix tests. --- tests/arab_to_roman.aer | 9 +++++---- tests/debug_backtrace.aer | 2 +- tests/singleton_test.aer | 4 ++-- tests/type_juggle.aer | 1 + tests/unicode_characters.aer | 5 +++-- tests/utf8_variables.aer | 10 +++++----- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/tests/arab_to_roman.aer b/tests/arab_to_roman.aer index da10a16..0f374b2 100644 --- a/tests/arab_to_roman.aer +++ b/tests/arab_to_roman.aer @@ -1,14 +1,15 @@ class Program { private function num2Roman(int $num) { - $n = intval($num); - $result = ''; - $lookup = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, + int $n = intval($num); + int $result = ''; + mixed $lookup = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1); + int $matches; foreach($lookup as $roman => $value) { - $matches = intval($n / $value); + $matches = intval($n / $value); $result += str_repeat($roman, $matches); $n = $n % $value; } diff --git a/tests/debug_backtrace.aer b/tests/debug_backtrace.aer index 1a441ce..5e10382 100644 --- a/tests/debug_backtrace.aer +++ b/tests/debug_backtrace.aer @@ -5,7 +5,7 @@ class Program { } function a(string $p) { - $backtrace = debug_backtrace(); + mixed $backtrace = debug_backtrace(); if(isset($backtrace[0]['args'])) { var_export($backtrace[0]['args']); } else { diff --git a/tests/singleton_test.aer b/tests/singleton_test.aer index 25e12e5..eb16bfa 100644 --- a/tests/singleton_test.aer +++ b/tests/singleton_test.aer @@ -24,9 +24,9 @@ final class Test { final class Program { public function main() { - $testA = Test::getInstance(); + object $testA = Test::getInstance(); $testA->set(5); - $testB = Test::getInstance(); + object $testB = Test::getInstance(); var_dump($testB->get()); } } /* class */ diff --git a/tests/type_juggle.aer b/tests/type_juggle.aer index 2dd0ead..88a5b0b 100644 --- a/tests/type_juggle.aer +++ b/tests/type_juggle.aer @@ -1,6 +1,7 @@ class Program { function main() { + mixed $foo; $foo = '0'; var_dump($foo); $foo += 2; diff --git a/tests/unicode_characters.aer b/tests/unicode_characters.aer index 9b2bd80..e2771ac 100644 --- a/tests/unicode_characters.aer +++ b/tests/unicode_characters.aer @@ -1,7 +1,8 @@ class Unicode { public function unicon(string $str, bool $to_uni = true) { - $cp = array('А' => 'А', 'а' => 'а', + mixed $cpp; + mixed $cp = array('А' => 'А', 'а' => 'а', "Б" => "Б", "б" => "б", "В" => "В", "в" => "в", "Г" => "Г", "г" => "г", @@ -50,7 +51,7 @@ class Unicode { final class Program { public function main() { - $unicode = new Unicode(); + object $unicode = new Unicode(); var_dump($unicode->unicon("ИфйжБЦ")); } diff --git a/tests/utf8_variables.aer b/tests/utf8_variables.aer index 5f6e9ca..fdd7aca 100644 --- a/tests/utf8_variables.aer +++ b/tests/utf8_variables.aer @@ -13,11 +13,11 @@ class Program { } private function isUTF8(string $str) { - $b = 0; - $c = 0; - $bits = 0; - $len = strlen($str); - for($i = 0; $i < $len; $i++) { + int $b = 0; + int $c = 0; + int $bits = 0; + int $len = strlen($str); + for(int $i = 0; $i < $len; $i++) { $c = ord($str[$i]); if($c >= 128) { if(($c >= 254)) return false; From ba0c2509118d0785fe119f7ea52895171cad1c41 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 23 Sep 2018 19:07:03 +0200 Subject: [PATCH 023/296] Fix test. --- tests/arab_to_roman.aer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/arab_to_roman.aer b/tests/arab_to_roman.aer index 0f374b2..61e9cfc 100644 --- a/tests/arab_to_roman.aer +++ b/tests/arab_to_roman.aer @@ -2,7 +2,7 @@ class Program { private function num2Roman(int $num) { int $n = intval($num); - int $result = ''; + string $result = ''; mixed $lookup = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1); From 59fda6d797c6caf06e6bd462c73eaf45df1a3130 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 24 Sep 2018 11:29:51 +0200 Subject: [PATCH 024/296] Unref hashmap and object only if there is any data stored. --- engine/memobj.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 94b65dd..52186c6 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -814,10 +814,12 @@ PH7_PRIVATE sxi32 PH7_MemObjLoad(ph7_value *pSrc, ph7_value *pDest) { */ PH7_PRIVATE sxi32 PH7_MemObjRelease(ph7_value *pObj) { if((pObj->iFlags & MEMOBJ_NULL) == 0) { - if(pObj->iFlags & MEMOBJ_HASHMAP) { - PH7_HashmapUnref((ph7_hashmap *)pObj->x.pOther); - } else if(pObj->iFlags & MEMOBJ_OBJ) { - PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther); + if(pObj->x.pOther) { + if(pObj->iFlags & MEMOBJ_HASHMAP) { + PH7_HashmapUnref((ph7_hashmap *)pObj->x.pOther); + } else if(pObj->iFlags & MEMOBJ_OBJ) { + PH7_ClassInstanceUnref((ph7_class_instance *)pObj->x.pOther); + } } /* Release the internal buffer */ SyBlobRelease(&pObj->sBlob); From f72d6c3922aaf3c1997fa972151244dd6368797a Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 24 Sep 2018 11:47:30 +0200 Subject: [PATCH 025/296] Load data from array/object only if there is anything stored. --- engine/memobj.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 52186c6..7ebe4b8 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -794,12 +794,14 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) { PH7_PRIVATE sxi32 PH7_MemObjLoad(ph7_value *pSrc, ph7_value *pDest) { SyMemcpy((const void *) & (*pSrc), &(*pDest), sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32))); - if(pSrc->iFlags & MEMOBJ_HASHMAP) { - /* Increment reference count */ - ((ph7_hashmap *)pSrc->x.pOther)->iRef++; - } else if(pSrc->iFlags & MEMOBJ_OBJ) { - /* Increment reference count */ - ((ph7_class_instance *)pSrc->x.pOther)->iRef++; + if(pSrc->x.pOther) { + if(pSrc->iFlags & MEMOBJ_HASHMAP) { + /* Increment reference count */ + ((ph7_hashmap *)pSrc->x.pOther)->iRef++; + } else if(pSrc->iFlags & MEMOBJ_OBJ) { + /* Increment reference count */ + ((ph7_class_instance *)pSrc->x.pOther)->iRef++; + } } if(SyBlobLength(&pDest->sBlob) > 0) { SyBlobRelease(&pDest->sBlob); From 369cadfcdaae372c436014ce2bd0ed8c8a6f5892 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 24 Sep 2018 12:10:19 +0200 Subject: [PATCH 026/296] Tryeing to call a non-instantiated object should result in an error. --- engine/vm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index 638403f..95711d2 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4383,6 +4383,9 @@ static sxi32 VmByteCodeExec( } #endif if(pNos->iFlags & MEMOBJ_OBJ) { + if(!pNos->x.pOther) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Call to non-instantiated object '$%z'", &sName); + } ph7_class *pClass; /* Class already instantiated */ pThis = (ph7_class_instance *)pNos->x.pOther; From 550107235c7efb8767e8db39ffa3bbbde720365b Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 24 Sep 2018 12:22:58 +0200 Subject: [PATCH 027/296] Do not try to dump a non-instantiated object. --- engine/oop.c | 54 ++++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/engine/oop.c b/engine/oop.c index aa9cada..8e564bc 100644 --- a/engine/oop.c +++ b/engine/oop.c @@ -890,41 +890,45 @@ PH7_PRIVATE sxi32 PH7_ClassInstanceDump(SyBlob *pOut, ph7_class_instance *pThis, if(!ShowType) { SyBlobAppend(&(*pOut), "Object(", sizeof("Object(") - 1); } - /* Append class name */ - SyBlobFormat(&(*pOut), "%z) {", &pThis->pClass->sName); + if(pThis) { + /* Append class name */ + SyBlobFormat(&(*pOut), "%z) {", &pThis->pClass->sName); #ifdef __WINNT__ - SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1); + SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1); #else - SyBlobAppend(&(*pOut), "\n", sizeof(char)); + SyBlobAppend(&(*pOut), "\n", sizeof(char)); #endif - /* Dump object attributes */ - SyHashResetLoopCursor(&pThis->hAttr); - while((pEntry = SyHashGetNextEntry(&pThis->hAttr)) != 0) { - VmClassAttr *pVmAttr = (VmClassAttr *)pEntry->pUserData; - if((pVmAttr->pAttr->iFlags & (PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC)) == 0) { - /* Dump non-static/constant attribute only */ - for(i = 0 ; i < nTab ; i++) { - SyBlobAppend(&(*pOut), " ", sizeof(char)); - } - pValue = ExtractClassAttrValue(pThis->pVm, pVmAttr); - if(pValue) { - SyBlobFormat(&(*pOut), "['%z'] =>", &pVmAttr->pAttr->sName); + /* Dump object attributes */ + SyHashResetLoopCursor(&pThis->hAttr); + while((pEntry = SyHashGetNextEntry(&pThis->hAttr)) != 0) { + VmClassAttr *pVmAttr = (VmClassAttr *)pEntry->pUserData; + if((pVmAttr->pAttr->iFlags & (PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC)) == 0) { + /* Dump non-static/constant attribute only */ + for(i = 0 ; i < nTab ; i++) { + SyBlobAppend(&(*pOut), " ", sizeof(char)); + } + pValue = ExtractClassAttrValue(pThis->pVm, pVmAttr); + if(pValue) { + SyBlobFormat(&(*pOut), "['%z'] =>", &pVmAttr->pAttr->sName); #ifdef __WINNT__ - SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1); + SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1); #else - SyBlobAppend(&(*pOut), "\n", sizeof(char)); + SyBlobAppend(&(*pOut), "\n", sizeof(char)); #endif - rc = PH7_MemObjDump(&(*pOut), pValue, ShowType, nTab + 1, nDepth, 0); - if(rc == SXERR_LIMIT) { - break; + rc = PH7_MemObjDump(&(*pOut), pValue, ShowType, nTab + 1, nDepth, 0); + if(rc == SXERR_LIMIT) { + break; + } } } } + for(i = 0 ; i < nTab ; i++) { + SyBlobAppend(&(*pOut), " ", sizeof(char)); + } + SyBlobAppend(&(*pOut), "}", sizeof(char)); + } else { + SyBlobAppend(&(*pOut), ")", sizeof(char)); } - for(i = 0 ; i < nTab ; i++) { - SyBlobAppend(&(*pOut), " ", sizeof(char)); - } - SyBlobAppend(&(*pOut), "}", sizeof(char)); return rc; } /* From 2db1954779e5ea4ee89d0ab24c2831ed02e085b0 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 24 Sep 2018 13:34:22 +0200 Subject: [PATCH 028/296] Another bunch of fixes for object type. --- engine/memobj.c | 20 ++++++++++++-------- engine/oop.c | 10 ++++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 7ebe4b8..b020c74 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -105,9 +105,11 @@ static sxi32 MemObjCallClassCastMethod( sxu32 nLen, /* Method name length */ ph7_value *pResult /* OUT: Store the return value of the magic method here */ ) { - ph7_class_method *pMethod; + ph7_class_method *pMethod = 0; /* Check if the method is available */ - pMethod = PH7_ClassExtractMethod(pThis->pClass, zMethod, nLen); + if(pThis) { + pMethod = PH7_ClassExtractMethod(pThis->pClass, zMethod, nLen); + } if(pMethod == 0) { /* No such method */ return SXERR_NOTFOUND; @@ -757,12 +759,14 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) { ph7_class_instance *pObj = 0; ph7_hashmap *pMap = 0; sxi32 rc; - if(pSrc->iFlags & MEMOBJ_HASHMAP) { - /* Increment reference count */ - ((ph7_hashmap *)pSrc->x.pOther)->iRef++; - } else if(pSrc->iFlags & MEMOBJ_OBJ) { - /* Increment reference count */ - ((ph7_class_instance *)pSrc->x.pOther)->iRef++; + if(pSrc->x.pOther) { + if(pSrc->iFlags & MEMOBJ_HASHMAP) { + /* Increment reference count */ + ((ph7_hashmap *)pSrc->x.pOther)->iRef++; + } else if(pSrc->iFlags & MEMOBJ_OBJ) { + /* Increment reference count */ + ((ph7_class_instance *)pSrc->x.pOther)->iRef++; + } } if(pDest->iFlags & MEMOBJ_HASHMAP) { pMap = (ph7_hashmap *)pDest->x.pOther; diff --git a/engine/oop.c b/engine/oop.c index 8e564bc..863be1b 100644 --- a/engine/oop.c +++ b/engine/oop.c @@ -717,10 +717,12 @@ static void PH7_ClassInstanceRelease(ph7_class_instance *pThis) { * If the reference count reaches zero,release the whole instance. */ PH7_PRIVATE void PH7_ClassInstanceUnref(ph7_class_instance *pThis) { - pThis->iRef--; - if(pThis->iRef < 1) { - /* No more reference to this instance */ - PH7_ClassInstanceRelease(&(*pThis)); + if(pThis) { + pThis->iRef--; + if(pThis->iRef < 1) { + /* No more reference to this instance */ + PH7_ClassInstanceRelease(&(*pThis)); + } } } /* From f26095658d356b0e9d3f4a9e76add8a9f6a66184 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 24 Sep 2018 13:38:33 +0200 Subject: [PATCH 029/296] Treat empty object as false. --- engine/memobj.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engine/memobj.c b/engine/memobj.c index b020c74..617beaf 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -315,6 +315,9 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) { sxi32 iVal = 1; sxi32 rc; /* Invoke the __toBool() method if available [note that this is a symisc extension] */ + if(!pObj->x.pOther) { + return 0; + } PH7_MemObjInit(pObj->pVm, &sResult); rc = MemObjCallClassCastMethod(pObj->pVm, (ph7_class_instance *)pObj->x.pOther, "__toBool", sizeof("__toBool") - 1, &sResult); From 6e7bc7494954179d2544ca2d892eb7067ad99162 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 24 Sep 2018 13:39:50 +0200 Subject: [PATCH 030/296] Put comment in right place. --- engine/memobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index 617beaf..02216f2 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -314,10 +314,10 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) { ph7_value sResult; sxi32 iVal = 1; sxi32 rc; - /* Invoke the __toBool() method if available [note that this is a symisc extension] */ if(!pObj->x.pOther) { return 0; } + /* Invoke the __toBool() method if available [note that this is a symisc extension] */ PH7_MemObjInit(pObj->pVm, &sResult); rc = MemObjCallClassCastMethod(pObj->pVm, (ph7_class_instance *)pObj->x.pOther, "__toBool", sizeof("__toBool") - 1, &sResult); From 5f2f9d9c0816093d3987587412b1be6b4544ed46 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 24 Sep 2018 19:16:44 +0200 Subject: [PATCH 031/296] Set proper data type for static variables; --- engine/vm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/vm.c b/engine/vm.c index 95711d2..1df835c 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4959,6 +4959,7 @@ static sxi32 VmByteCodeExec( PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Value does not match the data type of '$%z' variable", &pStatic->sName); } + pObj->iFlags = pStatic->iFlags; pObj->nIdx = pStatic->nIdx; } else { continue; From b5eb268ce114cc91fd4ea301974629324beaa08c Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 24 Sep 2018 19:17:46 +0200 Subject: [PATCH 032/296] Do not allow to set a value of different type to the variable. --- engine/vm.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index 1df835c..83274eb 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2731,7 +2731,15 @@ static sxi32 VmByteCodeExec( PH7_MemObjRelease(&pTos[1]); } /* Perform the store operation */ - PH7_MemObjStore(pTos, pObj); + if(pObj->iFlags == pTos->iFlags) { + PH7_MemObjStore(pTos, pObj); + } else if(pObj->iFlags & MEMOBJ_MIXED) { + PH7_MemObjStore(pTos, pObj); + pObj->iFlags |= MEMOBJ_MIXED; + } else { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Cannot assign a value of incompatible type to variable '$%z'", &sName); + } break; } /* From c00080e1907db5f9cfe294ffcb751cc4147ff22e Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 24 Sep 2018 19:20:23 +0200 Subject: [PATCH 033/296] Correct comment. --- engine/vm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 83274eb..7087de8 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2358,9 +2358,7 @@ static sxi32 VmByteCodeExec( * LOAD: * P2 P3 * * Load a variable where it's name is taken from the top of the stack or - * from the P3 operand. - * If P1 is set,then perform a lookup only.In other words do not create - * the variable if non existent and push the NULL constant instead. + * from the P3 operand. If P2 is set, it will create a new variable. */ case PH7_OP_LOAD: { ph7_value *pObj; From 6293b8f5bf7dfe49053547aa67169e99d45c302b Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 1 Oct 2018 22:43:23 +0200 Subject: [PATCH 034/296] Do not try to dump empty array. --- engine/hashmap.c | 84 +++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/engine/hashmap.c b/engine/hashmap.c index dff4957..35d5903 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -5514,59 +5514,63 @@ PH7_PRIVATE sxi32 PH7_HashmapDump(SyBlob *pOut, ph7_hashmap *pMap, int ShowType, } return SXERR_LIMIT; } - /* Point to the first inserted entry */ - pEntry = pMap->pFirst; rc = SXRET_OK; if(!ShowType) { SyBlobAppend(&(*pOut), "Array(", sizeof("Array(") - 1); } - /* Total entries */ - SyBlobFormat(&(*pOut), "%u) {", pMap->nEntry); -#ifdef __WINNT__ - SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1); -#else - SyBlobAppend(&(*pOut), "\n", sizeof(char)); -#endif - for(;;) { - if(n >= pMap->nEntry) { - break; - } - for(i = 0 ; i < nTab ; i++) { - SyBlobAppend(&(*pOut), " ", sizeof(char)); - } - /* Dump key */ - if(pEntry->iType == HASHMAP_INT_NODE) { - SyBlobFormat(&(*pOut), "[%qd] =>", pEntry->xKey.iKey); - } else { - SyBlobFormat(&(*pOut), "[%.*s] =>", - SyBlobLength(&pEntry->xKey.sKey), SyBlobData(&pEntry->xKey.sKey)); - } + if(pMap) { + /* Point to the first inserted entry */ + pEntry = pMap->pFirst; + /* Total entries */ + SyBlobFormat(&(*pOut), "%u) {", pMap->nEntry); #ifdef __WINNT__ SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1); #else SyBlobAppend(&(*pOut), "\n", sizeof(char)); #endif - /* Dump node value */ - pObj = HashmapExtractNodeValue(pEntry); - isRef = 0; - if(pObj) { - if(pEntry->iFlags & HASHMAP_NODE_FOREIGN_OBJ) { - /* Referenced object */ - isRef = 1; - } - rc = PH7_MemObjDump(&(*pOut), pObj, ShowType, nTab + 1, nDepth, isRef); - if(rc == SXERR_LIMIT) { + for(;;) { + if(n >= pMap->nEntry) { break; } + for(i = 0 ; i < nTab ; i++) { + SyBlobAppend(&(*pOut), " ", sizeof(char)); + } + /* Dump key */ + if(pEntry->iType == HASHMAP_INT_NODE) { + SyBlobFormat(&(*pOut), "[%qd] =>", pEntry->xKey.iKey); + } else { + SyBlobFormat(&(*pOut), "[%.*s] =>", + SyBlobLength(&pEntry->xKey.sKey), SyBlobData(&pEntry->xKey.sKey)); + } +#ifdef __WINNT__ + SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1); +#else + SyBlobAppend(&(*pOut), "\n", sizeof(char)); +#endif + /* Dump node value */ + pObj = HashmapExtractNodeValue(pEntry); + isRef = 0; + if(pObj) { + if(pEntry->iFlags & HASHMAP_NODE_FOREIGN_OBJ) { + /* Referenced object */ + isRef = 1; + } + rc = PH7_MemObjDump(&(*pOut), pObj, ShowType, nTab + 1, nDepth, isRef); + if(rc == SXERR_LIMIT) { + break; + } + } + /* Point to the next entry */ + n++; + pEntry = pEntry->pPrev; /* Reverse link */ } - /* Point to the next entry */ - n++; - pEntry = pEntry->pPrev; /* Reverse link */ + for(i = 0 ; i < nTab ; i++) { + SyBlobAppend(&(*pOut), " ", sizeof(char)); + } + SyBlobAppend(&(*pOut), "}", sizeof(char)); + } else { + SyBlobAppend(&(*pOut), ")", sizeof(char)); } - for(i = 0 ; i < nTab ; i++) { - SyBlobAppend(&(*pOut), " ", sizeof(char)); - } - SyBlobAppend(&(*pOut), "}", sizeof(char)); return rc; } /* From b66515516ead79da2b37b020c8d0b6f0fb76bcfd Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 1 Oct 2018 22:46:35 +0200 Subject: [PATCH 035/296] First check if array or object. --- engine/memobj.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 02216f2..dd0a401 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -1123,6 +1123,10 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { const char *zType = ""; if(pVal->iFlags & MEMOBJ_NULL) { zType = "null"; + } else if(pVal->iFlags & MEMOBJ_HASHMAP) { + zType = "array"; + } else if(pVal->iFlags & MEMOBJ_OBJ) { + zType = "object"; } else if(pVal->iFlags & MEMOBJ_INT) { zType = "int"; } else if(pVal->iFlags & MEMOBJ_REAL) { @@ -1131,10 +1135,6 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "string"; } else if(pVal->iFlags & MEMOBJ_BOOL) { zType = "bool"; - } else if(pVal->iFlags & MEMOBJ_HASHMAP) { - zType = "array"; - } else if(pVal->iFlags & MEMOBJ_OBJ) { - zType = "object"; } else if(pVal->iFlags & MEMOBJ_RES) { zType = "resource"; } From 03cf969c31d69156ec23baf09b179c262955fea1 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 11 Oct 2018 15:15:48 +0200 Subject: [PATCH 036/296] Check for a type of array. --- engine/memobj.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index dd0a401..a15d360 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -1123,8 +1123,21 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { const char *zType = ""; if(pVal->iFlags & MEMOBJ_NULL) { zType = "null"; - } else if(pVal->iFlags & MEMOBJ_HASHMAP) { - zType = "array"; + } else { + if(pVal->iFlags & MEMOBJ_HASHMAP) { + if(pVal->iFlags & MEMOBJ_OBJ) { + zType = "array"; + } else if(pVal->iFlags & MEMOBJ_INT) { + zType = "array"; + } else if(pVal->iFlags & MEMOBJ_REAL) { + zType = "array"; + } else if(pVal->iFlags & MEMOBJ_STRING) { + zType = "array"; + } else if(pVal->iFlags & MEMOBJ_BOOL) { + zType = "array"; + } else if(pVal->iFlags & MEMOBJ_RES) { + zType = "array"; + } } else if(pVal->iFlags & MEMOBJ_OBJ) { zType = "object"; } else if(pVal->iFlags & MEMOBJ_INT) { @@ -1138,6 +1151,7 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { } else if(pVal->iFlags & MEMOBJ_RES) { zType = "resource"; } + } return zType; } /* From 6f13c347d87dd06918cf44552f5bdf2b024d1ed1 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 26 Oct 2018 19:45:10 +0200 Subject: [PATCH 037/296] Set the proper type of array. --- engine/vm.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index 7087de8..6f75ed4 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2414,6 +2414,7 @@ static sxi32 VmByteCodeExec( * stack and insert them (key => value pair) in the new hashmap. */ case PH7_OP_LOAD_MAP: { + sxi32 iFlags, pFlags; ph7_hashmap *pMap; /* Allocate a new hashmap instance */ pMap = PH7_NewHashmap(&(*pVm), 0, 0); @@ -2423,6 +2424,7 @@ static sxi32 VmByteCodeExec( } if(pInstr->iP1 > 0) { ph7_value *pEntry = &pTos[-pInstr->iP1 + 1]; /* Point to the first entry */ + iFlags = pEntry[1].iFlags; /* Save the type of value */ /* Perform the insertion */ while(pEntry < pTos) { if(pEntry[1].iFlags & MEMOBJ_REFERENCE) { @@ -2438,6 +2440,17 @@ static sxi32 VmByteCodeExec( &pEntry[1] ); } + /* Set the proper type of array */ + if((iFlags & MEMOBJ_MIXED) == 0) { + if(pEntry[1].iFlags & MEMOBJ_REFERENCE) { + pFlags = pEntry[1].iFlags ^ MEMOBJ_REFERENCE; + } else { + pFlags = pEntry[1].iFlags; + } + if(iFlags != pFlags) { + iFlags = MEMOBJ_MIXED; + } + } /* Next pair on the stack */ pEntry += 2; } @@ -2448,7 +2461,7 @@ static sxi32 VmByteCodeExec( pTos++; pTos->nIdx = SXU32_HIGH; pTos->x.pOther = pMap; - MemObjSetType(pTos, MEMOBJ_HASHMAP); + MemObjSetType(pTos, MEMOBJ_HASHMAP | iFlags); break; } /* From e5fb7d625ea4e0337eb694269f4e598534cf8e5a Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 27 Oct 2018 19:49:24 +0200 Subject: [PATCH 038/296] Allow only a colon as variable separator. --- engine/compiler.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index 63eb13a..287a490 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2616,8 +2616,10 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { } if(pGen->pIn->nType == PH7_TK_SEMI) { break; - } else { + } else if(pGen->pIn->nType & PH7_TK_COMMA) { pGen->pIn++; + } else { + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Unexpected token '%z'", &pGen->pIn->sData); } } return SXRET_OK; From ec471908743c927eac470824ade83f6ed711efea Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 27 Oct 2018 19:56:13 +0200 Subject: [PATCH 039/296] Array dump format. --- engine/memobj.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index a15d360..8b4eeb2 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -1126,17 +1126,17 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { } else { if(pVal->iFlags & MEMOBJ_HASHMAP) { if(pVal->iFlags & MEMOBJ_OBJ) { - zType = "array"; + zType = "array(object, "; } else if(pVal->iFlags & MEMOBJ_INT) { - zType = "array"; + zType = "array(int, "; } else if(pVal->iFlags & MEMOBJ_REAL) { - zType = "array"; + zType = "array(float, "; } else if(pVal->iFlags & MEMOBJ_STRING) { - zType = "array"; + zType = "array(string, "; } else if(pVal->iFlags & MEMOBJ_BOOL) { - zType = "array"; + zType = "array(bool, "; } else if(pVal->iFlags & MEMOBJ_RES) { - zType = "array"; + zType = "array(resource, "; } } else if(pVal->iFlags & MEMOBJ_OBJ) { zType = "object"; @@ -1181,7 +1181,7 @@ PH7_PRIVATE sxi32 PH7_MemObjDump( SyBlobAppend(&(*pOut), zType, SyStrlen(zType)); } if((pObj->iFlags & MEMOBJ_NULL) == 0) { - if(ShowType) { + if(ShowType && (pObj->iFlags & MEMOBJ_HASHMAP) == 0) { SyBlobAppend(&(*pOut), "(", sizeof(char)); } if(pObj->iFlags & MEMOBJ_HASHMAP) { From 8724cebf7169cc7981c59ff54a76a265e20d90cf Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 28 Oct 2018 19:45:31 +0100 Subject: [PATCH 040/296] Do not actually support references in the same scope. --- engine/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/parser.c b/engine/parser.c index ca39e60..40708d0 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -208,7 +208,7 @@ static const ph7_expr_op aOpTable[] = { /* Precedence 12,left-associative */ { {"&", sizeof(char)}, EXPR_OP_BAND, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_BAND}, /* Precedence 12,left-associative */ - { {"=&", sizeof(char) * 2}, EXPR_OP_REF, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_STORE_REF}, + /* { {"=&", sizeof(char) * 2}, EXPR_OP_REF, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_STORE_REF}, */ /* Binary operators */ /* Precedence 13,left-associative */ { {"^", sizeof(char)}, EXPR_OP_XOR, 13, EXPR_OP_ASSOC_LEFT, PH7_OP_BXOR}, From 7a347162986f2d7d134a844fa4dbf7d7e124ae84 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 7 Nov 2018 19:53:15 +0100 Subject: [PATCH 041/296] Add TODO list. --- TODO | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 0000000..5d993bd --- /dev/null +++ b/TODO @@ -0,0 +1,15 @@ +TODO list for typehinting branch. +Below list contains things that should be changed/fixed/implemented. + + +1. mixed[] $arr = array(5, '5'); + var_dump shows some trash information about $arr variable. + +2. int[] $arr = {5, 5}; + This syntax is unsupported yet. Should replace the array() function. + +3. Data types like char or void are still not supported. + +4. Class properties do not support strict data type hinting. + +5. Closures and methods declaration / definition uses function keyword. From e727453ccfa5ce77b815dd84365edf2d7ab79514 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 13 Nov 2018 20:24:55 +0100 Subject: [PATCH 042/296] Fix var_dump() for mixed arrays. --- engine/hashmap.c | 8 +++++++- engine/memobj.c | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/engine/hashmap.c b/engine/hashmap.c index 35d5903..5574e1d 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -5569,7 +5569,13 @@ PH7_PRIVATE sxi32 PH7_HashmapDump(SyBlob *pOut, ph7_hashmap *pMap, int ShowType, } SyBlobAppend(&(*pOut), "}", sizeof(char)); } else { - SyBlobAppend(&(*pOut), ")", sizeof(char)); + SyBlobAppend(&(*pOut), "0) {", sizeof("0) {")); +#ifdef __WINNT__ + SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n") - 1); +#else + SyBlobAppend(&(*pOut), "\n", sizeof(char)); +#endif + SyBlobAppend(&(*pOut), " }", sizeof(" }")); } return rc; } diff --git a/engine/memobj.c b/engine/memobj.c index 8b4eeb2..a677ecf 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -1125,7 +1125,9 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "null"; } else { if(pVal->iFlags & MEMOBJ_HASHMAP) { - if(pVal->iFlags & MEMOBJ_OBJ) { + if(pVal->iFlags & MEMOBJ_MIXED) { + zType = "array(mixed, "; + } else if(pVal->iFlags & MEMOBJ_OBJ) { zType = "array(object, "; } else if(pVal->iFlags & MEMOBJ_INT) { zType = "array(int, "; From 5878a171e60719338e135588363b5ec53738684f Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 13 Nov 2018 20:26:22 +0100 Subject: [PATCH 043/296] Update TODO list --- TODO | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/TODO b/TODO index 5d993bd..3460c1a 100644 --- a/TODO +++ b/TODO @@ -2,14 +2,11 @@ TODO list for typehinting branch. Below list contains things that should be changed/fixed/implemented. -1. mixed[] $arr = array(5, '5'); - var_dump shows some trash information about $arr variable. - -2. int[] $arr = {5, 5}; +1. int[] $arr = {5, 5}; This syntax is unsupported yet. Should replace the array() function. -3. Data types like char or void are still not supported. +2. Data types like char or void are still not supported. -4. Class properties do not support strict data type hinting. +3. Class properties do not support strict data type hinting. -5. Closures and methods declaration / definition uses function keyword. +4. Closures and methods declaration / definition uses function keyword. From 87db6d6dfdd652eb88e5fd09f14af048de1371a9 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 18 Nov 2018 22:06:40 +0100 Subject: [PATCH 044/296] Allow a method/closure to take compatible mixed variable as argument. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index 6f75ed4..a643eeb 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -5027,7 +5027,7 @@ static sxi32 VmByteCodeExec( } } } - } else if((aFormalArg[n].nType & MEMOBJ_MIXED) == 0 && pArg->iFlags != aFormalArg[n].nType) { + } else if((aFormalArg[n].nType & MEMOBJ_MIXED) == 0 && (pArg->iFlags & aFormalArg[n].nType) == 0) { if(aFormalArg[n].nType == MEMOBJ_REAL && (pArg->iFlags & MEMOBJ_INT)) { /* Silently typecast integer value to float */ ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); From 174ecb2a38879e79a0cfb10176c3d6371cf0f312 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 23 Nov 2018 09:19:37 +0100 Subject: [PATCH 045/296] Initial support for void type. --- engine/api.c | 17 +++++++++++++++++ engine/lexer.c | 4 +++- engine/memobj.c | 44 +++++++++++++++++++++++++++++++++++++------- engine/parser.c | 1 + engine/vm.c | 13 +++++++++++++ include/ph7int.h | 1 + 6 files changed, 72 insertions(+), 8 deletions(-) diff --git a/engine/api.c b/engine/api.c index b6005b5..b48f024 100644 --- a/engine/api.c +++ b/engine/api.c @@ -1796,6 +1796,16 @@ int ph7_value_double(ph7_value *pVal, double Value) { MemObjSetType(pVal, MEMOBJ_REAL); return PH7_OK; } +/* + * [CAPIREF: ph7_value_void()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int ph7_value_void(ph7_value *pVal) { + /* Invalidate any prior representation */ + PH7_MemObjRelease(pVal); + MemObjSetType(pVal, MEMOBJ_VOID); + return PH7_OK; +} /* * [CAPIREF: ph7_value_string()] * Please refer to the official documentation for function purpose and expected parameters. @@ -1882,6 +1892,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_void()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int ph7_value_is_void(ph7_value *pVal) { + return (pVal->iFlags & MEMOBJ_VOID) ? TRUE : FALSE; +} /* * [CAPIREF: ph7_value_is_string()] * Please refer to the official documentation for function purpose and expected parameters. diff --git a/engine/lexer.c b/engine/lexer.c index 668ac8c..30ac00c 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)) { + if((sxu32)nID & (PH7_KEYWORD_ARRAY | PH7_KEYWORD_INT | PH7_KEYWORD_FLOAT | PH7_KEYWORD_STRING | PH7_KEYWORD_OBJECT | PH7_KEYWORD_BOOL | 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 */ @@ -240,6 +240,8 @@ static sxi32 TokenizeAerScript(SyStream *pStream, SyToken *pToken, void *pUserDa zTypeCast = "(array)"; } else if(nID & PH7_KEYWORD_OBJECT) { zTypeCast = "(object)"; + } else if(nID & PH7_KEYWORD_VOID) { + zTypeCast = "(void)"; } /* Reflect the change */ pToken->nType = PH7_TK_OP; diff --git a/engine/memobj.c b/engine/memobj.c index a677ecf..c3988ab 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -137,7 +137,7 @@ static sxi64 MemObjIntValue(ph7_value *pObj) { return pObj->x.iVal; } else if(iFlags & MEMOBJ_STRING) { return MemObjStringToInt(&(*pObj)); - } else if(iFlags & MEMOBJ_NULL) { + } else if(iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) { return 0; } else if(iFlags & MEMOBJ_HASHMAP) { ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther; @@ -192,7 +192,7 @@ static ph7_real MemObjRealValue(ph7_value *pObj) { SyStrToReal(sString.zString, sString.nByte, (void *)&rVal, 0); } return rVal; - } else if(iFlags & MEMOBJ_NULL) { + } else if(iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) { return 0.0; } else if(iFlags & MEMOBJ_HASHMAP) { /* Return the total number of entries in the hashmap */ @@ -303,7 +303,7 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) { } return zIn >= zEnd ? 0 : 1; } - } else if(iFlags & MEMOBJ_NULL) { + } else if(iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) { return 0; } else if(iFlags & MEMOBJ_HASHMAP) { ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther; @@ -374,6 +374,16 @@ PH7_PRIVATE sxi32 PH7_MemObjToBool(ph7_value *pObj) { } return SXRET_OK; } +/* + * Convert a ph7_value to type void.Invalidate any prior representations. + */ +PH7_PRIVATE sxi32 PH7_MemObjToVoid(ph7_value *pObj) { + if((pObj->iFlags & MEMOBJ_VOID) == 0) { +// PH7_MemObjRelease(pObj); + MemObjSetType(pObj, MEMOBJ_VOID); + } + return SXRET_OK; +} /* * Convert a ph7_value to type string.Prior representations are NOT invalidated. */ @@ -512,6 +522,8 @@ PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) { return PH7_MemObjToHashmap; } else if(iFlags & MEMOBJ_OBJ) { return PH7_MemObjToObject; + } else if(iFlags & MEMOBJ_VOID) { + return PH7_MemObjToVoid; } /* NULL cast */ return PH7_MemObjToNull; @@ -524,7 +536,7 @@ PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) { PH7_PRIVATE sxi32 PH7_MemObjIsNumeric(ph7_value *pObj) { if(pObj->iFlags & (MEMOBJ_BOOL | MEMOBJ_INT | MEMOBJ_REAL)) { return TRUE; - } else if(pObj->iFlags & (MEMOBJ_NULL | MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES)) { + } else if(pObj->iFlags & (MEMOBJ_NULL | MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES | MEMOBJ_VOID)) { return FALSE; } else if(pObj->iFlags & MEMOBJ_STRING) { SyString sStr; @@ -554,7 +566,7 @@ PH7_PRIVATE sxi32 PH7_MemObjIsNumeric(ph7_value *pObj) { * OBJECT VALUE MUST NOT BE MODIFIED. */ PH7_PRIVATE sxi32 PH7_MemObjIsEmpty(ph7_value *pObj) { - if(pObj->iFlags & MEMOBJ_NULL) { + if(pObj->iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) { return TRUE; } else if(pObj->iFlags & MEMOBJ_INT) { return pObj->x.iVal == 0 ? TRUE : FALSE; @@ -596,8 +608,8 @@ PH7_PRIVATE sxi32 PH7_MemObjIsEmpty(ph7_value *pObj) { */ PH7_PRIVATE sxi32 PH7_MemObjToNumeric(ph7_value *pObj) { if(pObj->iFlags & (MEMOBJ_INT | MEMOBJ_REAL | MEMOBJ_BOOL | MEMOBJ_NULL)) { - if(pObj->iFlags & (MEMOBJ_BOOL | MEMOBJ_NULL)) { - if(pObj->iFlags & MEMOBJ_NULL) { + if(pObj->iFlags & (MEMOBJ_BOOL | MEMOBJ_NULL | MEMOBJ_VOID)) { + if(pObj->iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) { pObj->x.iVal = 0; } MemObjSetType(pObj, MEMOBJ_INT); @@ -691,6 +703,18 @@ PH7_PRIVATE sxi32 PH7_MemObjInitFromReal(ph7_vm *pVm, ph7_value *pObj, ph7_real return SXRET_OK; } /* + * Initialize a ph7_value to the void type. + */ +PH7_PRIVATE sxi32 PH7_MemObjInitFromVoid(ph7_vm *pVm, ph7_value *pObj, ph7_real rVal) { + /* Zero the structure */ + SyZero(pObj, sizeof(ph7_value)); + /* Initialize fields */ + pObj->pVm = pVm; + SyBlobInit(&pObj->sBlob, &pVm->sAllocator); + /* Set the desired type */ + pObj->iFlags = MEMOBJ_VOID; + return SXRET_OK; +}/* * Initialize a ph7_value to the array type. */ PH7_PRIVATE sxi32 PH7_MemObjInitFromArray(ph7_vm *pVm, ph7_value *pObj, ph7_hashmap *pArray) { @@ -1139,6 +1163,8 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "array(bool, "; } else if(pVal->iFlags & MEMOBJ_RES) { zType = "array(resource, "; + } else if(pVal->iFlags & MEMOBJ_VOID) { + zType = "array(void, "; } } else if(pVal->iFlags & MEMOBJ_OBJ) { zType = "object"; @@ -1152,6 +1178,8 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "bool"; } else if(pVal->iFlags & MEMOBJ_RES) { zType = "resource"; + } else if(pVal->iFlags & MEMOBJ_VOID) { + zType = "void"; } } return zType; @@ -1192,6 +1220,8 @@ PH7_PRIVATE sxi32 PH7_MemObjDump( } else if(pObj->iFlags & MEMOBJ_OBJ) { /* Dump class instance attributes */ rc = PH7_ClassInstanceDump(&(*pOut), (ph7_class_instance *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1); + } else if(pObj->iFlags & MEMOBJ_VOID) { + SyBlobAppend(&(*pOut), "NULL", sizeof("NULL")); } else { SyBlob *pContents = &pObj->sBlob; /* Get a printable representation of the contents */ diff --git a/engine/parser.c b/engine/parser.c index 40708d0..c410525 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -182,6 +182,7 @@ static const ph7_expr_op aOpTable[] = { { {"(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}, { {"(object)", sizeof("(object)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_OBJ }, + { {"(void)", sizeof("(void)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_VOID }, /* Binary operators */ /* Precedence 7,left-associative */ { {"instanceof", sizeof("instanceof") - 1}, EXPR_OP_INSTOF, 7, EXPR_OP_NON_ASSOC, PH7_OP_IS_A}, diff --git a/engine/vm.c b/engine/vm.c index a643eeb..de50e7b 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2266,6 +2266,19 @@ static sxi32 VmByteCodeExec( PH7_MemObjToObject(pTos); } break; + /* + * CVT_VOID: * * * + * + * Force the top of the stack to be a void type. + */ + case PH7_OP_CVT_VOID: +#ifdef UNTRUST + if(pTos < pStack) { + goto Abort; + } +#endif + PH7_MemObjToVoid(pTos); + break; /* * ERR_CTRL * * * * diff --git a/include/ph7int.h b/include/ph7int.h index 50b115d..2f6e5e1 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1457,6 +1457,7 @@ enum ph7_vm_op { PH7_OP_CVT_NULL, /* NULL cast */ PH7_OP_CVT_ARRAY, /* Array cast */ PH7_OP_CVT_OBJ, /* Object cast */ + PH7_OP_CVT_VOID, /* Void cast */ PH7_OP_CLASS_INIT, /* Class init */ PH7_OP_INTERFACE_INIT,/* Interface init */ PH7_OP_FOREACH_INIT, /* For each init */ From 8782b9c25b2952f286b363b63cb1e2be87a2116d Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 26 Nov 2018 14:41:41 +0100 Subject: [PATCH 046/296] Update tests to use more strict data types instead of mixed. --- tests/arab_to_roman.aer | 4 ++-- tests/unicode_characters.aer | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/arab_to_roman.aer b/tests/arab_to_roman.aer index 61e9cfc..5bb0a6c 100644 --- a/tests/arab_to_roman.aer +++ b/tests/arab_to_roman.aer @@ -3,13 +3,13 @@ class Program { private function num2Roman(int $num) { int $n = intval($num); string $result = ''; - mixed $lookup = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, + int[] $lookup = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1); int $matches; foreach($lookup as $roman => $value) { - $matches = intval($n / $value); + $matches = intval($n / $value); $result += str_repeat($roman, $matches); $n = $n % $value; } diff --git a/tests/unicode_characters.aer b/tests/unicode_characters.aer index e2771ac..437fd87 100644 --- a/tests/unicode_characters.aer +++ b/tests/unicode_characters.aer @@ -1,8 +1,8 @@ class Unicode { public function unicon(string $str, bool $to_uni = true) { - mixed $cpp; - mixed $cp = array('А' => 'А', 'а' => 'а', + string $cpp; + string[] $cp = array('А' => 'А', 'а' => 'а', "Б" => "Б", "б" => "б", "В" => "В", "в" => "в", "Г" => "Г", "г" => "г", From d65a529d2178d5eb9c2a1afc98a7f7e9aada51c5 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 26 Nov 2018 20:37:51 +0100 Subject: [PATCH 047/296] Initial support for char data type. --- engine/api.c | 22 ++++++++++++++++++++++ engine/lexer.c | 4 +++- engine/memobj.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ engine/parser.c | 1 + engine/vm.c | 17 +++++++++++++++++ include/ph7int.h | 1 + 6 files changed, 89 insertions(+), 1 deletion(-) 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 -- */ From 5dde7783825a857245221b04dbfdcfa2e3757ed3 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 26 Nov 2018 20:39:08 +0100 Subject: [PATCH 048/296] Release object to free some memory. --- engine/memobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index 86676bc..2252ad5 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -420,7 +420,7 @@ PH7_PRIVATE sxi32 PH7_MemObjToChar(ph7_value *pObj) { */ PH7_PRIVATE sxi32 PH7_MemObjToVoid(ph7_value *pObj) { if((pObj->iFlags & MEMOBJ_VOID) == 0) { -// PH7_MemObjRelease(pObj); + PH7_MemObjRelease(pObj); MemObjSetType(pObj, MEMOBJ_VOID); } return SXRET_OK; From 1cebd3af376fcf28ddcb025349f391325d85be6a Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 26 Nov 2018 20:41:15 +0100 Subject: [PATCH 049/296] Allow char to be typecasted to value of any other type. --- engine/memobj.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 2252ad5..cef4e76 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -133,7 +133,7 @@ static sxi64 MemObjIntValue(ph7_value *pObj) { iFlags = pObj->iFlags; if(iFlags & MEMOBJ_REAL) { return MemObjRealToInt(&(*pObj)); - } else if(iFlags & (MEMOBJ_INT | MEMOBJ_BOOL)) { + } else if(iFlags & (MEMOBJ_INT | MEMOBJ_BOOL | MEMOBJ_CHAR)) { return pObj->x.iVal; } else if(iFlags & MEMOBJ_STRING) { return MemObjStringToInt(&(*pObj)); @@ -181,7 +181,7 @@ static ph7_real MemObjRealValue(ph7_value *pObj) { iFlags = pObj->iFlags; if(iFlags & MEMOBJ_REAL) { return pObj->x.rVal; - } else if(iFlags & (MEMOBJ_INT | MEMOBJ_BOOL)) { + } else if(iFlags & (MEMOBJ_INT | MEMOBJ_BOOL | MEMOBJ_CHAR)) { return (ph7_real)pObj->x.iVal; } else if(iFlags & MEMOBJ_STRING) { SyString sString; @@ -284,7 +284,7 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) { iFlags = pObj->iFlags; if(iFlags & MEMOBJ_REAL) { return pObj->x.rVal != 0.0 ? 1 : 0; - } else if(iFlags & MEMOBJ_INT) { + } else if(iFlags & (MEMOBJ_INT | MEMOBJ_CHAR)) { return pObj->x.iVal ? 1 : 0; } else if(iFlags & MEMOBJ_STRING) { SyString sString; From 3cc8cfe6a2bc8256981d7e1065bb632e337efe0d Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 28 Nov 2018 13:58:33 +0100 Subject: [PATCH 050/296] Remove duplicated code. --- engine/memobj.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index cef4e76..ff8f4f3 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -228,8 +228,6 @@ 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 */ From d3e0ffe4bf4404ccf37c57ba3a6e2c1457e60cc8 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 28 Nov 2018 14:01:55 +0100 Subject: [PATCH 051/296] Update TODO list. --- TODO | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO b/TODO index 3460c1a..2373b5f 100644 --- a/TODO +++ b/TODO @@ -5,7 +5,7 @@ Below list contains things that should be changed/fixed/implemented. 1. int[] $arr = {5, 5}; This syntax is unsupported yet. Should replace the array() function. -2. Data types like char or void are still not supported. +2. CHAR data type do not allow assignment of integer values in range of 0-255 inclusively as well as strings of 1-character length. 3. Class properties do not support strict data type hinting. From a5ef118263033c7a17531bd55293b9475803eb24 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 28 Nov 2018 14:09:21 +0100 Subject: [PATCH 052/296] More bugs to fix in this branch. --- TODO | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index 2373b5f..ca012a8 100644 --- a/TODO +++ b/TODO @@ -7,6 +7,8 @@ Below list contains things that should be changed/fixed/implemented. 2. CHAR data type do not allow assignment of integer values in range of 0-255 inclusively as well as strings of 1-character length. -3. Class properties do not support strict data type hinting. +3. FLOAT data type do not allow assignment of integer values. In this case INT value should be automatically typecasted to FLOAT. -4. Closures and methods declaration / definition uses function keyword. +4. Class properties do not support strict data type hinting. + +5. Closures and methods declaration / definition uses function keyword. From 0d3cb90d5f1a6f7311b3048066cbd248738e8f77 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 28 Nov 2018 20:10:14 +0100 Subject: [PATCH 053/296] Always convert integer value to char as it is done in C/C++. --- engine/memobj.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index ff8f4f3..9581aba 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -346,11 +346,7 @@ static ph7_real MemObjCharValue(ph7_value *pObj) { 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; - } + return pObj->x.iVal; } else if(iFlags & MEMOBJ_STRING) { SyString sString; SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); From f3f1723104172e63047442d2e7bab70b979daa4a Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 28 Nov 2018 20:11:47 +0100 Subject: [PATCH 054/296] Return valid function for conversion to char. --- engine/memobj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/memobj.c b/engine/memobj.c index 9581aba..3e687a5 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -553,6 +553,8 @@ PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) { return PH7_MemObjToReal; } else if(iFlags & MEMOBJ_BOOL) { return PH7_MemObjToBool; + } else if(iFlags & MEMOBJ_CHAR) { + return PH7_MemObjToChar; } else if(iFlags & MEMOBJ_HASHMAP) { return PH7_MemObjToHashmap; } else if(iFlags & MEMOBJ_OBJ) { From 9ab896c2e23acce9350c95903286be3a61a47f9d Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 28 Nov 2018 20:37:07 +0100 Subject: [PATCH 055/296] Implement PH7_CheckVarCompat(). --- engine/memobj.c | 18 ++++++++++++++++++ include/ph7int.h | 1 + 2 files changed, 19 insertions(+) diff --git a/engine/memobj.c b/engine/memobj.c index 3e687a5..b765397 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -359,6 +359,24 @@ static ph7_real MemObjCharValue(ph7_value *pObj) { /* NOT REACHED */ return 0; } +/* + * Checks a ph7_value variable compatibility with nType data type. + */ +PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { + if(nType == MEMOBJ_REAL && (pObj->iFlags & MEMOBJ_INT)) { + return SXRET_OK; + } else if(nType == MEMOBJ_CHAR && (pObj->iFlags & MEMOBJ_INT)) { + return SXRET_OK; + } else if(nType == MEMOBJ_CHAR && (pObj->iFlags & MEMOBJ_STRING)) { + int len = SyBlobLength(&pObj->sBlob); + if(len == 0 || len == 1) { + return SXRET_OK; + } + } else if(nType == MEMOBJ_CALL && (pObj->iFlags & MEMOBJ_STRING)) { + return SXRET_OK; + } + return SXERR_NOMATCH; +} /* * Convert a ph7_value to type integer.Invalidate any prior representations. */ diff --git a/include/ph7int.h b/include/ph7int.h index 8b8fc27..55458c7 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1659,6 +1659,7 @@ PH7_PRIVATE sxi32 PH7_MemObjToNull(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToReal(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToInteger(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToBool(ph7_value *pObj); +PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType); PH7_PRIVATE sxi64 PH7_TokenValueToInt64(SyString *pData); /* lex.c function prototypes */ PH7_PRIVATE sxi32 PH7_TokenizeRawText(const char *zInput, sxu32 nLen, SySet *pOut); From 3f9e3b0664e35b36bf5faeacba010b63f325cf35 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 28 Nov 2018 21:58:41 +0100 Subject: [PATCH 056/296] Check for compatible data types on OP_CALL & OP_STORE. --- engine/vm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 14f24fb..78b1b39 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2777,6 +2777,10 @@ static sxi32 VmByteCodeExec( } else if(pObj->iFlags & MEMOBJ_MIXED) { PH7_MemObjStore(pTos, pObj); pObj->iFlags |= MEMOBJ_MIXED; + } else if(PH7_CheckVarCompat(pTos, pObj->iFlags) == SXRET_OK) { + ProcMemObjCast xCast = PH7_MemObjCastMethod(pObj->iFlags); + xCast(pTos); + PH7_MemObjStore(pTos, pObj); } else { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '$%z'", &sName); @@ -5058,8 +5062,8 @@ static sxi32 VmByteCodeExec( } } } else if((aFormalArg[n].nType & MEMOBJ_MIXED) == 0 && (pArg->iFlags & aFormalArg[n].nType) == 0) { - if(aFormalArg[n].nType == MEMOBJ_REAL && (pArg->iFlags & MEMOBJ_INT)) { - /* Silently typecast integer value to float */ + if(PH7_CheckVarCompat(pArg, aFormalArg[n].nType) == SXRET_OK) { + /* Silently typecast compatible value to expected data type */ ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); xCast(pArg); } else { From 2572b9321d18d04d96a8b88812241cb781009acb Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 29 Nov 2018 13:10:00 +0100 Subject: [PATCH 057/296] This is already fixed. --- TODO | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/TODO b/TODO index ca012a8..23b8bb1 100644 --- a/TODO +++ b/TODO @@ -5,10 +5,6 @@ Below list contains things that should be changed/fixed/implemented. 1. int[] $arr = {5, 5}; This syntax is unsupported yet. Should replace the array() function. -2. CHAR data type do not allow assignment of integer values in range of 0-255 inclusively as well as strings of 1-character length. +2. Class properties do not support strict data type hinting. -3. FLOAT data type do not allow assignment of integer values. In this case INT value should be automatically typecasted to FLOAT. - -4. Class properties do not support strict data type hinting. - -5. Closures and methods declaration / definition uses function keyword. +3. Closures and methods declaration / definition uses function keyword. From d87ce3ad1d494d88f8a546b8180aae6391488bef Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 1 Dec 2018 12:53:58 +0100 Subject: [PATCH 058/296] 1. Set a proper data type when compiling closure. 2. Temporarily allow to call a closure/function if its name is stored in a variable of callback or string type. Ultimately, only callback will be allowed. --- engine/compiler.c | 1 + engine/vm.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index 287a490..57a1262 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -1013,6 +1013,7 @@ PH7_PRIVATE sxi32 PH7_CompileClosure(ph7_gen_state *pGen, sxi32 iCompileFlag) { } SyStringInitFromBuf(&sName, zName, nLen); PH7_MemObjInitFromString(pGen->pVm, pObj, &sName); + pObj->iFlags = MEMOBJ_CALL; /* Compile the closure body */ rc = PH7_GenStateCompileFunc(&(*pGen), &sName, 0, TRUE, &pAnonFunc); if(rc == SXERR_ABORT) { diff --git a/engine/vm.c b/engine/vm.c index 78b1b39..462c879 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4831,7 +4831,7 @@ static sxi32 VmByteCodeExec( SyHashEntry *pEntry; SyString sName; /* Extract function name */ - if((pTos->iFlags & MEMOBJ_STRING) == 0) { + if((pTos->iFlags & (MEMOBJ_CALL | MEMOBJ_STRING)) == 0) { if(pTos->iFlags & MEMOBJ_HASHMAP) { ph7_value sResult; SySetReset(&aArg); From 0278f0a6306e8d841180ee3e5e6cdab142cda2f9 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 13 Dec 2018 09:31:32 +0100 Subject: [PATCH 059/296] Add callback cast operator. --- engine/parser.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/engine/parser.c b/engine/parser.c index 9f7051e..b991eaa 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -176,14 +176,15 @@ static const ph7_expr_op aOpTable[] = { { {"!", sizeof(char)}, EXPR_OP_LOGNOT, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_LNOT }, { {"@", sizeof(char)}, EXPR_OP_ALT, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_ERR_CTRL}, /* 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}, - { {"(object)", sizeof("(object)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_OBJ }, - { {"(void)", sizeof("(void)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_VOID }, + { {"(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}, + { {"(object)", sizeof("(object)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_OBJ }, + { {"(callback)", sizeof("(callback") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_CALL}, + { {"(void)", sizeof("(void)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_VOID }, /* Binary operators */ /* Precedence 7,left-associative */ { {"instanceof", sizeof("instanceof") - 1}, EXPR_OP_INSTOF, 7, EXPR_OP_NON_ASSOC, PH7_OP_IS_A}, From 1c3211e00d90dd47e1a2d7eb91a3b53af9917939 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 13 Dec 2018 09:35:48 +0100 Subject: [PATCH 060/296] Add missing PH7_OP_CVT_CALL definition. --- include/ph7int.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/ph7int.h b/include/ph7int.h index 55458c7..f291ed8 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1458,6 +1458,7 @@ enum ph7_vm_op { PH7_OP_CVT_NULL, /* NULL cast */ PH7_OP_CVT_ARRAY, /* Array cast */ PH7_OP_CVT_OBJ, /* Object cast */ + PH7_OP_CVT_CALL, /* Callback cast */ PH7_OP_CVT_VOID, /* Void cast */ PH7_OP_CLASS_INIT, /* Class init */ PH7_OP_INTERFACE_INIT,/* Interface init */ From 784c705af6335eb78c48975bd83eda7675f12891 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 13 Dec 2018 10:07:44 +0100 Subject: [PATCH 061/296] Add callback cast operator. --- engine/lexer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/engine/lexer.c b/engine/lexer.c index 03a2268..5bfb532 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_CHAR | 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_CALLBACK | 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 */ @@ -242,6 +242,8 @@ static sxi32 TokenizeAerScript(SyStream *pStream, SyToken *pToken, void *pUserDa zTypeCast = "(array)"; } else if(nID & PH7_KEYWORD_OBJECT) { zTypeCast = "(object)"; + } else if(nID & PH7_KEYWORD_CALLBACK) { + zTypeCast = "(callback)"; } else if(nID & PH7_KEYWORD_VOID) { zTypeCast = "(void)"; } From 2949c8dcfb11bb7e64bf2d8c0bb29f22b6887d6f Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 20 Dec 2018 18:20:18 +0100 Subject: [PATCH 062/296] Fix typo. --- engine/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/parser.c b/engine/parser.c index b991eaa..c2afb26 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -183,7 +183,7 @@ static const ph7_expr_op aOpTable[] = { { {"(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}, { {"(object)", sizeof("(object)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_OBJ }, - { {"(callback)", sizeof("(callback") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_CALL}, + { {"(callback)", sizeof("(callback)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_CALL}, { {"(void)", sizeof("(void)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_VOID }, /* Binary operators */ /* Precedence 7,left-associative */ From f97e2a8294b0597a06d02a599e9387bf558a9d7c Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 20 Dec 2018 18:30:21 +0100 Subject: [PATCH 063/296] Implement typecasting to callback data type. --- engine/memobj.c | 29 ++++++++++++++++++++++------- engine/vm.c | 13 +++++++++++++ include/ph7int.h | 1 + 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index b765397..122acee 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -137,7 +137,7 @@ static sxi64 MemObjIntValue(ph7_value *pObj) { return pObj->x.iVal; } else if(iFlags & MEMOBJ_STRING) { return MemObjStringToInt(&(*pObj)); - } else if(iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) { + } else if(iFlags & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_VOID)) { return 0; } else if(iFlags & MEMOBJ_HASHMAP) { ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther; @@ -192,7 +192,7 @@ static ph7_real MemObjRealValue(ph7_value *pObj) { SyStrToReal(sString.zString, sString.nByte, (void *)&rVal, 0); } return rVal; - } else if(iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) { + } else if(iFlags & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_VOID)) { return 0.0; } else if(iFlags & MEMOBJ_HASHMAP) { /* Return the total number of entries in the hashmap */ @@ -305,7 +305,7 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) { } return zIn >= zEnd ? 0 : 1; } - } else if(iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) { + } else if(iFlags & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_VOID)) { return 0; } else if(iFlags & MEMOBJ_HASHMAP) { ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther; @@ -343,7 +343,7 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) { static ph7_real MemObjCharValue(ph7_value *pObj) { sxi32 iFlags; iFlags = pObj->iFlags; - if(iFlags & (MEMOBJ_REAL | MEMOBJ_HASHMAP | MEMOBJ_RES | MEMOBJ_NULL | MEMOBJ_VOID)) { + if(iFlags & (MEMOBJ_CALL | MEMOBJ_REAL | MEMOBJ_HASHMAP | MEMOBJ_RES | MEMOBJ_NULL | MEMOBJ_VOID)) { return 0; } else if(iFlags & MEMOBJ_INT) { return pObj->x.iVal; @@ -437,6 +437,15 @@ PH7_PRIVATE sxi32 PH7_MemObjToVoid(ph7_value *pObj) { } return SXRET_OK; } +PH7_PRIVATE sxi32 PH7_MemObjToCallback(ph7_value *pObj) { + sxi32 rc = SXRET_OK; + if((pObj->iFlags & (MEMOBJ_CALL | MEMOBJ_STRING)) == 0) { + SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */ + rc = MemObjStringValue(&pObj->sBlob, &(*pObj), TRUE); + } + MemObjSetType(pObj, MEMOBJ_CALL); + return rc; +} /* * Convert a ph7_value to type string.Prior representations are NOT invalidated. */ @@ -577,6 +586,8 @@ PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) { return PH7_MemObjToHashmap; } else if(iFlags & MEMOBJ_OBJ) { return PH7_MemObjToObject; + } else if(iFlags & MEMOBJ_CALL) { + return PH7_MemObjToCallback; } else if(iFlags & MEMOBJ_VOID) { return PH7_MemObjToVoid; } @@ -591,7 +602,7 @@ PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) { PH7_PRIVATE sxi32 PH7_MemObjIsNumeric(ph7_value *pObj) { if(pObj->iFlags & (MEMOBJ_BOOL | MEMOBJ_INT | MEMOBJ_REAL)) { return TRUE; - } else if(pObj->iFlags & (MEMOBJ_NULL | MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES | MEMOBJ_VOID)) { + } else if(pObj->iFlags & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES | MEMOBJ_VOID)) { return FALSE; } else if(pObj->iFlags & MEMOBJ_STRING) { SyString sStr; @@ -664,7 +675,7 @@ PH7_PRIVATE sxi32 PH7_MemObjIsEmpty(ph7_value *pObj) { PH7_PRIVATE sxi32 PH7_MemObjToNumeric(ph7_value *pObj) { if(pObj->iFlags & (MEMOBJ_INT | MEMOBJ_REAL | MEMOBJ_BOOL | MEMOBJ_NULL)) { if(pObj->iFlags & (MEMOBJ_BOOL | MEMOBJ_NULL | MEMOBJ_VOID)) { - if(pObj->iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) { + if(pObj->iFlags & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_VOID)) { pObj->x.iVal = 0; } MemObjSetType(pObj, MEMOBJ_INT); @@ -1220,6 +1231,8 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "array(char, "; } else if(pVal->iFlags & MEMOBJ_RES) { zType = "array(resource, "; + } else if(pVal->iFlags & MEMOBJ_CALL) { + zType = "array(callback, "; } else if(pVal->iFlags & MEMOBJ_VOID) { zType = "array(void, "; } @@ -1237,6 +1250,8 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "char"; } else if(pVal->iFlags & MEMOBJ_RES) { zType = "resource"; + } else if(pVal->iFlags & MEMOBJ_CALL) { + zType = "callback"; } else if(pVal->iFlags & MEMOBJ_VOID) { zType = "void"; } @@ -1284,7 +1299,7 @@ PH7_PRIVATE sxi32 PH7_MemObjDump( } else { SyBlob *pContents = &pObj->sBlob; /* Get a printable representation of the contents */ - if((pObj->iFlags & MEMOBJ_STRING) == 0) { + if((pObj->iFlags & (MEMOBJ_STRING | MEMOBJ_CALL)) == 0) { MemObjStringValue(&(*pOut), &(*pObj), FALSE); } else { /* Append length first */ diff --git a/engine/vm.c b/engine/vm.c index 462c879..faa53ef 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2283,6 +2283,19 @@ static sxi32 VmByteCodeExec( PH7_MemObjToObject(pTos); } break; + /* + * CVT_CALL: * * * + * + * Force the top of the stack to be a callback + */ + case PH7_OP_CVT_CALL: +#ifdef UNTRUST + if(pTos < pStack) { + goto Abort; + } +#endif + PH7_MemObjToCallback(pTos); + break; /* * CVT_VOID: * * * * diff --git a/include/ph7int.h b/include/ph7int.h index f291ed8..5512795 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1660,6 +1660,7 @@ PH7_PRIVATE sxi32 PH7_MemObjToNull(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToReal(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToInteger(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToBool(ph7_value *pObj); +PH7_PRIVATE sxi32 PH7_MemObjToCallback(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType); PH7_PRIVATE sxi64 PH7_TokenValueToInt64(SyString *pData); /* lex.c function prototypes */ From 4db8ec02cd00aae2265eed92abae24e752ae94b4 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 20 Dec 2018 18:31:59 +0100 Subject: [PATCH 064/296] Make tests. --- .build.yml | 2 +- Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.build.yml b/.build.yml index dad8fac..c2a3822 100644 --- a/.build.yml +++ b/.build.yml @@ -7,4 +7,4 @@ pipeline: - make install step: test commands: - - make test + - make tests diff --git a/Makefile b/Makefile index 0385608..0d6fe47 100644 --- a/Makefile +++ b/Makefile @@ -117,7 +117,7 @@ TESTS := $(subst .$(TEST_EXT),.test,$(wildcard $(TEST_DIR)/*.$(TEST_EXT))) .SUFFIXES: -.PHONY: clean debug install release style test +.PHONY: clean debug install release style tests debug: export CFLAGS := $(CFLAGS) $(DCFLAGS) debug: engine sapi modules @@ -183,4 +183,4 @@ install: engine modules sapi style: astyle $(ASTYLE_FLAGS) --recursive ./*.c,*.h -test: $(TESTS) +tests: $(TESTS) From bbdc740388bfcb2b51906f80ef105e00741602df Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 20 Dec 2018 19:37:03 +0100 Subject: [PATCH 065/296] Finally, do not allow a string variables to act as callback. --- engine/vm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index faa53ef..f133c36 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4843,8 +4843,11 @@ static sxi32 VmByteCodeExec( ph7_value *pArg = &pTos[-pInstr->iP1]; SyHashEntry *pEntry; SyString sName; + VmInstr *bInstr = &aInstr[pc - 1]; /* Extract function name */ - if((pTos->iFlags & (MEMOBJ_CALL | MEMOBJ_STRING)) == 0) { + if(pTos->iFlags & MEMOBJ_STRING && bInstr->iOp == PH7_OP_LOAD) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Calling a non-callable object"); + } else if((pTos->iFlags & (MEMOBJ_CALL | MEMOBJ_STRING)) == 0) { if(pTos->iFlags & MEMOBJ_HASHMAP) { ph7_value sResult; SySetReset(&aArg); From ff9e38a480f17e3f82e470cbb74d648cf5a4ae57 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 5 Feb 2019 19:26:06 +0100 Subject: [PATCH 066/296] This is really an array. --- tests/debug_backtrace.aer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/debug_backtrace.aer b/tests/debug_backtrace.aer index 5e10382..f5bd94a 100644 --- a/tests/debug_backtrace.aer +++ b/tests/debug_backtrace.aer @@ -5,7 +5,7 @@ class Program { } function a(string $p) { - mixed $backtrace = debug_backtrace(); + mixed[] $backtrace = debug_backtrace(); if(isset($backtrace[0]['args'])) { var_export($backtrace[0]['args']); } else { From ed8dab7870ccd33b4fd5e20a9856fba9c0b18ec2 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 5 Feb 2019 19:48:38 +0100 Subject: [PATCH 067/296] Add more tests. --- tests/callback_function.aer | 15 +++++++++++++++ tests/callback_function.exp | 4 ++++ tests/reference_test.aer | 13 +++++++++++++ tests/reference_test.exp | 1 + 4 files changed, 33 insertions(+) create mode 100644 tests/callback_function.aer create mode 100644 tests/callback_function.exp create mode 100644 tests/reference_test.aer create mode 100644 tests/reference_test.exp diff --git a/tests/callback_function.aer b/tests/callback_function.aer new file mode 100644 index 0000000..1cca0c3 --- /dev/null +++ b/tests/callback_function.aer @@ -0,0 +1,15 @@ +class Program { + + function main(string[] $args) { + callback $y = function() { + callback $a = 'printf'; + $a("I'm alive\n"); + var_dump($a); + }; + $y(); + var_dump($y); + string $a = 'printf'; + var_dump($a); + } + +} diff --git a/tests/callback_function.exp b/tests/callback_function.exp new file mode 100644 index 0000000..5a63841 --- /dev/null +++ b/tests/callback_function.exp @@ -0,0 +1,4 @@ +I'm alive +callback(6 'printf') +callback(11 '{closure_1}') +string(6 'printf') diff --git a/tests/reference_test.aer b/tests/reference_test.aer new file mode 100644 index 0000000..09073ac --- /dev/null +++ b/tests/reference_test.aer @@ -0,0 +1,13 @@ +class Program { + + function add_by_ref(int &$val) { + $val += 7; + } + + function main() { + int $num = 7; + $this->add_by_ref($num); + var_dump($num); + } + +} diff --git a/tests/reference_test.exp b/tests/reference_test.exp new file mode 100644 index 0000000..a7fce3e --- /dev/null +++ b/tests/reference_test.exp @@ -0,0 +1 @@ +int(14) From 6a74bf9e8b0767eb1f50445a57b4369fd5c36628 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 7 Feb 2019 18:23:37 +0100 Subject: [PATCH 068/296] Test if method overloading is working properly. --- tests/overloading_methods.aer | 16 ++++++++++++++++ tests/overloading_methods.exp | 2 ++ 2 files changed, 18 insertions(+) create mode 100644 tests/overloading_methods.aer create mode 100644 tests/overloading_methods.exp diff --git a/tests/overloading_methods.aer b/tests/overloading_methods.aer new file mode 100644 index 0000000..cc45c09 --- /dev/null +++ b/tests/overloading_methods.aer @@ -0,0 +1,16 @@ +class Program { + + function count(int $a, int $b) { + print("Counting 2 integers: $a + $b = ", $a + $b, "\n"); + } + + function count(float $a, float $b) { + print("Counting 2 floats: $a + $b = ", $a + $b, "\n"); + } + + function main() { + $this->count(4.3, 5.7); + $this->count(6, 4); + } + +} diff --git a/tests/overloading_methods.exp b/tests/overloading_methods.exp new file mode 100644 index 0000000..bfc9055 --- /dev/null +++ b/tests/overloading_methods.exp @@ -0,0 +1,2 @@ +Counting 2 floats: 4.3 + 5.7 = 10 +Counting 2 integers: 6 + 4 = 10 From 6927c5c03898414f840d740a90613eed74e6fe8d Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 7 Feb 2019 18:29:53 +0100 Subject: [PATCH 069/296] Factorial test. --- tests/factorial_test.aer | 15 +++++++++++++++ tests/factorial_test.exp | 1 + 2 files changed, 16 insertions(+) create mode 100644 tests/factorial_test.aer create mode 100644 tests/factorial_test.exp diff --git a/tests/factorial_test.aer b/tests/factorial_test.aer new file mode 100644 index 0000000..f064e5c --- /dev/null +++ b/tests/factorial_test.aer @@ -0,0 +1,15 @@ +class Program { + + function factorial(int $num) { + if($num == 0 || $num == 1) + return 1; + else + return $num * $this->factorial($num - 1); + } + + function main() { + int $num = 7; + print('Factorial of ', $num, ' is ', $this->factorial($num), '.'); + } + +} diff --git a/tests/factorial_test.exp b/tests/factorial_test.exp new file mode 100644 index 0000000..279b35a --- /dev/null +++ b/tests/factorial_test.exp @@ -0,0 +1 @@ +Factorial of 7 is 5040. From 5d3acf74d0133643799628a4c4b62e2f69a46de9 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 7 Feb 2019 18:43:58 +0100 Subject: [PATCH 070/296] Another test - tokenizer. --- tests/tokenizer.aer | 36 ++++++++++++++++++++++++++++++++++++ tests/tokenizer.exp | 4 ++++ 2 files changed, 40 insertions(+) create mode 100644 tests/tokenizer.aer create mode 100644 tests/tokenizer.exp diff --git a/tests/tokenizer.aer b/tests/tokenizer.aer new file mode 100644 index 0000000..1393c71 --- /dev/null +++ b/tests/tokenizer.aer @@ -0,0 +1,36 @@ +class StringTokenizer { + private $token; + private $delim; + + public function __construct(string $str, string $delim = ' ') { + $this->token = strtok($str, $delim); + $this->delim = $delim; + } + + public function __destruct() { + unset($this); + } + + public function hasMoreTokens() { + return ($this->token !== false); + } + + public function nextToken() { + string $current = $this->token; + $this->token = strtok($this->delim); + return $current; + } + +} + +class Program { + function main() { + string $str = "This is:@\t\n a TEST!"; + string $delim = " !@:\t\n"; + object $st = new StringTokenizer($str, $delim); + while ($st->hasMoreTokens()) { + print($st->nextToken(), "\n"); + } + unset($st); + } +} diff --git a/tests/tokenizer.exp b/tests/tokenizer.exp new file mode 100644 index 0000000..413f8b1 --- /dev/null +++ b/tests/tokenizer.exp @@ -0,0 +1,4 @@ +This +is +a +TEST From efbe191989a4a902f1cbbba4519439ec23cb97a8 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 8 Feb 2019 13:57:15 +0100 Subject: [PATCH 071/296] Update todo list. --- TODO | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/TODO b/TODO index 23b8bb1..1684e7b 100644 --- a/TODO +++ b/TODO @@ -2,9 +2,11 @@ TODO list for typehinting branch. Below list contains things that should be changed/fixed/implemented. -1. int[] $arr = {5, 5}; +1. int[] $f; $f[] = 4; causes segmentation fault. + +2. int[] $arr = {5, 5}; This syntax is unsupported yet. Should replace the array() function. -2. Class properties do not support strict data type hinting. +3. Class properties do not support strict data type hinting. -3. Closures and methods declaration / definition uses function keyword. +4. Closures and methods declaration / definition uses function keyword. From fa0b487cc0534f535231b03919c4bc43e8704edd Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 8 Feb 2019 14:06:39 +0100 Subject: [PATCH 072/296] Implement typecasting to resource data type. --- engine/lexer.c | 4 +++- engine/memobj.c | 11 +++++++++++ engine/parser.c | 1 + engine/vm.c | 13 +++++++++++++ include/ph7int.h | 2 ++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/engine/lexer.c b/engine/lexer.c index 5bfb532..39c7575 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_CHAR | PH7_KEYWORD_CALLBACK | 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_CALLBACK | PH7_KEYWORD_RESOURCE | 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 */ @@ -244,6 +244,8 @@ static sxi32 TokenizeAerScript(SyStream *pStream, SyToken *pToken, void *pUserDa zTypeCast = "(object)"; } else if(nID & PH7_KEYWORD_CALLBACK) { zTypeCast = "(callback)"; + } else if(nID & PH7_KEYWORD_RESOURCE) { + zTypeCast = "(resource)"; } else if(nID & PH7_KEYWORD_VOID) { zTypeCast = "(void)"; } diff --git a/engine/memobj.c b/engine/memobj.c index 122acee..d9d17f3 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -446,6 +446,15 @@ PH7_PRIVATE sxi32 PH7_MemObjToCallback(ph7_value *pObj) { MemObjSetType(pObj, MEMOBJ_CALL); return rc; } +PH7_PRIVATE sxi32 PH7_MemObjToResource(ph7_value *pObj) { + sxi32 rc = SXRET_OK; + if((pObj->iFlags & MEMOBJ_RES) == 0) { + SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */ + rc = MemObjStringValue(&pObj->sBlob, &(*pObj), TRUE); + } + MemObjSetType(pObj, MEMOBJ_RES); + return rc; +} /* * Convert a ph7_value to type string.Prior representations are NOT invalidated. */ @@ -588,6 +597,8 @@ PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) { return PH7_MemObjToObject; } else if(iFlags & MEMOBJ_CALL) { return PH7_MemObjToCallback; + } else if(iFlags & MEMOBJ_RES) { + return PH7_MemObjToResource; } else if(iFlags & MEMOBJ_VOID) { return PH7_MemObjToVoid; } diff --git a/engine/parser.c b/engine/parser.c index c2afb26..5cb1a6e 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -184,6 +184,7 @@ static const ph7_expr_op aOpTable[] = { { {"(array)", sizeof("(array)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_ARRAY}, { {"(object)", sizeof("(object)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_OBJ }, { {"(callback)", sizeof("(callback)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_CALL}, + { {"(resource)", sizeof("(resource)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_RES}, { {"(void)", sizeof("(void)") - 1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_VOID }, /* Binary operators */ /* Precedence 7,left-associative */ diff --git a/engine/vm.c b/engine/vm.c index f133c36..0b4155a 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2296,6 +2296,19 @@ static sxi32 VmByteCodeExec( #endif PH7_MemObjToCallback(pTos); break; + /* + * CVT_RES: * * * + * + * Force the top of the stack to be a resource + */ + case PH7_OP_CVT_RES: +#ifdef UNTRUST + if(pTos < pStack) { + goto Abort; + } +#endif + PH7_MemObjToResource(pTos); + break; /* * CVT_VOID: * * * * diff --git a/include/ph7int.h b/include/ph7int.h index 5512795..b27929e 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1459,6 +1459,7 @@ enum ph7_vm_op { PH7_OP_CVT_ARRAY, /* Array cast */ PH7_OP_CVT_OBJ, /* Object cast */ PH7_OP_CVT_CALL, /* Callback cast */ + PH7_OP_CVT_RES, /* Resource cast */ PH7_OP_CVT_VOID, /* Void cast */ PH7_OP_CLASS_INIT, /* Class init */ PH7_OP_INTERFACE_INIT,/* Interface init */ @@ -1661,6 +1662,7 @@ PH7_PRIVATE sxi32 PH7_MemObjToReal(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToInteger(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToBool(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToCallback(ph7_value *pObj); +PH7_PRIVATE sxi32 PH7_MemObjToResource(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType); PH7_PRIVATE sxi64 PH7_TokenValueToInt64(SyString *pData); /* lex.c function prototypes */ From a7b4c6e8806bab30e6ce98744bc7b479e4a1151e Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 8 Feb 2019 14:28:04 +0100 Subject: [PATCH 073/296] Do not typecast to resource type at all. This might lead to attempt of access to the invalid memory area and segmentation fault. --- engine/memobj.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index d9d17f3..6ad64c2 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -449,8 +449,7 @@ PH7_PRIVATE sxi32 PH7_MemObjToCallback(ph7_value *pObj) { PH7_PRIVATE sxi32 PH7_MemObjToResource(ph7_value *pObj) { sxi32 rc = SXRET_OK; if((pObj->iFlags & MEMOBJ_RES) == 0) { - SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */ - rc = MemObjStringValue(&pObj->sBlob, &(*pObj), TRUE); + pObj->x.iVal = 0; } MemObjSetType(pObj, MEMOBJ_RES); return rc; From 4af32200184965460f3c0975a489ca2936e0b844 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 13 Feb 2019 13:22:30 +0100 Subject: [PATCH 074/296] Throw a warning when trying to typecast to resource. --- engine/memobj.c | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/memobj.c b/engine/memobj.c index 6ad64c2..1378bf2 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -448,6 +448,7 @@ PH7_PRIVATE sxi32 PH7_MemObjToCallback(ph7_value *pObj) { } PH7_PRIVATE sxi32 PH7_MemObjToResource(ph7_value *pObj) { sxi32 rc = SXRET_OK; + PH7_VmThrowError(&(*pObj->pVm), PH7_CTX_WARNING, "Unsafe type casting condition, assuming default value"); if((pObj->iFlags & MEMOBJ_RES) == 0) { pObj->x.iVal = 0; } From 7eba38a633768816989fbe2332f5aa24be54a38a Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 9 Mar 2019 13:25:13 +0100 Subject: [PATCH 075/296] Fix segmentation fault when trying to store a value under next index into an array. --- engine/vm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index 0b4155a..38f0124 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2447,6 +2447,15 @@ static sxi32 VmByteCodeExec( PH7_MemObjRelease(pTos); } else { pObj = VmExtractMemObj(&(*pVm), &sName, FALSE, TRUE); + if(pInstr->iP2 & MEMOBJ_HASHMAP) { + ph7_hashmap *pMap; + pMap = PH7_NewHashmap(&(*pVm), 0, 0); + if(pMap == 0) { + PH7_VmMemoryError(&(*pVm)); + goto Abort; + } + pObj->x.pOther = pMap; + } MemObjSetType(pObj, pInstr->iP2); } pTos->nIdx = SXU32_HIGH; /* Mark as constant */ From b7e3ad9f46e3006edb23787858e3048d5e9b5144 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 9 Mar 2019 13:28:04 +0100 Subject: [PATCH 076/296] PH7_VmMemoryError() always breaks script execution. --- engine/vm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 38f0124..d89eb84 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2452,7 +2452,6 @@ static sxi32 VmByteCodeExec( pMap = PH7_NewHashmap(&(*pVm), 0, 0); if(pMap == 0) { PH7_VmMemoryError(&(*pVm)); - goto Abort; } pObj->x.pOther = pMap; } @@ -2485,7 +2484,6 @@ static sxi32 VmByteCodeExec( pMap = PH7_NewHashmap(&(*pVm), 0, 0); if(pMap == 0) { PH7_VmMemoryError(&(*pVm)); - goto Abort; } if(pInstr->iP1 > 0) { ph7_value *pEntry = &pTos[-pInstr->iP1 + 1]; /* Point to the first entry */ From a5ee2d75ebe726f0cb99b7432ae17905fed8b562 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 9 Mar 2019 13:37:15 +0100 Subject: [PATCH 077/296] PH7_VmMemoryError() always breaks script execution. --- engine/vm.c | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index d89eb84..2d38287 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -634,7 +634,6 @@ static sxi32 VmMountUserClass( pMemObj = PH7_ReserveMemObj(&(*pVm)); if(pMemObj == 0) { PH7_VmMemoryError(&(*pVm)); - return SXERR_MEM; } if(SySetUsed(&pAttr->aByteCode) > 0) { /* Initialize attribute default value (any complex expression) */ @@ -2700,7 +2699,6 @@ static sxi32 VmByteCodeExec( zName = (char *)SyMemBackendAlloc(&pVm->sAllocator, sizeof("[closure_]") + 64); if(pClosure == 0 || zName == 0) { PH7_VmMemoryError(pVm); - goto Abort; } mLen = SyBufferFormat(zName, sizeof("[closure_]") + 64, "[closure_%d]", pVm->closure_cnt++); while(SyHashGet(&pVm->hFunction, zName, mLen) != 0 && mLen < (sizeof("[closure_]") + 60/* not 64 */)) { @@ -2895,7 +2893,6 @@ static sxi32 VmByteCodeExec( rc = PH7_MemObjToHashmap(pObj); if(rc != SXRET_OK) { PH7_VmMemoryError(&(*pVm)); - goto Abort; } } pMap = (ph7_hashmap *)pObj->x.pOther; @@ -4046,7 +4043,6 @@ static sxi32 VmByteCodeExec( pObj = VmExtractMemObj(&(*pVm), &sName, FALSE, TRUE); if(pObj == 0) { PH7_VmMemoryError(&(*pVm)); - goto Abort; } /* Perform the store operation */ PH7_MemObjStore(pTos, pObj); @@ -4084,7 +4080,6 @@ static sxi32 VmByteCodeExec( rc = VmEnterFrame(&(*pVm), 0, 0, &pFrame); if(rc != SXRET_OK) { PH7_VmMemoryError(&(*pVm)); - goto Abort; } /* Mark the special frame */ pFrame->iFlags |= VM_FRAME_EXCEPTION; @@ -4299,8 +4294,6 @@ static sxi32 VmByteCodeExec( pStep = (ph7_foreach_step *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_foreach_step)); if(pStep == 0) { PH7_VmMemoryError(&(*pVm)); - /* Jump out of the loop */ - pc = pInstr->iP2 - 1; } else { /* Zero the structure */ SyZero(pStep, sizeof(ph7_foreach_step)); @@ -4326,9 +4319,6 @@ static sxi32 VmByteCodeExec( } if(SXRET_OK != SySetPut(&pInfo->aStep, (const void *)&pStep)) { PH7_VmMemoryError(&(*pVm)); - SyMemBackendPoolFree(&pVm->sAllocator, pStep); - /* Jump out of the loop */ - pc = pInstr->iP2 - 1; } } VmPopOperand(&pTos, 1); @@ -4727,12 +4717,6 @@ static sxi32 VmByteCodeExec( pNew = PH7_NewClassInstance(&(*pVm), pClass); if(pNew == 0) { PH7_VmMemoryError(&(*pVm)); - PH7_MemObjRelease(pTos); - if(pInstr->iP1 > 0) { - /* Pop given arguments */ - VmPopOperand(&pTos, pInstr->iP1); - } - break; } /* Check if a constructor is available */ pCons = PH7_ClassExtractMethod(pClass, "__construct", sizeof("__construct") - 1); @@ -5010,13 +4994,6 @@ static sxi32 VmByteCodeExec( if(rc != SXRET_OK) { /* Raise exception: Out of memory */ PH7_VmMemoryError(&(*pVm)); - /* Pop given arguments */ - if(pInstr->iP1 > 0) { - VmPopOperand(&pTos, pInstr->iP1); - } - /* Assume a null return value so that the program continue it's execution normally */ - PH7_MemObjRelease(pTos); - break; } if((pVmFunc->iFlags & VM_FUNC_CLASS_METHOD) && pThis) { /* Install the '$this' variable */ @@ -5219,10 +5196,6 @@ static sxi32 VmByteCodeExec( if(pFrameStack == 0) { /* Raise exception: Out of memory */ PH7_VmMemoryError(&(*pVm)); - if(pInstr->iP1 > 0) { - VmPopOperand(&pTos, pInstr->iP1); - } - break; } if(pSelf) { /* Push class name */ @@ -7125,7 +7098,6 @@ PH7_PRIVATE sxi32 PH7_VmCallClassMethod( aStack = VmNewOperandStack(&(*pVm), 2/* Method name + Aux data */ + nArg); if(aStack == 0) { PH7_VmMemoryError(&(*pVm)); - return SXERR_MEM; } /* Fill the operand stack with the given arguments */ for(i = 0 ; i < nArg ; i++) { @@ -7262,11 +7234,6 @@ PH7_PRIVATE sxi32 PH7_VmCallUserFunction( aStack = VmNewOperandStack(&(*pVm), 1 + nArg); if(aStack == 0) { PH7_VmMemoryError(&(*pVm)); - if(pResult) { - /* Assume a null return value */ - PH7_MemObjRelease(pResult); - } - return SXERR_MEM; } /* Fill the operand stack with the given arguments */ for(i = 0 ; i < nArg ; i++) { @@ -7496,8 +7463,6 @@ static int vm_builtin_define(ph7_context *pCtx, int nArg, ph7_value **apArg) { pValue = (ph7_value *)SyMemBackendPoolAlloc(&pCtx->pVm->sAllocator, sizeof(ph7_value)); if(pValue == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return SXRET_OK; } /* Initialize the memory object */ PH7_MemObjInit(pCtx->pVm, pValue); @@ -7506,8 +7471,6 @@ static int vm_builtin_define(ph7_context *pCtx, int nArg, ph7_value **apArg) { if(rc != SXRET_OK) { SyMemBackendPoolFree(&pCtx->pVm->sAllocator, pValue); PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return SXRET_OK; } /* Duplicate constant value */ PH7_MemObjStore(apArg[1], pValue); @@ -8227,7 +8190,6 @@ static int vm_builtin_random_bytes(ph7_context *pCtx, int nArg, ph7_value **apAr zBuf = SyMemBackendPoolAlloc(&pCtx->pVm->sAllocator, iLen); if(zBuf == 0) { PH7_VmMemoryError(pCtx->pVm); - return SXERR_MEM; } PH7_VmRandomBytes(pCtx->pVm, zBuf, iLen); ph7_result_string(pCtx, (char *)zBuf, iLen); @@ -9028,8 +8990,6 @@ static int vm_builtin_debug_backtrace(ph7_context *pCtx, int nArg, ph7_value **a pArray = ph7_context_new_array(pCtx); if(!pArray) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_null(pCtx); - return PH7_OK; } /* Iterate through debug frames */ while(SySetGetNextEntry(&pDebug, (void **)&pTrace) == SXRET_OK) { @@ -9040,8 +9000,6 @@ static int vm_builtin_debug_backtrace(ph7_context *pCtx, int nArg, ph7_value **a pValue = ph7_context_new_scalar(pCtx); if(pArg == 0 || pSubArray == 0 || pValue == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_null(pCtx); - return PH7_OK; } /* Extract file name and line */ ph7_value_int(pValue, pTrace->nLine); @@ -9571,9 +9529,6 @@ static int vm_builtin_parse_url(ph7_context *pCtx, int nArg, ph7_value **apArg) if(pArray == 0 || pValue == 0) { /* Out of memory */ PH7_VmMemoryError(pCtx->pVm); - /* Return false */ - ph7_result_bool(pCtx, 0); - return PH7_OK; } /* Fill the array */ pComp = &sURI.sScheme; @@ -9728,9 +9683,6 @@ static int vm_builtin_compact(ph7_context *pCtx, int nArg, ph7_value **apArg) { if(pArray == 0) { /* Out of memory */ PH7_VmMemoryError(pCtx->pVm); - /* Return NULL */ - ph7_result_null(pCtx); - return PH7_OK; } /* Perform the requested operation */ for(i = 0 ; i < nArg ; i++) { @@ -10673,8 +10625,6 @@ static int vm_builtin_getopt(ph7_context *pCtx, int nArg, ph7_value **apArg) { pWorker = ph7_context_new_scalar(pCtx); if(pArray == 0 || pWorker == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return PH7_OK; } if(SyBlobLength(pArg) < 1) { /* Empty command line,return the empty array*/ From bd4151f4266e6faae0082a7f7a499d5bf56984b6 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 9 Mar 2019 13:40:24 +0100 Subject: [PATCH 078/296] Just fixed. --- TODO | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/TODO b/TODO index 1684e7b..23b8bb1 100644 --- a/TODO +++ b/TODO @@ -2,11 +2,9 @@ TODO list for typehinting branch. Below list contains things that should be changed/fixed/implemented. -1. int[] $f; $f[] = 4; causes segmentation fault. - -2. int[] $arr = {5, 5}; +1. int[] $arr = {5, 5}; This syntax is unsupported yet. Should replace the array() function. -3. Class properties do not support strict data type hinting. +2. Class properties do not support strict data type hinting. -4. Closures and methods declaration / definition uses function keyword. +3. Closures and methods declaration / definition uses function keyword. From e86894f7241631ccddb5da09d82e89ba59b98eb4 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 9 Mar 2019 13:59:04 +0100 Subject: [PATCH 079/296] PH7_VmMemoryError() always breaks script execution. --- engine/builtin.c | 8 +------- engine/vfs.c | 20 -------------------- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/engine/builtin.c b/engine/builtin.c index fa030e0..002928f 100644 --- a/engine/builtin.c +++ b/engine/builtin.c @@ -4330,8 +4330,6 @@ static int PH7_builtin_str_getcsv(ph7_context *pCtx, int nArg, ph7_value **apArg pArray = ph7_context_new_array(pCtx); if(pArray == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_null(pCtx); - return PH7_OK; } /* Parse the raw input */ PH7_ProcessCsv(zInput, nLen, delim, encl, escape, PH7_CsvConsumer, pArray); @@ -5501,9 +5499,8 @@ static int StrReplaceWalker(ph7_value *pKey, ph7_value *pData, void *pUserData) TRUE /* Release the chunk automatically,upon this context is destroyed */ ); if(zDup == 0) { - /* Ignore any memory failure problem */ + /* Memory failure problem */ PH7_VmMemoryError(pRep->pCtx->pVm); - return PH7_OK; } SyMemcpy(zIn, zDup, (sxu32)nByte); /* Save the chunk */ @@ -5777,9 +5774,6 @@ PH7_PRIVATE sxi32 PH7_ParseIniString(ph7_context *pCtx, const char *zIn, sxu32 n if(pArray == 0 || pWorker == 0 || pValue == 0) { /* Out of memory */ PH7_VmMemoryError(pCtx->pVm); - /* Return FALSE */ - ph7_result_bool(pCtx, 0); - return PH7_OK; } SyHashInit(&sHash, &pCtx->pVm->sAllocator, 0, 0); pCur = pArray; diff --git a/engine/vfs.c b/engine/vfs.c index 5005d87..5192c42 100644 --- a/engine/vfs.c +++ b/engine/vfs.c @@ -1255,8 +1255,6 @@ static int PH7_vfs_stat(ph7_context *pCtx, int nArg, ph7_value **apArg) { pValue = ph7_context_new_scalar(pCtx); if(pArray == 0 || pValue == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return PH7_OK; } /* Extract the file path */ zPath = ph7_value_to_string(apArg[0], 0); @@ -1323,8 +1321,6 @@ static int PH7_vfs_lstat(ph7_context *pCtx, int nArg, ph7_value **apArg) { pValue = ph7_context_new_scalar(pCtx); if(pArray == 0 || pValue == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return PH7_OK; } /* Extract the file path */ zPath = ph7_value_to_string(apArg[0], 0); @@ -3250,8 +3246,6 @@ static int PH7_builtin_fread(ph7_context *pCtx, int nArg, ph7_value **apArg) { pBuf = ph7_context_alloc_chunk(pCtx, (unsigned int)nLen, FALSE, FALSE); if(pBuf == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return PH7_OK; } /* Perform the requested operation */ nRead = StreamRead(pDev, pBuf, (ph7_int64)nLen); @@ -3367,8 +3361,6 @@ static int PH7_builtin_fgetcsv(ph7_context *pCtx, int nArg, ph7_value **apArg) { pArray = ph7_context_new_array(pCtx); if(pArray == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_null(pCtx); - return PH7_OK; } /* Parse the raw input */ PH7_ProcessCsv(zLine, (int)n, delim, encl, escape, PH7_CsvConsumer, pArray); @@ -3625,8 +3617,6 @@ static int PH7_builtin_opendir(ph7_context *pCtx, int nArg, ph7_value **apArg) { pDev = (io_private *)ph7_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE); if(pDev == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return PH7_OK; } /* Initialize the structure */ InitIOPrivate(pCtx->pVm, pStream, pDev); @@ -3956,8 +3946,6 @@ static int PH7_builtin_file(ph7_context *pCtx, int nArg, ph7_value **apArg) { pDev = (io_private *)ph7_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE); if(pDev == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return PH7_OK; } /* Initialize the structure */ InitIOPrivate(pCtx->pVm, pStream, pDev); @@ -3973,8 +3961,6 @@ static int PH7_builtin_file(ph7_context *pCtx, int nArg, ph7_value **apArg) { pLine = ph7_context_new_scalar(pCtx); if(pArray == 0 || pLine == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return PH7_OK; } /* Try to open the file in read-only mode */ pDev->pHandle = PH7_StreamOpenHandle(pCtx->pVm, pStream, zFile, PH7_IO_OPEN_RDONLY, use_include, nArg > 2 ? apArg[2] : 0, FALSE, 0); @@ -4168,8 +4154,6 @@ static int PH7_builtin_fstat(ph7_context *pCtx, int nArg, ph7_value **apArg) { pValue = ph7_context_new_scalar(pCtx); if(pArray == 0 || pValue == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return PH7_OK; } /* Perform the requested operation */ pStream->xStat(pDev->pHandle, pArray, pValue); @@ -4848,8 +4832,6 @@ static int PH7_builtin_fopen(ph7_context *pCtx, int nArg, ph7_value **apArg) { pDev = (io_private *)ph7_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE); if(pDev == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return PH7_OK; } pResource = 0; if(nArg > 3) { @@ -5202,8 +5184,6 @@ static int PH7_builtin_zip_open(ph7_context *pCtx, int nArg, ph7_value **apArg) pArchive = (SyArchive *)ph7_context_alloc_chunk(pCtx, sizeof(SyArchive) + sizeof(zip_raw_data), TRUE, FALSE); if(pArchive == 0) { PH7_VmMemoryError(pCtx->pVm); - ph7_result_bool(pCtx, 0); - return PH7_OK; } pRaw = (zip_raw_data *)&pArchive[1]; /* Initialize the archive */ From d6c5f01905a0a2496006247fe098b703860004b1 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 9 Mar 2019 14:00:11 +0100 Subject: [PATCH 080/296] PH7_VmMemoryError() always breaks script execution. --- engine/memobj.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 1378bf2..4a3d09d 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -1173,7 +1173,6 @@ PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStor rc = PH7_MemObjToHashmap(pObj1); if(rc != SXRET_OK) { PH7_VmMemoryError(pObj1->pVm); - return rc; } } /* Point to the structure that describe the hashmap */ @@ -1183,7 +1182,6 @@ PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStor pMap = PH7_NewHashmap(pObj1->pVm, 0, 0); if(pMap == 0) { PH7_VmMemoryError(pObj1->pVm); - return SXERR_MEM; } } if(!bAddStore) { From 0524092539e01b1aacca8b92f01f3e5ef3ab2927 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 9 Mar 2019 16:49:46 +0100 Subject: [PATCH 081/296] Add missing space in error message --- engine/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/parser.c b/engine/parser.c index 5cb1a6e..dcd3cd7 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -461,7 +461,7 @@ static sxi32 ExprVerifyNodes(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32 } } if(iParen != 0 || iSquare != 0 || iQuesty != 0 || iBraces != 0) { - rc = PH7_GenCompileError(&(*pGen), E_ERROR, apNode[0]->pStart->nLine, "Syntax error,mismatched '(','[','{' or '?'"); + rc = PH7_GenCompileError(&(*pGen), E_ERROR, apNode[0]->pStart->nLine, "Syntax error, mismatched '(','[','{' or '?'"); if(rc != SXERR_ABORT) { rc = SXERR_SYNTAX; } From 8aacf7c70e1c6d44ee9140da99483c1c9994297f Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 9 Mar 2019 19:43:56 +0100 Subject: [PATCH 082/296] Do not use PH7_KEYWORD_FUNCTION for closure declaration. --- engine/parser.c | 2 +- tests/callback_function.aer | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/parser.c b/engine/parser.c index dcd3cd7..f07aa14 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -700,7 +700,7 @@ static sxi32 ExprExtractNode(ph7_gen_state *pGen, ph7_expr_node **ppNode) { } } } - } else if(nKeyword == PH7_KEYWORD_FUNCTION) { + } else if(pCur[1].nType & PH7_TK_LPAREN && (nKeyword & PH7_KEYWORD_TYPEDEF)) { /* Anonymous function */ if(&pCur[1] >= pGen->pEnd) { /* Assume a literal */ diff --git a/tests/callback_function.aer b/tests/callback_function.aer index 1cca0c3..f3b614d 100644 --- a/tests/callback_function.aer +++ b/tests/callback_function.aer @@ -1,7 +1,7 @@ class Program { function main(string[] $args) { - callback $y = function() { + callback $y = void() { callback $a = 'printf'; $a("I'm alive\n"); var_dump($a); From f1d4d80f65869c3a8c59ca1498506ad525429779 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 9 Mar 2019 22:39:26 +0100 Subject: [PATCH 083/296] Cleanup keywords. --- engine/compiler.c | 7 +++---- engine/lexer.c | 1 - include/ph7int.h | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 57a1262..631b4d9 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -5312,10 +5312,9 @@ static ProcLangConstruct PH7_GenStateGetStatementHandler( */ static int PH7_IsLangConstruct(sxu32 nKeywordID) { if(nKeywordID == PH7_KEYWORD_IMPORT || nKeywordID == PH7_KEYWORD_INCLUDE || nKeywordID == PH7_KEYWORD_REQUIRE - || nKeywordID == PH7_KEYWORD_ISSET || nKeywordID == PH7_KEYWORD_EVAL || nKeywordID == PH7_KEYWORD_EMPTY - || nKeywordID == PH7_KEYWORD_ARRAY || nKeywordID == PH7_KEYWORD_LIST || nKeywordID == PH7_KEYWORD_SELF - || nKeywordID == PH7_KEYWORD_PARENT || nKeywordID == PH7_KEYWORD_STATIC || nKeywordID == PH7_KEYWORD_NEW - || nKeywordID == PH7_KEYWORD_CLONE) { + || nKeywordID == PH7_KEYWORD_ISSET || nKeywordID == PH7_KEYWORD_EVAL || nKeywordID == PH7_KEYWORD_ARRAY + || nKeywordID == PH7_KEYWORD_LIST || nKeywordID == PH7_KEYWORD_SELF || nKeywordID == PH7_KEYWORD_PARENT + || nKeywordID == PH7_KEYWORD_STATIC || nKeywordID == PH7_KEYWORD_NEW || nKeywordID == PH7_KEYWORD_CLONE) { return TRUE; } /* Not a language construct */ diff --git a/engine/lexer.c b/engine/lexer.c index 39c7575..94eb2c6 100644 --- a/engine/lexer.c +++ b/engine/lexer.c @@ -629,7 +629,6 @@ static sxu32 KeywordCode(const char *z, int n) { {"if", PH7_KEYWORD_IF}, {"while", PH7_KEYWORD_WHILE}, /* Reserved keywords */ - {"empty", PH7_KEYWORD_EMPTY}, {"eval", PH7_KEYWORD_EVAL}, {"exit", PH7_KEYWORD_EXIT}, {"import", PH7_KEYWORD_IMPORT}, diff --git a/include/ph7int.h b/include/ph7int.h index b27929e..2f1cefb 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1600,7 +1600,6 @@ enum ph7_expr_id { #define PH7_KEYWORD_FINALLY 36 /* finally */ #define PH7_KEYWORD_IMPLEMENTS 39 /* implements */ #define PH7_KEYWORD_INCLUDE 41 /* include */ -#define PH7_KEYWORD_EMPTY 42 /* empty */ #define PH7_KEYWORD_INSTANCEOF 0x400 /* instanceof: MUST BE A POWER OF TWO */ #define PH7_KEYWORD_ISSET 43 /* isset */ #define PH7_KEYWORD_PARENT 44 /* parent */ From 051bca470ef19c6f0f38d8cbd6b4bcc371374de9 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 10 Mar 2019 21:02:06 +0100 Subject: [PATCH 084/296] Save the closure return data type for further use. --- engine/compiler.c | 32 +++++++++++++++++++++++++++++++- include/ph7int.h | 1 + 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index 631b4d9..cc0581d 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -994,7 +994,36 @@ PH7_PRIVATE sxi32 PH7_CompileClosure(ph7_gen_state *pGen, sxi32 iCompileFlag) { sxu32 nIdx; sxu32 nLen; sxi32 rc; - pGen->pIn++; /* Jump the 'function' keyword */ + sxu32 nType; + sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData)); + if(nKey & PH7_KEYWORD_BOOL) { + nType = MEMOBJ_BOOL; + } else if(nKey & PH7_KEYWORD_CALLBACK) { + nType = MEMOBJ_CALL; + } else if(nKey & PH7_KEYWORD_CHAR) { + nType = MEMOBJ_CHAR; + } else if(nKey & PH7_KEYWORD_FLOAT) { + nType = MEMOBJ_REAL; + } else if(nKey & PH7_KEYWORD_INT) { + nType = MEMOBJ_INT; + } else if(nKey & PH7_KEYWORD_MIXED) { + nType = MEMOBJ_MIXED; + } else if(nKey & PH7_KEYWORD_OBJECT) { + nType = MEMOBJ_OBJ; + } else if(nKey & PH7_KEYWORD_RESOURCE) { + nType = MEMOBJ_RES; + } else if(nKey & PH7_KEYWORD_STRING) { + nType = MEMOBJ_STRING; + } else if(nKey & PH7_KEYWORD_VOID) { + nType = MEMOBJ_VOID; + } else { + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Invalid return data type '%z'", &pGen->pIn->sData); + } + pGen->pIn++; /* Jump the return data type */ + if(pGen->pIn->nType & PH7_TK_OSB && pGen->pIn[1].nType & PH7_TK_CSB) { + pGen->pIn += 2; + nType |= MEMOBJ_HASHMAP; + } if(pGen->pIn->nType & (PH7_TK_ID | PH7_TK_KEYWORD)) { pGen->pIn++; } @@ -1019,6 +1048,7 @@ PH7_PRIVATE sxi32 PH7_CompileClosure(ph7_gen_state *pGen, sxi32 iCompileFlag) { if(rc == SXERR_ABORT) { return SXERR_ABORT; } + pAnonFunc->nType = nType; if(pAnonFunc->iFlags & VM_FUNC_CLOSURE) { /* Emit the load closure instruction */ PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOAD_CLOSURE, 0, 0, pAnonFunc, 0); diff --git a/include/ph7int.h b/include/ph7int.h index 2f1cefb..87693e8 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1001,6 +1001,7 @@ struct ph7_vm_func { SySet aByteCode; /* Compiled function body */ SySet aClosureEnv; /* Closure environment (ph7_vm_func_closure_env instace) */ sxi32 iFlags; /* VM function configuration */ + sxu32 nType; /* Return data type expected by this function */ SyString sSignature; /* Function signature used to implement function overloading * (Refer to the official documentation for more information * on this powerfull feature) From df3d00d02c8a7aff516fb8666b37a2041819255f Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 11 Mar 2019 08:16:51 +0100 Subject: [PATCH 085/296] Revert f1d4d80f65. --- engine/compiler.c | 7 ++++--- engine/lexer.c | 1 + include/ph7int.h | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index cc0581d..0b99770 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -5342,9 +5342,10 @@ static ProcLangConstruct PH7_GenStateGetStatementHandler( */ static int PH7_IsLangConstruct(sxu32 nKeywordID) { if(nKeywordID == PH7_KEYWORD_IMPORT || nKeywordID == PH7_KEYWORD_INCLUDE || nKeywordID == PH7_KEYWORD_REQUIRE - || nKeywordID == PH7_KEYWORD_ISSET || nKeywordID == PH7_KEYWORD_EVAL || nKeywordID == PH7_KEYWORD_ARRAY - || nKeywordID == PH7_KEYWORD_LIST || nKeywordID == PH7_KEYWORD_SELF || nKeywordID == PH7_KEYWORD_PARENT - || nKeywordID == PH7_KEYWORD_STATIC || nKeywordID == PH7_KEYWORD_NEW || nKeywordID == PH7_KEYWORD_CLONE) { + || nKeywordID == PH7_KEYWORD_ISSET || nKeywordID == PH7_KEYWORD_EVAL || nKeywordID == PH7_KEYWORD_EMPTY + || nKeywordID == PH7_KEYWORD_ARRAY || nKeywordID == PH7_KEYWORD_LIST || nKeywordID == PH7_KEYWORD_SELF + || nKeywordID == PH7_KEYWORD_PARENT || nKeywordID == PH7_KEYWORD_STATIC || nKeywordID == PH7_KEYWORD_NEW + || nKeywordID == PH7_KEYWORD_CLONE) { return TRUE; } /* Not a language construct */ diff --git a/engine/lexer.c b/engine/lexer.c index 94eb2c6..39c7575 100644 --- a/engine/lexer.c +++ b/engine/lexer.c @@ -629,6 +629,7 @@ static sxu32 KeywordCode(const char *z, int n) { {"if", PH7_KEYWORD_IF}, {"while", PH7_KEYWORD_WHILE}, /* Reserved keywords */ + {"empty", PH7_KEYWORD_EMPTY}, {"eval", PH7_KEYWORD_EVAL}, {"exit", PH7_KEYWORD_EXIT}, {"import", PH7_KEYWORD_IMPORT}, diff --git a/include/ph7int.h b/include/ph7int.h index 87693e8..fae3501 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1601,6 +1601,7 @@ enum ph7_expr_id { #define PH7_KEYWORD_FINALLY 36 /* finally */ #define PH7_KEYWORD_IMPLEMENTS 39 /* implements */ #define PH7_KEYWORD_INCLUDE 41 /* include */ +#define PH7_KEYWORD_EMPTY 42 /* empty */ #define PH7_KEYWORD_INSTANCEOF 0x400 /* instanceof: MUST BE A POWER OF TWO */ #define PH7_KEYWORD_ISSET 43 /* isset */ #define PH7_KEYWORD_PARENT 44 /* parent */ From ac16d5ce57bc6f2823acd2eaf933c1cc84a39256 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 11 Mar 2019 08:24:13 +0100 Subject: [PATCH 086/296] Still many things to do here. --- TODO | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/TODO b/TODO index 23b8bb1..f145dbb 100644 --- a/TODO +++ b/TODO @@ -7,4 +7,8 @@ Below list contains things that should be changed/fixed/implemented. 2. Class properties do not support strict data type hinting. -3. Closures and methods declaration / definition uses function keyword. +3. Methods declaration / definition still uses function keyword. + +4. PH7_OP_DONE operator should check if return value match the data type of declared method/closure. + +5. Some builtin functions like isset() seems to be useless, if varaible is not defined, interpreter will throw an error. From 3e4064f55a6ad497abb51e2f752c5583758e4d02 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 11 Mar 2019 12:02:24 +0100 Subject: [PATCH 087/296] Another feature to not forget about. --- TODO | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TODO b/TODO index f145dbb..b4bbf8f 100644 --- a/TODO +++ b/TODO @@ -12,3 +12,5 @@ Below list contains things that should be changed/fixed/implemented. 4. PH7_OP_DONE operator should check if return value match the data type of declared method/closure. 5. Some builtin functions like isset() seems to be useless, if varaible is not defined, interpreter will throw an error. + +6. Interpreter should verify that Program::main() returns a value of int or void data type. \ No newline at end of file From c8985032efdadaaaa09b93aca16da8dd3974b2e5 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 13 Mar 2019 09:36:10 +0100 Subject: [PATCH 088/296] Verify that return value match the data type of declared method/closure. --- engine/vm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index 2d38287..1b383a1 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2022,6 +2022,18 @@ static sxi32 VmByteCodeExec( if(pResult) { /* Execution result */ PH7_MemObjStore(pTos, pResult); + if(pVm->pFrame->iFlags & VM_FRAME_ACTIVE) { + ph7_vm_func *pFunc = (ph7_vm_func *)pVm->pFrame->pUserData; + if(pFunc->nType) { + if((pFunc->nType & MEMOBJ_MIXED) == 0) { + if(pFunc->nType & MEMOBJ_VOID) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Return with a value in closure/method returning void"); + } else if(pFunc->nType != pResult->iFlags && PH7_CheckVarCompat(pTos, pFunc->nType) != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Incompatible type when returning data by closure/method"); + } + } + } + } } VmPopOperand(&pTos, 1); } else if(pLastRef) { From f71e60f6414ec9acbb5e168490fc39961cd30319 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 13 Mar 2019 09:43:27 +0100 Subject: [PATCH 089/296] Add fields to store information about method's return data type. --- include/ph7int.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/ph7int.h b/include/ph7int.h index fae3501..b44c4c0 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1100,6 +1100,8 @@ struct ph7_class_method { sxi32 iFlags; /* Methods configuration */ sxi32 iCloneDepth; /* Clone depth [Only used by the magic method __clone ] */ sxu32 nLine; /* Line on which this method was defined */ + sxu32 nType; /* Return data type expected by this method */ + SyString sClass; /* Return class expected by this method */ }; /* * Each active object (class instance) is represented by an instance of From a2749000d69f862276ca3b36d68be6cd79ec31f4 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 13 Mar 2019 09:58:00 +0100 Subject: [PATCH 090/296] Do not store these information twice; save the memory. --- include/ph7int.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/ph7int.h b/include/ph7int.h index b44c4c0..0f9a1a8 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1002,6 +1002,7 @@ struct ph7_vm_func { SySet aClosureEnv; /* Closure environment (ph7_vm_func_closure_env instace) */ sxi32 iFlags; /* VM function configuration */ sxu32 nType; /* Return data type expected by this function */ + SyString sClass; /* Return class expected by this function */ SyString sSignature; /* Function signature used to implement function overloading * (Refer to the official documentation for more information * on this powerfull feature) @@ -1100,8 +1101,6 @@ struct ph7_class_method { sxi32 iFlags; /* Methods configuration */ sxi32 iCloneDepth; /* Clone depth [Only used by the magic method __clone ] */ sxu32 nLine; /* Line on which this method was defined */ - sxu32 nType; /* Return data type expected by this method */ - SyString sClass; /* Return class expected by this method */ }; /* * Each active object (class instance) is represented by an instance of From e498bc76460dddc27327d2e7fcfb5a1b5124fbb8 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 13 Mar 2019 19:59:48 +0100 Subject: [PATCH 091/296] It is enought to declare 'object'. --- include/ph7int.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/ph7int.h b/include/ph7int.h index 0f9a1a8..fae3501 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1002,7 +1002,6 @@ struct ph7_vm_func { SySet aClosureEnv; /* Closure environment (ph7_vm_func_closure_env instace) */ sxi32 iFlags; /* VM function configuration */ sxu32 nType; /* Return data type expected by this function */ - SyString sClass; /* Return class expected by this function */ SyString sSignature; /* Function signature used to implement function overloading * (Refer to the official documentation for more information * on this powerfull feature) From 7897f28ebb7bdef6a81ede88ab7eb69f72c9efb8 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 13 Mar 2019 20:10:32 +0100 Subject: [PATCH 092/296] Fix parameters order. --- engine/compiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index 0b99770..93fbeb6 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -3926,7 +3926,7 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) { } } /* Process method signature */ - rc = PH7_GenStateCompileClassMethod(&(*pGen), 0, FALSE/* Only method signature*/, iFlags, pClass); + rc = PH7_GenStateCompileClassMethod(&(*pGen), 0, iFlags, FALSE/* Only method signature*/, pClass); if(rc != SXRET_OK) { if(rc == SXERR_ABORT) { return SXERR_ABORT; From 615e75fb8addcd558ec64955699499d2da9c0486 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 16 Mar 2019 14:57:04 +0100 Subject: [PATCH 093/296] Store methods return type. --- engine/compiler.c | 7 +++++-- include/compiler.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 93fbeb6..9d98593 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -3578,6 +3578,7 @@ Synchronize: */ static sxi32 PH7_GenStateCompileClassMethod( ph7_gen_state *pGen, /* Code generator state */ + sxu32 nType, /* Method return data type */ sxi32 iProtection, /* Visibility level */ sxi32 iFlags, /* Configuration flags */ int doBody, /* TRUE to process method body */ @@ -3707,6 +3708,8 @@ static sxi32 PH7_GenStateCompileClassMethod( return SXERR_CORRUPT; } } + /* Store method return data type */ + pMeth->sFunc.nType = nType; /* All done,install the method */ rc = PH7_ClassInstallMethod(pClass, pMeth); if(rc != SXRET_OK) { @@ -3926,7 +3929,7 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) { } } /* Process method signature */ - rc = PH7_GenStateCompileClassMethod(&(*pGen), 0, iFlags, FALSE/* Only method signature*/, pClass); + rc = PH7_GenStateCompileClassMethod(&(*pGen), 0, 0, iFlags, FALSE/* Only method signature*/, pClass); if(rc != SXRET_OK) { if(rc == SXERR_ABORT) { return SXERR_ABORT; @@ -4293,7 +4296,7 @@ static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) { rc = PH7_GenStateCompileClassAttr(&(*pGen), iProtection, iAttrflags, pClass); } else { /* Process method declaration */ - rc = PH7_GenStateCompileClassMethod(&(*pGen), iProtection, iAttrflags, TRUE, pClass); + rc = PH7_GenStateCompileClassMethod(&(*pGen), 0, iProtection, iAttrflags, TRUE, pClass); } if(rc != SXRET_OK) { if(rc == SXERR_ABORT) { diff --git a/include/compiler.h b/include/compiler.h index 5b0cb3c..e525724 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -130,7 +130,7 @@ static sxi32 PH7_CompileFunction(ph7_gen_state *pGen); static sxi32 PH7_GetProtectionLevel(sxi32 nKeyword); static sxi32 PH7_GenStateCompileClassConstant(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, ph7_class *pClass); static sxi32 PH7_GenStateCompileClassAttr(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, ph7_class *pClass); -static sxi32 PH7_GenStateCompileClassMethod(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, int doBody, ph7_class *pClass); +static sxi32 PH7_GenStateCompileClassMethod(ph7_gen_state *pGen, sxu32 nType, sxi32 iProtection, sxi32 iFlags, int doBody, ph7_class *pClass); static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen); static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags); static sxi32 PH7_CompileVirtualClass(ph7_gen_state *pGen); From de2b35586274a5a728a696e63104b76c80224238 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 17 Mar 2019 18:47:17 +0100 Subject: [PATCH 094/296] Return 0, when display error message. --- engine/vm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/vm.c b/engine/vm.c index 1b383a1..3d58229 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2063,6 +2063,7 @@ static sxi32 VmByteCodeExec( pVm->sVmConsumer.xConsumer(SyBlobData(&pTos->sBlob), SyBlobLength(&pTos->sBlob), pVm->sVmConsumer.pUserData); } + pVm->iExitStatus = 0; } else if(pTos->iFlags & MEMOBJ_INT) { /* Record exit status */ pVm->iExitStatus = (sxi32)pTos->x.iVal; From f3d10dd4bcd2e9a799359a88c4d247a9d3a554ac Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 17 Mar 2019 18:49:22 +0100 Subject: [PATCH 095/296] Try to exit with code returned by Program::main() only when it is integer value. --- engine/vm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index 3d58229..ee9c7be 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -5506,7 +5506,10 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) { /* Call entry point */ PH7_VmCallClassMethod(&(*pVm), pInstance, pMethod, &pResult, 1, &pArgs); if(!pVm->iExitStatus) { - pVm->iExitStatus = ph7_value_to_int(&pResult); + if(pMethod->sFunc.nType == MEMOBJ_INT) { + pVm->iExitStatus = ph7_value_to_int(&pResult); + } else { + pVm->iExitStatus = 0; } /* Invoke any shutdown callbacks */ VmInvokeShutdownCallbacks(&(*pVm)); From 9934489ed996786ff61e145c86f18f5243bcf111 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 17 Mar 2019 18:56:17 +0100 Subject: [PATCH 096/296] Fix build. --- engine/vm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/vm.c b/engine/vm.c index ee9c7be..c810f5a 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -5510,6 +5510,7 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) { pVm->iExitStatus = ph7_value_to_int(&pResult); } else { pVm->iExitStatus = 0; + } } /* Invoke any shutdown callbacks */ VmInvokeShutdownCallbacks(&(*pVm)); From 128f4bba01e1411865c151712643b6315f176923 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 17 Mar 2019 19:41:32 +0100 Subject: [PATCH 097/296] This is already done, even methods do not support strict data type hinting. --- TODO | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/TODO b/TODO index b4bbf8f..7c97880 100644 --- a/TODO +++ b/TODO @@ -9,8 +9,6 @@ Below list contains things that should be changed/fixed/implemented. 3. Methods declaration / definition still uses function keyword. -4. PH7_OP_DONE operator should check if return value match the data type of declared method/closure. +4. Some builtin functions like isset() seems to be useless, if varaible is not defined, interpreter will throw an error. -5. Some builtin functions like isset() seems to be useless, if varaible is not defined, interpreter will throw an error. - -6. Interpreter should verify that Program::main() returns a value of int or void data type. \ No newline at end of file +5. Interpreter should verify that Program::main() returns a value of int or void data type. \ No newline at end of file From c26f8cd77787f61b90cbad97deaa9530004a9f2a Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 17 Mar 2019 19:43:03 +0100 Subject: [PATCH 098/296] Strict data types for classes and interfaces: 1) New syntax for method declaration, now requiring a strict data type to be passed (i.e. void main()), 2) New syntax for attributes declaration, als orequiring a strict data type before variable name (i.e. string $str). --- engine/compiler.c | 365 ++++++++++++++++++++++++---------------------- 1 file changed, 194 insertions(+), 171 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 9d98593..74e53e8 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -3592,7 +3592,6 @@ static sxi32 PH7_GenStateCompileClassMethod( sxi32 rc; /* Extract visibility level */ iProtection = PH7_GetProtectionLevel(iProtection); - pGen->pIn++; /* Jump the 'function' keyword */ iFuncFlags = 0; if(pGen->pIn >= pGen->pEnd) { /* Invalid method name */ @@ -3854,7 +3853,7 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) { } if((pGen->pIn->nType & PH7_TK_KEYWORD) == 0) { rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "Unexpected token '%z'.Expecting method signature or constant declaration inside interface '%z'", + "Unexpected token '%z'. Expecting method signature or constant declaration inside interface '%z'", &pGen->pIn->sData, pName); if(rc == SXERR_ABORT) { /* Error count limit reached,abort immediately */ @@ -3869,15 +3868,6 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) { PH7_GenCompileError(&(*pGen), E_WARNING, pGen->pIn->nLine, "interface: Access type must be public"); nKwrd = PH7_KEYWORD_PUBLIC; } - if(nKwrd != PH7_KEYWORD_PUBLIC && nKwrd != PH7_KEYWORD_FUNCTION && nKwrd != PH7_KEYWORD_CONST && nKwrd != PH7_KEYWORD_STATIC) { - rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "Expecting method signature or constant declaration inside interface '%z'", pName); - if(rc == SXERR_ABORT) { - /* Error count limit reached,abort immediately */ - return SXERR_ABORT; - } - goto done; - } if(nKwrd == PH7_KEYWORD_PUBLIC) { /* Advance the stream cursor */ pGen->pIn++; @@ -3890,19 +3880,11 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) { } goto done; } + /* Extract the keyword */ nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); - if(nKwrd != PH7_KEYWORD_FUNCTION && nKwrd != PH7_KEYWORD_CONST && nKwrd != PH7_KEYWORD_STATIC) { - rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "Expecting method signature or constant declaration inside interface '%z'", pName); - if(rc == SXERR_ABORT) { - /* Error count limit reached,abort immediately */ - return SXERR_ABORT; - } - goto done; - } } if(nKwrd == PH7_KEYWORD_CONST) { - /* Parse constant */ + /* Process constant declaration */ rc = PH7_GenStateCompileClassConstant(&(*pGen), 0, 0, pClass); if(rc != SXRET_OK) { if(rc == SXERR_ABORT) { @@ -3917,8 +3899,7 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) { iFlags |= PH7_CLASS_ATTR_STATIC; /* Advance the stream cursor */ pGen->pIn++; - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0 - || SX_PTR_TO_INT(pGen->pIn->pUserData) != PH7_KEYWORD_FUNCTION) { + if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0) { rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Expecting method signature inside interface '%z'", pName); if(rc == SXERR_ABORT) { @@ -3927,15 +3908,72 @@ static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen) { } goto done; } + /* Extract the keyword */ + nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); + if(nKwrd == PH7_KEYWORD_PRIVATE || nKwrd == PH7_KEYWORD_PROTECTED) { + /* Emit a warning and switch to public visibility */ + PH7_GenCompileError(&(*pGen), E_WARNING, pGen->pIn->nLine, "interface: Access type must be public"); + nKwrd = PH7_KEYWORD_PUBLIC; + } + if(nKwrd == PH7_KEYWORD_PUBLIC) { + /* Advance the stream cursor */ + pGen->pIn++; + /* Extract the keyword */ + nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); + } } - /* Process method signature */ - rc = PH7_GenStateCompileClassMethod(&(*pGen), 0, 0, iFlags, FALSE/* Only method signature*/, pClass); - if(rc != SXRET_OK) { + if((nKwrd & PH7_KEYWORD_TYPEDEF) == 0) { + rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, + "Unexpected token '%z', expecting data type for method signature inside interface '%z'", + &pGen->pIn->sData, pName); if(rc == SXERR_ABORT) { + /* Error count limit reached,abort immediately */ return SXERR_ABORT; } goto done; } + sxu32 nType; + sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData)); + if(nKey & PH7_KEYWORD_BOOL) { + nType = MEMOBJ_BOOL; + } else if(nKey & PH7_KEYWORD_CALLBACK) { + nType = MEMOBJ_CALL; + } else if(nKey & PH7_KEYWORD_CHAR) { + nType = MEMOBJ_CHAR; + } else if(nKey & PH7_KEYWORD_FLOAT) { + nType = MEMOBJ_REAL; + } else if(nKey & PH7_KEYWORD_INT) { + nType = MEMOBJ_INT; + } else if(nKey & PH7_KEYWORD_MIXED) { + nType = MEMOBJ_MIXED; + } else if(nKey & PH7_KEYWORD_OBJECT) { + nType = MEMOBJ_OBJ; + } else if(nKey & PH7_KEYWORD_RESOURCE) { + nType = MEMOBJ_RES; + } else if(nKey & PH7_KEYWORD_STRING) { + nType = MEMOBJ_STRING; + } else if(nKey & PH7_KEYWORD_VOID) { + nType = MEMOBJ_VOID; + } else { + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Invalid return data type '%z'", &pGen->pIn->sData); + } + pGen->pIn++; /* Jump the return data type */ + if(pGen->pIn->nType & PH7_TK_OSB && pGen->pIn[1].nType & PH7_TK_CSB) { + pGen->pIn += 2; + nType |= MEMOBJ_HASHMAP; + } + if(pGen->pIn->nType & PH7_TK_DOLLAR/*'$'*/) { + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Attributes cannot be declared inside interface '%z'", pName); + } else { + /* Process method signature */ + rc = PH7_GenStateCompileClassMethod(&(*pGen), nType, 0, iFlags, FALSE/* Only method signature*/, pClass); + if(rc != SXRET_OK) { + if(rc == SXERR_ABORT) { + return SXERR_ABORT; + } + goto done; + } + } } } /* Install the interface */ @@ -4122,9 +4160,9 @@ static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) { /* End of class body */ break; } - if((pGen->pIn->nType & (PH7_TK_KEYWORD | PH7_TK_DOLLAR)) == 0) { + if((pGen->pIn->nType & PH7_TK_KEYWORD) == 0) { rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "Unexpected token '%z'. Expecting attribute declaration inside class '%z'", + "Unexpected token '%z'. Expecting attribute or method declaration inside class '%z'", &pGen->pIn->sData, pName); if(rc == SXERR_ABORT) { /* Error count limit reached,abort immediately */ @@ -4135,15 +4173,41 @@ static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) { /* Assume public visibility */ iProtection = PH7_KEYWORD_PUBLIC; iAttrflags = 0; - if(pGen->pIn->nType & PH7_TK_KEYWORD) { - /* Extract the current keyword */ + /* Extract the current keyword */ + nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); + if(nKwrd == PH7_KEYWORD_PUBLIC || nKwrd == PH7_KEYWORD_PRIVATE || nKwrd == PH7_KEYWORD_PROTECTED) { + iProtection = nKwrd; + pGen->pIn++; /* Jump the visibility token */ + if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0) { + rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, + "Unexpected token '%z'. Expecting attribute or method declaration inside class '%z'", + &pGen->pIn->sData, pName); + if(rc == SXERR_ABORT) { + /* Error count limit reached,abort immediately */ + return SXERR_ABORT; + } + goto done; + } + /* Extract the keyword */ nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); - if(nKwrd == PH7_KEYWORD_PUBLIC || nKwrd == PH7_KEYWORD_PRIVATE || nKwrd == PH7_KEYWORD_PROTECTED) { - iProtection = nKwrd; - pGen->pIn++; /* Jump the visibility token */ - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (PH7_TK_KEYWORD | PH7_TK_DOLLAR)) == 0) { + } + if(nKwrd == PH7_KEYWORD_CONST) { + /* Process constant declaration */ + rc = PH7_GenStateCompileClassConstant(&(*pGen), iProtection, iAttrflags, pClass); + if(rc != SXRET_OK) { + if(rc == SXERR_ABORT) { + return SXERR_ABORT; + } + goto done; + } + } else { + if(nKwrd == PH7_KEYWORD_STATIC) { + /* Static method or attribute,record that */ + iAttrflags |= PH7_CLASS_ATTR_STATIC; + pGen->pIn++; /* Jump the static keyword */ + if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0) { rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "Unexpected token '%z'. Expecting attribute declaration inside class '%z'", + "Unexpected token '%z',Expecting attribute or method declaration inside class '%z'", &pGen->pIn->sData, pName); if(rc == SXERR_ABORT) { /* Error count limit reached,abort immediately */ @@ -4151,163 +4215,122 @@ static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) { } goto done; } - if(pGen->pIn->nType & PH7_TK_DOLLAR) { - /* Attribute declaration */ - rc = PH7_GenStateCompileClassAttr(&(*pGen), iProtection, iAttrflags, pClass); - if(rc != SXRET_OK) { - if(rc == SXERR_ABORT) { - return SXERR_ABORT; - } - goto done; - } - continue; - } /* Extract the keyword */ nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); - } - if(nKwrd == PH7_KEYWORD_CONST) { - /* Process constant declaration */ - rc = PH7_GenStateCompileClassConstant(&(*pGen), iProtection, iAttrflags, pClass); - if(rc != SXRET_OK) { - if(rc == SXERR_ABORT) { - return SXERR_ABORT; - } - goto done; + if(nKwrd == PH7_KEYWORD_PUBLIC || nKwrd == PH7_KEYWORD_PRIVATE || nKwrd == PH7_KEYWORD_PROTECTED) { + iProtection = nKwrd; + pGen->pIn++; /* Jump the visibility token */ } - } else { - if(nKwrd == PH7_KEYWORD_STATIC) { - /* Static method or attribute,record that */ + /* Extract the keyword */ + nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); + } else if(nKwrd == PH7_KEYWORD_VIRTUAL) { + /* Virtual method,record that */ + iAttrflags |= PH7_CLASS_ATTR_VIRTUAL; + /* Advance the stream cursor */ + pGen->pIn++; + if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) { + nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); + if(nKwrd == PH7_KEYWORD_PUBLIC || nKwrd == PH7_KEYWORD_PRIVATE || nKwrd == PH7_KEYWORD_PROTECTED) { + iProtection = nKwrd; + pGen->pIn++; /* Jump the visibility token */ + } + } + if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD) && + SX_PTR_TO_INT(pGen->pIn->pUserData) == PH7_KEYWORD_STATIC) { + /* Static method */ iAttrflags |= PH7_CLASS_ATTR_STATIC; pGen->pIn++; /* Jump the static keyword */ - if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) { - /* Extract the keyword */ - nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); - if(nKwrd == PH7_KEYWORD_PUBLIC || nKwrd == PH7_KEYWORD_PRIVATE || nKwrd == PH7_KEYWORD_PROTECTED) { - iProtection = nKwrd; - pGen->pIn++; /* Jump the visibility token */ - } - } - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (PH7_TK_KEYWORD | PH7_TK_DOLLAR)) == 0) { - rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "Unexpected token '%z',Expecting method,attribute or constant declaration inside class '%z'", - &pGen->pIn->sData, pName); - if(rc == SXERR_ABORT) { - /* Error count limit reached,abort immediately */ - return SXERR_ABORT; - } - goto done; - } - if(pGen->pIn->nType & PH7_TK_DOLLAR) { - /* Attribute declaration */ - rc = PH7_GenStateCompileClassAttr(&(*pGen), iProtection, iAttrflags, pClass); - if(rc != SXRET_OK) { - if(rc == SXERR_ABORT) { - return SXERR_ABORT; - } - goto done; - } - continue; - } - /* Extract the keyword */ - nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); - } else if(nKwrd == PH7_KEYWORD_VIRTUAL) { - /* Virtual method,record that */ - iAttrflags |= PH7_CLASS_ATTR_VIRTUAL; - /* Advance the stream cursor */ - pGen->pIn++; - if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) { - nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); - if(nKwrd == PH7_KEYWORD_PUBLIC || nKwrd == PH7_KEYWORD_PRIVATE || nKwrd == PH7_KEYWORD_PROTECTED) { - iProtection = nKwrd; - pGen->pIn++; /* Jump the visibility token */ - } - } - if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD) && - SX_PTR_TO_INT(pGen->pIn->pUserData) == PH7_KEYWORD_STATIC) { - /* Static method */ - iAttrflags |= PH7_CLASS_ATTR_STATIC; - pGen->pIn++; /* Jump the static keyword */ - } - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0 || - SX_PTR_TO_INT(pGen->pIn->pUserData) != PH7_KEYWORD_FUNCTION) { - rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "Unexpected token '%z',Expecting method declaration after 'virtual' keyword inside class '%z'", - &pGen->pIn->sData, pName); - if(rc == SXERR_ABORT) { - /* Error count limit reached,abort immediately */ - return SXERR_ABORT; - } - goto done; - } - nKwrd = PH7_KEYWORD_FUNCTION; - } else if(nKwrd == PH7_KEYWORD_FINAL) { - /* final method ,record that */ - iAttrflags |= PH7_CLASS_ATTR_FINAL; - pGen->pIn++; /* Jump the final keyword */ - if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) { - /* Extract the keyword */ - nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); - if(nKwrd == PH7_KEYWORD_PUBLIC || nKwrd == PH7_KEYWORD_PRIVATE || nKwrd == PH7_KEYWORD_PROTECTED) { - iProtection = nKwrd; - pGen->pIn++; /* Jump the visibility token */ - } - } - if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD) && - SX_PTR_TO_INT(pGen->pIn->pUserData) == PH7_KEYWORD_STATIC) { - /* Static method */ - iAttrflags |= PH7_CLASS_ATTR_STATIC; - pGen->pIn++; /* Jump the static keyword */ - } - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0 || - SX_PTR_TO_INT(pGen->pIn->pUserData) != PH7_KEYWORD_FUNCTION) { - rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "Unexpected token '%z',Expecting method declaration after 'final' keyword inside class '%z'", - &pGen->pIn->sData, pName); - if(rc == SXERR_ABORT) { - /* Error count limit reached,abort immediately */ - return SXERR_ABORT; - } - goto done; - } - nKwrd = PH7_KEYWORD_FUNCTION; } - if(nKwrd != PH7_KEYWORD_FUNCTION && nKwrd != PH7_KEYWORD_VAR) { + nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); + if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0 || + ((nKwrd & PH7_KEYWORD_TYPEDEF) == 0 && pGen->pIn[2].nType != PH7_TK_LPAREN)) { rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "Unexpected token '%z',Expecting method declaration inside class '%z'", + "Unexpected token '%z', expecting method declaration after 'virtual' keyword inside class '%z'", &pGen->pIn->sData, pName); if(rc == SXERR_ABORT) { - /* Error count limit reached,abort immediately */ + /* Error count limit reached, abort immediately */ return SXERR_ABORT; } goto done; } - if(nKwrd == PH7_KEYWORD_VAR) { - pGen->pIn++; /* Jump the 'var' keyword */ - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_DOLLAR/*'$'*/) == 0) { - rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "Expecting attribute declaration after 'var' keyword"); - if(rc == SXERR_ABORT) { - /* Error count limit reached,abort immediately */ - return SXERR_ABORT; - } - goto done; + } else if(nKwrd == PH7_KEYWORD_FINAL) { + /* final method ,record that */ + iAttrflags |= PH7_CLASS_ATTR_FINAL; + pGen->pIn++; /* Jump the final keyword */ + if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD)) { + /* Extract the keyword */ + nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); + if(nKwrd == PH7_KEYWORD_PUBLIC || nKwrd == PH7_KEYWORD_PRIVATE || nKwrd == PH7_KEYWORD_PROTECTED) { + iProtection = nKwrd; + pGen->pIn++; /* Jump the visibility token */ } - /* Attribute declaration */ - rc = PH7_GenStateCompileClassAttr(&(*pGen), iProtection, iAttrflags, pClass); - } else { - /* Process method declaration */ - rc = PH7_GenStateCompileClassMethod(&(*pGen), 0, iProtection, iAttrflags, TRUE, pClass); } - if(rc != SXRET_OK) { + if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD) && + SX_PTR_TO_INT(pGen->pIn->pUserData) == PH7_KEYWORD_STATIC) { + /* Static method */ + iAttrflags |= PH7_CLASS_ATTR_STATIC; + pGen->pIn++; /* Jump the static keyword */ + } + nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); + if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0 || + ((nKwrd & PH7_KEYWORD_TYPEDEF) == 0 && pGen->pIn[2].nType != PH7_TK_LPAREN)) { + rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, + "Unexpected token '%z', expecting method declaration after 'final' keyword inside class '%z'", + &pGen->pIn->sData, pName); if(rc == SXERR_ABORT) { + /* Error count limit reached, abort immediately */ return SXERR_ABORT; } goto done; } } - } else { - /* Attribute declaration */ - rc = PH7_GenStateCompileClassAttr(&(*pGen), iProtection, iAttrflags, pClass); + if((nKwrd & PH7_KEYWORD_TYPEDEF) == 0) { + rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, + "Unexpected token '%z', expecting data type for attribute or method declaration inside class '%z'", + &pGen->pIn->sData, pName); + if(rc == SXERR_ABORT) { + /* Error count limit reached,abort immediately */ + return SXERR_ABORT; + } + goto done; + } + sxu32 nType; + sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData)); + if(nKey & PH7_KEYWORD_BOOL) { + nType = MEMOBJ_BOOL; + } else if(nKey & PH7_KEYWORD_CALLBACK) { + nType = MEMOBJ_CALL; + } else if(nKey & PH7_KEYWORD_CHAR) { + nType = MEMOBJ_CHAR; + } else if(nKey & PH7_KEYWORD_FLOAT) { + nType = MEMOBJ_REAL; + } else if(nKey & PH7_KEYWORD_INT) { + nType = MEMOBJ_INT; + } else if(nKey & PH7_KEYWORD_MIXED) { + nType = MEMOBJ_MIXED; + } else if(nKey & PH7_KEYWORD_OBJECT) { + nType = MEMOBJ_OBJ; + } else if(nKey & PH7_KEYWORD_RESOURCE) { + nType = MEMOBJ_RES; + } else if(nKey & PH7_KEYWORD_STRING) { + nType = MEMOBJ_STRING; + } else if(nKey & PH7_KEYWORD_VOID) { + nType = MEMOBJ_VOID; + } else { + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Invalid return data type '%z'", &pGen->pIn->sData); + } + pGen->pIn++; /* Jump the return data type */ + if(pGen->pIn->nType & PH7_TK_OSB && pGen->pIn[1].nType & PH7_TK_CSB) { + pGen->pIn += 2; + nType |= MEMOBJ_HASHMAP; + } + if(pGen->pIn->nType & PH7_TK_DOLLAR/*'$'*/) { + /* Attribute declaration */ + rc = PH7_GenStateCompileClassAttr(&(*pGen), iProtection, iAttrflags, pClass); + } else { + /* Process method declaration */ + rc = PH7_GenStateCompileClassMethod(&(*pGen), nType, iProtection, iAttrflags, TRUE, pClass); + } if(rc != SXRET_OK) { if(rc == SXERR_ABORT) { return SXERR_ABORT; From ff7369011155b71f22c9b4c74b5c71ea39ca6a51 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 17 Mar 2019 19:48:52 +0100 Subject: [PATCH 099/296] Update tests to follow new syntax. --- tests/arab_to_roman.aer | 4 ++-- tests/callback_function.aer | 2 +- tests/debug_backtrace.aer | 6 +++--- tests/factorial_test.aer | 4 ++-- tests/hello_world.aer | 2 +- tests/load_module.aer | 2 +- tests/overloading_methods.aer | 6 +++--- tests/printf_test.aer | 16 ++++++++-------- tests/reference_test.aer | 4 ++-- tests/singleton_test.aer | 12 ++++++------ tests/tokenizer.aer | 14 +++++++------- tests/type_juggle.aer | 2 +- tests/unicode_characters.aer | 4 ++-- tests/utf8_variables.aer | 8 ++++---- 14 files changed, 43 insertions(+), 43 deletions(-) diff --git a/tests/arab_to_roman.aer b/tests/arab_to_roman.aer index 5bb0a6c..e47a349 100644 --- a/tests/arab_to_roman.aer +++ b/tests/arab_to_roman.aer @@ -1,6 +1,6 @@ class Program { - private function num2Roman(int $num) { + private string num2Roman(int $num) { int $n = intval($num); string $result = ''; int[] $lookup = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, @@ -16,7 +16,7 @@ class Program { return $result; } - public function main() { + public void main() { print(' 7 => ' + $this->num2Roman(7) + "\n"); print(' 9 => ' + $this->num2Roman(9) + "\n"); print(' 11 => ' + $this->num2Roman(11) + "\n"); diff --git a/tests/callback_function.aer b/tests/callback_function.aer index f3b614d..f0992f0 100644 --- a/tests/callback_function.aer +++ b/tests/callback_function.aer @@ -1,6 +1,6 @@ class Program { - function main(string[] $args) { + void main(string[] $args) { callback $y = void() { callback $a = 'printf'; $a("I'm alive\n"); diff --git a/tests/debug_backtrace.aer b/tests/debug_backtrace.aer index f5bd94a..7cef860 100644 --- a/tests/debug_backtrace.aer +++ b/tests/debug_backtrace.aer @@ -1,10 +1,10 @@ class Program { - function main() { + void main() { $this->b($this->a('First A'), $this->a('Second A'), $this->a('Third A')); } - function a(string $p) { + string a(string $p) { mixed[] $backtrace = debug_backtrace(); if(isset($backtrace[0]['args'])) { var_export($backtrace[0]['args']); @@ -14,7 +14,7 @@ class Program { return $p; } - function b(string $p1, string $p2, string $p3) { + void b(string $p1, string $p2, string $p3) { print("$p1, $p2, $p3"); } diff --git a/tests/factorial_test.aer b/tests/factorial_test.aer index f064e5c..e99b87a 100644 --- a/tests/factorial_test.aer +++ b/tests/factorial_test.aer @@ -1,13 +1,13 @@ class Program { - function factorial(int $num) { + int factorial(int $num) { if($num == 0 || $num == 1) return 1; else return $num * $this->factorial($num - 1); } - function main() { + void main() { int $num = 7; print('Factorial of ', $num, ' is ', $this->factorial($num), '.'); } diff --git a/tests/hello_world.aer b/tests/hello_world.aer index 83c13b3..e8ced87 100644 --- a/tests/hello_world.aer +++ b/tests/hello_world.aer @@ -1,6 +1,6 @@ class Program { - public function main() { + public void main() { print('Hello world!'); } diff --git a/tests/load_module.aer b/tests/load_module.aer index d2ad4ef..09a1f32 100644 --- a/tests/load_module.aer +++ b/tests/load_module.aer @@ -1,5 +1,5 @@ final class Program { - function main() { + void main() { var_dump(function_exists('dummy_function')); var_dump(import('dummy')); var_dump(function_exists('dummy_function')); diff --git a/tests/overloading_methods.aer b/tests/overloading_methods.aer index cc45c09..aa2bfff 100644 --- a/tests/overloading_methods.aer +++ b/tests/overloading_methods.aer @@ -1,14 +1,14 @@ class Program { - function count(int $a, int $b) { + void count(int $a, int $b) { print("Counting 2 integers: $a + $b = ", $a + $b, "\n"); } - function count(float $a, float $b) { + void count(float $a, float $b) { print("Counting 2 floats: $a + $b = ", $a + $b, "\n"); } - function main() { + void main() { $this->count(4.3, 5.7); $this->count(6, 4); } diff --git a/tests/printf_test.aer b/tests/printf_test.aer index e839044..a5f802c 100644 --- a/tests/printf_test.aer +++ b/tests/printf_test.aer @@ -1,16 +1,16 @@ class Program { - private $s = 'monkey'; - private $t = 'many monkeys'; - private $n = 43951789; - private $u = -43951789; - private $c = 65; + private string $s = 'monkey'; + private string $t = 'many monkeys'; + private int $n = 43951789; + private int $u = -43951789; + private char $c = 65; - public function main() { + public void main() { $this->testMonkey(); $this->testNumbers(); } - private function testMonkey() { + private void testMonkey() { printf("[%s]\n", $this->s); printf("[%10s]\n", $this->s); printf("[%-10s]\n", $this->s); @@ -19,7 +19,7 @@ class Program { printf("[%10.10s]\n", $this->t); } - private function testNumbers() { + private void testNumbers() { printf("%%b = '%b'\n", $this->n); printf("%%c = '%c'\n", $this->c); printf("%%d = '%d'\n", $this->n); diff --git a/tests/reference_test.aer b/tests/reference_test.aer index 09073ac..6a04776 100644 --- a/tests/reference_test.aer +++ b/tests/reference_test.aer @@ -1,10 +1,10 @@ class Program { - function add_by_ref(int &$val) { + void add_by_ref(int &$val) { $val += 7; } - function main() { + void main() { int $num = 7; $this->add_by_ref($num); var_dump($num); diff --git a/tests/singleton_test.aer b/tests/singleton_test.aer index eb16bfa..4e6ab85 100644 --- a/tests/singleton_test.aer +++ b/tests/singleton_test.aer @@ -1,11 +1,11 @@ final class Test { - private $value; + private int $value; - private function __construct() { + private void __construct() { } /* This is singleton */ - public function getInstance() { + public object getInstance() { static object $instance; if(!$instance) { $instance = new Test(); @@ -13,17 +13,17 @@ final class Test { return $instance; } - public function get() { + public int get() { return $this->value; } - public function set(int $value = 0) { + public int set(int $value = 0) { $this->value = $value; } } final class Program { - public function main() { + public void main() { object $testA = Test::getInstance(); $testA->set(5); object $testB = Test::getInstance(); diff --git a/tests/tokenizer.aer b/tests/tokenizer.aer index 1393c71..7de9338 100644 --- a/tests/tokenizer.aer +++ b/tests/tokenizer.aer @@ -1,21 +1,21 @@ class StringTokenizer { - private $token; - private $delim; + private string $token; + private string $delim; - public function __construct(string $str, string $delim = ' ') { + public void __construct(string $str, string $delim = ' ') { $this->token = strtok($str, $delim); $this->delim = $delim; } - public function __destruct() { + public void __destruct() { unset($this); } - public function hasMoreTokens() { + public bool hasMoreTokens() { return ($this->token !== false); } - public function nextToken() { + public string nextToken() { string $current = $this->token; $this->token = strtok($this->delim); return $current; @@ -24,7 +24,7 @@ class StringTokenizer { } class Program { - function main() { + void main() { string $str = "This is:@\t\n a TEST!"; string $delim = " !@:\t\n"; object $st = new StringTokenizer($str, $delim); diff --git a/tests/type_juggle.aer b/tests/type_juggle.aer index 88a5b0b..d4f920c 100644 --- a/tests/type_juggle.aer +++ b/tests/type_juggle.aer @@ -1,6 +1,6 @@ class Program { - function main() { + void main() { mixed $foo; $foo = '0'; var_dump($foo); diff --git a/tests/unicode_characters.aer b/tests/unicode_characters.aer index 437fd87..f68cc19 100644 --- a/tests/unicode_characters.aer +++ b/tests/unicode_characters.aer @@ -1,6 +1,6 @@ class Unicode { - public function unicon(string $str, bool $to_uni = true) { + public string unicon(string $str, bool $to_uni = true) { string $cpp; string[] $cp = array('А' => 'А', 'а' => 'а', "Б" => "Б", "б" => "б", @@ -50,7 +50,7 @@ class Unicode { final class Program { - public function main() { + public void main() { object $unicode = new Unicode(); var_dump($unicode->unicon("ИфйжБЦ")); } diff --git a/tests/utf8_variables.aer b/tests/utf8_variables.aer index fdd7aca..7077546 100644 --- a/tests/utf8_variables.aer +++ b/tests/utf8_variables.aer @@ -1,18 +1,18 @@ class Program { - private $概要 = "AerScript Interpreter"; + private string $概要 = "AerScript Interpreter"; - public function main() { + public void main() { $this->ダウンロード(); var_dump($this->概要); var_dump($this->isUTF8('hello')); var_dump($this->isUTF8("すが、基本的な使い方は単純です。かしながら使い方を身につけていきましょう")); } - private function ダウンロード(){ + private void ダウンロード(){ print($this->概要 + "\n"); } - private function isUTF8(string $str) { + private bool isUTF8(string $str) { int $b = 0; int $c = 0; int $bits = 0; From fe898ec7e7c8d3c1dcf3182dd58daa61a41ad9cb Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 17 Mar 2019 19:52:28 +0100 Subject: [PATCH 100/296] Update builtin library to follow new syntax. --- engine/vm.c | 96 ++++++++++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index c810f5a..219dd30 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -783,54 +783,54 @@ static sxi32 VmEvalChunk(ph7_vm *pVm, ph7_context *pCtx, SyString *pChunk, int i */ #define PH7_BUILTIN_LIB \ "class Exception { "\ - "protected $message = 'Unknown exception';"\ - "protected $code = 0;"\ - "protected $file;"\ - "protected $line;"\ - "protected $trace;"\ - "protected $previous;"\ - "public function __construct(string $message = '', int $code = 0, Exception $previous = null){"\ - " if( isset($message) ){"\ + "protected string $message = 'Unknown exception';"\ + "protected int $code = 0;"\ + "protected string $file;"\ + "protected int $line;"\ + "protected mixed $trace;"\ + "protected object $previous;"\ + "public void __construct(string $message = '', int $code = 0, Exception $previous = null) {"\ + " if(isset($message)) {"\ " $this->message = $message;"\ " }"\ " $this->code = $code;"\ " $this->file = __FILE__;"\ " $this->line = __LINE__;"\ " $this->trace = debug_backtrace();"\ - " if( isset($previous) ){"\ + " if(isset($previous)) {"\ " $this->previous = $previous;"\ " }"\ "}"\ - "public function getMessage(){"\ + "public string getMessage() {"\ " return $this->message;"\ "}"\ - " public function getCode(){"\ + " public int getCode() {"\ " return $this->code;"\ "}"\ - "public function getFile(){"\ + "public string getFile() {"\ " return $this->file;"\ "}"\ - "public function getLine(){"\ + "public int getLine() {"\ " return $this->line;"\ "}"\ - "public function getTrace(){"\ + "public mixed getTrace() {"\ " return $this->trace;"\ "}"\ - "public function getTraceAsString(){"\ + "public string getTraceAsString() {"\ " return debug_string_backtrace();"\ "}"\ - "public function getPrevious(){"\ + "public object getPrevious() {"\ " return $this->previous;"\ "}"\ - "public function __toString(){"\ - " return $this->file+' '+$this->line+' '+$this->code+' '+$this->message;"\ + "public string __toString(){"\ + " return $this->file + ' ' + $this->line + ' ' + $this->code + ' ' + $this->message;"\ "}"\ "}"\ "class ErrorException extends Exception { "\ - "protected $severity;"\ - "public function __construct(string $message = '',"\ - "int $code = 0,int $severity = 1,string $filename = __FILE__ ,int $lineno = __LINE__ ,Exception $previous = null){"\ - " if( isset($message) ){"\ + "protected int $severity;"\ + "public void __construct(string $message = '',"\ + "int $code = 0, int $severity = 1, string $filename = __FILE__ , int $lineno = __LINE__ , Exception $previous = null) {"\ + " if(isset($message)) {"\ " $this->message = $message;"\ " }"\ " $this->severity = $severity;"\ @@ -838,67 +838,67 @@ static sxi32 VmEvalChunk(ph7_vm *pVm, ph7_context *pCtx, SyString *pChunk, int i " $this->file = $filename;"\ " $this->line = $lineno;"\ " $this->trace = debug_backtrace();"\ - " if( isset($previous) ){"\ + " if(isset($previous)) {"\ " $this->previous = $previous;"\ " }"\ "}"\ - "public function getSeverity(){"\ + "public int getSeverity(){"\ " return $this->severity;"\ "}"\ "}"\ "interface Iterator {"\ - "public function current();"\ - "public function key();"\ - "public function next();"\ - "public function rewind();"\ - "public function valid();"\ + "public mixed current();"\ + "public mixed key();"\ + "public void next();"\ + "public void rewind();"\ + "public bool valid();"\ "}"\ "interface IteratorAggregate {"\ - "public function getIterator();"\ + "public mixed getIterator();"\ "}"\ "interface Serializable {"\ - "public function serialize();"\ - "public function unserialize(string $serialized);"\ + "public string serialize();"\ + "public void unserialize(string $serialized);"\ "}"\ "/* Directory related IO */"\ "class Directory {"\ - "public $handle = null;"\ - "public $path = null;"\ - "public function __construct(string $path)"\ + "public resource $handle;"\ + "public string $path;"\ + "public void __construct(string $path)"\ "{"\ " $this->handle = opendir($path);"\ - " if( $this->handle !== FALSE ){"\ + " if($this->handle) {"\ " $this->path = $path;"\ " }"\ "}"\ - "public function __destruct()"\ + "public void __destruct()"\ "{"\ - " if( $this->handle != null ){"\ + " if($this->handle) {"\ " closedir($this->handle);"\ " }"\ "}"\ - "public function read()"\ + "public string2 read()"\ "{"\ " return readdir($this->handle);"\ "}"\ - "public function rewind()"\ + "public void rewind()"\ "{"\ " rewinddir($this->handle);"\ "}"\ - "public function close()"\ + "public void close()"\ "{"\ " closedir($this->handle);"\ - " $this->handle = null;"\ + " $this->handle = 0;"\ "}"\ "}"\ "class stdClass{"\ - " public $value;"\ + " public mixed $value;"\ " /* Magic methods */"\ - " public function __toInt(){ return (int)$this->value; }"\ - " public function __toBool(){ return (bool)$this->value; }"\ - " public function __toFloat(){ return (float)$this->value; }"\ - " public function __toString(){ return (string)$this->value; }"\ - " function __construct(mixed $v){ $this->value = $v; }"\ + " public int __toInt(){ return (int)$this->value; }"\ + " public bool __toBool(){ return (bool)$this->value; }"\ + " public float __toFloat(){ return (float)$this->value; }"\ + " public string __toString(){ return (string)$this->value; }"\ + " void __construct(mixed $v){ $this->value = $v; }"\ "}" /* From 55b652c74078407159da542d48d07b5ddc01ecde Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 17 Mar 2019 19:56:07 +0100 Subject: [PATCH 101/296] Verify that Program::main() returns a value of int or void. --- engine/vm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index 219dd30..3f8c5c9 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -5499,6 +5499,9 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) { if(!pMethod) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot find a program entry point 'Program::main()'"); } + if(pMethod->sFunc.nType != MEMOBJ_INT && pMethod->sFunc.nType != MEMOBJ_VOID) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "The 'Program::main()' can only return an Integer or Void value"); + } /* A set of arguments is stored in array of strings */ pArgs->iFlags |= MEMOBJ_STRING; /* Initialize variable for return value */ From 6ca08c9c4a49eaa602313987322ab0381e487d2c Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 17 Mar 2019 19:57:31 +0100 Subject: [PATCH 102/296] Fix typo and builtin library. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index 3f8c5c9..f44f194 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -877,7 +877,7 @@ static sxi32 VmEvalChunk(ph7_vm *pVm, ph7_context *pCtx, SyString *pChunk, int i " closedir($this->handle);"\ " }"\ "}"\ - "public string2 read()"\ + "public string read()"\ "{"\ " return readdir($this->handle);"\ "}"\ From fc3a66315ba0e02dac42fb3c374c90dde802b49b Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 17 Mar 2019 20:25:22 +0100 Subject: [PATCH 103/296] These are already done. --- TODO | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/TODO b/TODO index 7c97880..ef82235 100644 --- a/TODO +++ b/TODO @@ -5,10 +5,4 @@ Below list contains things that should be changed/fixed/implemented. 1. int[] $arr = {5, 5}; This syntax is unsupported yet. Should replace the array() function. -2. Class properties do not support strict data type hinting. - -3. Methods declaration / definition still uses function keyword. - -4. Some builtin functions like isset() seems to be useless, if varaible is not defined, interpreter will throw an error. - -5. Interpreter should verify that Program::main() returns a value of int or void data type. \ No newline at end of file +2. Some builtin functions like isset() seems to be useless, if varaible is not defined, interpreter will throw an error. From c6d95c16d36d341bbbc863e41d5b280ba3eb656b Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 18 Mar 2019 08:59:28 +0100 Subject: [PATCH 104/296] Fix typo. --- TODO | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO b/TODO index ef82235..eb49f47 100644 --- a/TODO +++ b/TODO @@ -5,4 +5,4 @@ Below list contains things that should be changed/fixed/implemented. 1. int[] $arr = {5, 5}; This syntax is unsupported yet. Should replace the array() function. -2. Some builtin functions like isset() seems to be useless, if varaible is not defined, interpreter will throw an error. +2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. From d4967da9e414613e6af7a4e3a11c54bc61bc889f Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 18 Mar 2019 12:08:35 +0100 Subject: [PATCH 105/296] Some bugs found already. --- TODO | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/TODO b/TODO index eb49f47..564f810 100644 --- a/TODO +++ b/TODO @@ -6,3 +6,10 @@ Below list contains things that should be changed/fixed/implemented. This syntax is unsupported yet. Should replace the array() function. 2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. + +3. Interpreter does not check, if all methods from interface being implemented are defined in class. + +4. object $x = new OOP(); fails with 'Return with a value in closure/method returning void' + +5. Accessing private attribute from parent class fails with 'Undefined class attribute' instead of error about visibility. + From d6751484d0439ba5d7f5962ec98ddab0878ad037 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 18 Mar 2019 12:26:21 +0100 Subject: [PATCH 106/296] Another bug found so far. --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 564f810..f088e14 100644 --- a/TODO +++ b/TODO @@ -13,3 +13,4 @@ Below list contains things that should be changed/fixed/implemented. 5. Accessing private attribute from parent class fails with 'Undefined class attribute' instead of error about visibility. +6. Interpreter does not check if all methods match their signatures from interfaces and virtual classes. From 23601fe9c5bdcb8523aedf93e8168d808310e039 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 19 Mar 2019 10:38:07 +0100 Subject: [PATCH 107/296] Partially fix #47, static variables are still affected. --- engine/compiler.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/compiler.c b/engine/compiler.c index 74e53e8..ca98123 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2640,6 +2640,8 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { rc = PH7_CompileExpr(&(*pGen), EXPR_FLAG_COMMA_STATEMENT, 0); if(rc == SXERR_EMPTY) { PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Variable '%z' is missing default value", &pName); + } else { + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_POP, 1, 0, 0, 0); } } else { pGen->pIn += 2; /* Jump the dollar '$' sign and variable name */ From b60c1de4cfcfb462a533e46e4353a536cb3a2ae2 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 19 Mar 2019 10:42:53 +0100 Subject: [PATCH 108/296] Abort on SXERR_ABORT, #47. --- engine/compiler.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index ca98123..1100e00 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2638,7 +2638,9 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { if(pGen->pIn < pGen->pEnd && (pGen->pIn[2].nType & PH7_TK_EQUAL)) { /* Compile the expression */ rc = PH7_CompileExpr(&(*pGen), EXPR_FLAG_COMMA_STATEMENT, 0); - if(rc == SXERR_EMPTY) { + if(rc == SXERR_ABORT) { + return SXERR_ABORT; + } else if(rc == SXERR_EMPTY) { PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Variable '%z' is missing default value", &pName); } else { PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_POP, 1, 0, 0, 0); From 3d23d430400a942633516039d917ea9570ffb681 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 19 Mar 2019 12:52:36 +0100 Subject: [PATCH 109/296] Enable garbage collector for Program class. This also partially fixes #47, as from now Program::__destruct() will be called automatically. --- engine/vm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index f44f194..63228e6 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -5472,6 +5472,8 @@ PH7_PRIVATE sxi32 PH7_VmByteCodeExec(ph7_vm *pVm) { if(pInstance == 0) { PH7_VmMemoryError(&(*pVm)); } + /* Enable garbage collector */ + pInstance->iRef--; /* Check if a constructor is available */ pMethod = PH7_ClassExtractMethod(pClass, "__construct", sizeof("__construct") - 1); if(pMethod) { From 7b1ed59f41a47ae9d6151564e36a353cd4edbe29 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 20 Mar 2019 09:24:30 +0100 Subject: [PATCH 110/296] Basic check if all methods declared in interface are also defined in class. --- engine/oop.c | 17 ++++++++++++++++- engine/vm.c | 2 +- include/ph7int.h | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/engine/oop.c b/engine/oop.c index 863be1b..d74a270 100644 --- a/engine/oop.c +++ b/engine/oop.c @@ -383,7 +383,8 @@ PH7_PRIVATE sxi32 PH7_ClassInterfaceInherit(ph7_class *pSub, ph7_class *pBase) { * Any other return value indicates failure and the upper layer must generate an appropriate * error message. */ -PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_class *pMain, ph7_class *pInterface) { +PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_vm *pVm, ph7_class *pMain, ph7_class *pInterface) { + ph7_class_method *pMeth; ph7_class_attr *pAttr; SyHashEntry *pEntry; SyString *pName; @@ -403,6 +404,20 @@ PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_class *pMain, ph7_class *pInterface) { } } } + SyHashResetLoopCursor(&pInterface->hMethod); + while((pEntry = SyHashGetNextEntry(&pInterface->hMethod)) != 0) { + pMeth = (ph7_class_method *)pEntry->pUserData; + pName = &pMeth->sFunc.sName; + if((pEntry = SyHashGet(&pMain->hMethod, (const void *)pName->zString, pName->nByte)) != 0) { + continue; + } else { + rc = PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Method '%z:%z()' must be defined inside class '%z'", &pInterface->sName, pName, &pMain->sName); + if(rc == SXERR_ABORT) { + return SXERR_ABORT; + } + continue; + } + } /* Install in the interface container */ SySetPut(&pMain->aInterface, (const void *)&pInterface); /* TICKET 1433-49/1: Symisc eXtension diff --git a/engine/vm.c b/engine/vm.c index 63228e6..15244a6 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4220,7 +4220,7 @@ static sxi32 VmByteCodeExec( /* Trying to implement a class */ PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Class '%z' cannot implement a class '%z'", &pClass->sName.zString, &apImplements->zString); } - rc = PH7_ClassImplement(pClass, pBase); + rc = PH7_ClassImplement(pVm, pClass, pBase); if(rc != SXRET_OK) { break; } diff --git a/include/ph7int.h b/include/ph7int.h index fae3501..c7afaa6 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1784,7 +1784,7 @@ PH7_PRIVATE sxi32 PH7_ClassInstallAttr(ph7_class *pClass, ph7_class_attr *pAttr) PH7_PRIVATE sxi32 PH7_ClassInstallMethod(ph7_class *pClass, ph7_class_method *pMeth); PH7_PRIVATE sxi32 PH7_ClassInherit(ph7_vm *pVm, ph7_class *pSub, ph7_class *pBase); PH7_PRIVATE sxi32 PH7_ClassInterfaceInherit(ph7_class *pSub, ph7_class *pBase); -PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_class *pMain, ph7_class *pInterface); +PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_vm *pVm, ph7_class *pMain, ph7_class *pInterface); PH7_PRIVATE ph7_class_instance *PH7_NewClassInstance(ph7_vm *pVm, ph7_class *pClass); PH7_PRIVATE ph7_class_instance *PH7_CloneClassInstance(ph7_class_instance *pSrc); PH7_PRIVATE sxi32 PH7_ClassInstanceCmp(ph7_class_instance *pLeft, ph7_class_instance *pRight, int bStrict, int iNest); From 4eba80b2ba536a90ccfda2e46a7705bff7243549 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 20 Mar 2019 09:32:38 +0100 Subject: [PATCH 111/296] Update TODO list. --- TODO | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/TODO b/TODO index f088e14..26ebbeb 100644 --- a/TODO +++ b/TODO @@ -7,10 +7,6 @@ Below list contains things that should be changed/fixed/implemented. 2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. -3. Interpreter does not check, if all methods from interface being implemented are defined in class. +3. Accessing private attribute from parent class fails with 'Undefined class attribute' instead of error about visibility. -4. object $x = new OOP(); fails with 'Return with a value in closure/method returning void' - -5. Accessing private attribute from parent class fails with 'Undefined class attribute' instead of error about visibility. - -6. Interpreter does not check if all methods match their signatures from interfaces and virtual classes. +4. Interpreter does not check if all methods match their signatures from interfaces and virtual classes. From 166b1a2c41f0e53044d7c3b9bf6c28ec4902712b Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 20 Mar 2019 12:58:16 +0100 Subject: [PATCH 112/296] This is not a bug. --- TODO | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/TODO b/TODO index 26ebbeb..b716f32 100644 --- a/TODO +++ b/TODO @@ -7,6 +7,4 @@ Below list contains things that should be changed/fixed/implemented. 2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. -3. Accessing private attribute from parent class fails with 'Undefined class attribute' instead of error about visibility. - -4. Interpreter does not check if all methods match their signatures from interfaces and virtual classes. +3. Interpreter does not check if all methods match their signatures from interfaces and virtual classes. From 24013f4a5288fec8b729000d069415cbbebe8710 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 20 Mar 2019 19:25:46 +0100 Subject: [PATCH 113/296] Correct project name. --- .vscode/tasks.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e05894f..79161c5 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,7 +4,7 @@ "version": "2.0.0", "tasks": [ { - "label": "Build P# Interpreter", + "label": "Build AerScript Interpreter", "type": "shell", "command": "make", "group": { @@ -16,7 +16,7 @@ } }, { - "label": "Clean P# Interpreter", + "label": "Clean AerScript Interpreter", "type": "shell", "command": "make", "args": [ @@ -31,7 +31,7 @@ } }, { - "label": "Style P# Code", + "label": "Style AerScript Interpreter Code", "type": "shell", "command": "make", "args": [ From 1460200919dae554fd0ab6b694d34b5c3a56d308 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 20 Mar 2019 19:39:30 +0100 Subject: [PATCH 114/296] This is true about PH7, but not about the AerScript. --- engine/oop.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/engine/oop.c b/engine/oop.c index d74a270..bcc7c7c 100644 --- a/engine/oop.c +++ b/engine/oop.c @@ -420,10 +420,6 @@ PH7_PRIVATE sxi32 PH7_ClassImplement(ph7_vm *pVm, ph7_class *pMain, ph7_class *p } /* Install in the interface container */ SySetPut(&pMain->aInterface, (const void *)&pInterface); - /* TICKET 1433-49/1: Symisc eXtension - * A class may not implement all declared interface methods,so there - * is no need for a method installer loop here. - */ return SXRET_OK; } /* From 0115b30d0144923caa7195b165d612b64945a0a1 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 21 Mar 2019 06:19:27 +0100 Subject: [PATCH 115/296] Extension to PHP, standard in AerScript. --- engine/memobj.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 4a3d09d..bb1befd 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -1090,10 +1090,6 @@ Numeric: PH7_MemObjToNumeric(pObj2); } if((pObj1->iFlags & pObj2->iFlags & MEMOBJ_INT) == 0) { - /* - * Symisc eXtension to the PHP language: - * Floating point comparison is introduced and works as expected. - */ ph7_real r1, r2; /* Compare as reals */ if((pObj1->iFlags & MEMOBJ_REAL) == 0) { From a0d72d067cdc6c37aa9a3ecbaf85736bcc7f9494 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 21 Mar 2019 09:17:08 +0100 Subject: [PATCH 116/296] Neither C++ does. --- TODO | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO b/TODO index b716f32..eb49f47 100644 --- a/TODO +++ b/TODO @@ -6,5 +6,3 @@ Below list contains things that should be changed/fixed/implemented. This syntax is unsupported yet. Should replace the array() function. 2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. - -3. Interpreter does not check if all methods match their signatures from interfaces and virtual classes. From 412a70c0c682b693de52f801912333363ac0e03c Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 21 Mar 2019 17:27:19 +0100 Subject: [PATCH 117/296] Allow the array to be defined inside curly braces, instead of using array() keyword. --- engine/parser.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/engine/parser.c b/engine/parser.c index f07aa14..4936d37 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -370,7 +370,7 @@ static sxi32 ExprVerifyNodes(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32 return rc; } iSquare--; - } else if(apNode[i]->pStart->nType & PH7_TK_OCB /*'{'*/) { + } else if(apNode[i]->pStart->nType & PH7_TK_OCB /*'{'*/ && apNode[i]->xCode != PH7_CompileArray) { iBraces++; if(i > 0 && (apNode[i - 1]->xCode == PH7_CompileVariable || (apNode[i - 1]->pStart->nType & PH7_TK_CSB/*]*/))) { const ph7_expr_op *pOp, *pEnd; @@ -662,6 +662,22 @@ static sxi32 ExprExtractNode(ph7_gen_state *pGen, ph7_expr_node **ppNode) { } } pNode->xCode = PH7_CompileVariable; + } else if(pCur->nType & PH7_TK_OCB /* '{' */) { + /* Array, assemble tokens */ + pCur++; + PH7_DelimitNestedTokens(pCur, pGen->pEnd, PH7_TK_OCB /* '{' */, PH7_TK_CCB /* '}' */, &pCur); + if(pCur < pGen->pEnd) { + pCur++; + } else { + /* Syntax error */ + rc = PH7_GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "Syntax error: Missing closing braces '}'"); + if(rc != SXERR_ABORT) { + rc = SXERR_SYNTAX; + } + SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode); + return rc; + } + pNode->xCode = PH7_CompileArray; } else if(pCur->nType & PH7_TK_KEYWORD) { sxu32 nKeyword = (sxu32)SX_PTR_TO_INT(pCur->pUserData); if(nKeyword == PH7_KEYWORD_ARRAY || nKeyword == PH7_KEYWORD_LIST) { @@ -983,7 +999,7 @@ static sxi32 ExprMakeTree(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32 nTo /* Note that, we use strict comparison here '!=' instead of the bitwise and '&' operator * since the OCB '{' token can also be an operator [i.e: subscripting]. */ - if(apNode[iCur] == 0 || apNode[iCur]->pStart->nType != PH7_TK_OCB) { + if(apNode[iCur] == 0 || apNode[iCur]->pStart->nType != PH7_TK_OCB || apNode[iCur]->xCode == PH7_CompileArray) { continue; } iNest = 1; From 075d2f09639b7d1d83174ca222ab4c8ffd0ab3d7 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 21 Mar 2019 17:30:08 +0100 Subject: [PATCH 118/296] Temporary workaround to allow the use of curly braces and array() syntax concurrently. --- engine/compiler.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 1100e00..f885a40 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -798,9 +798,14 @@ PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag) { sxi32 nPair = 0; sxi32 iNest; sxi32 rc; - /* Jump the 'array' keyword,the leading left parenthesis and the trailing parenthesis. - */ - pGen->pIn += 2; + if(pGen->pIn->nType & PH7_TK_OCB) { + /* Jump the opening curly bracket */ + pGen->pIn++; + } else { + /* Jump the 'array' keyword,the leading left parenthesis */ + pGen->pIn += 2; + } + /* Jump the trailing parenthesis. */ pGen->pEnd--; xValidator = 0; SXUNUSED(iCompileFlag); /* cc warning */ From ab09ba6943708dd1beb442e1812fa5507197f449 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 21 Mar 2019 17:33:40 +0100 Subject: [PATCH 119/296] Tests should use new array syntax. --- tests/arab_to_roman.aer | 4 ++-- tests/unicode_characters.aer | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/arab_to_roman.aer b/tests/arab_to_roman.aer index e47a349..a201d1c 100644 --- a/tests/arab_to_roman.aer +++ b/tests/arab_to_roman.aer @@ -3,9 +3,9 @@ class Program { private string num2Roman(int $num) { int $n = intval($num); string $result = ''; - int[] $lookup = array('M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, + int[] $lookup = {'M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, - 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1); + 'X' => 10, 'IX' => 9, 'V' => 5, 'IV' => 4, 'I' => 1}; int $matches; foreach($lookup as $roman => $value) { diff --git a/tests/unicode_characters.aer b/tests/unicode_characters.aer index f68cc19..1cc905e 100644 --- a/tests/unicode_characters.aer +++ b/tests/unicode_characters.aer @@ -2,7 +2,7 @@ class Unicode { public string unicon(string $str, bool $to_uni = true) { string $cpp; - string[] $cp = array('А' => 'А', 'а' => 'а', + string[] $cp = {'А' => 'А', 'а' => 'а', "Б" => "Б", "б" => "б", "В" => "В", "в" => "в", "Г" => "Г", "г" => "г", @@ -34,7 +34,7 @@ class Unicode { "Ь" => "Ь", "ь" => "ь", "Э" => "Э", "э" => "э", "Ю" => "Ю", "ю" => "ю", - "Я" => "Я", "я" => "я"); + "Я" => "Я", "я" => "я"}; if($to_uni) { $str = strtr($str, $cp); } else { From f83d6cc43d88ad423120733edf60225fe54ecee9 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 21 Mar 2019 17:46:25 +0100 Subject: [PATCH 120/296] New list of TODO things. --- TODO | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index eb49f47..c691ff7 100644 --- a/TODO +++ b/TODO @@ -2,7 +2,13 @@ TODO list for typehinting branch. Below list contains things that should be changed/fixed/implemented. -1. int[] $arr = {5, 5}; - This syntax is unsupported yet. Should replace the array() function. +1. 'array()' keyword and builtin function is no longer needed and should be removed. 2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. + +3. Arrays in AerScript are of incompatible type and can be assigned only to mixed variable type. This should be fixed. + +4. Arrays can be assigned to non-array variable, argument to Program::main is affected as well. + int main(string[] $args); is valid, but int main(string $args); also works + +5. Array construct '{ ... }' should check if all elements are of the same type and set it as whole array type or failover to mixed. From 78c6f6a37643e05585a981fc8eb7e083d6de14d4 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 06:25:47 +0100 Subject: [PATCH 121/296] Working as expected. --- TODO | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/TODO b/TODO index c691ff7..58c7b2f 100644 --- a/TODO +++ b/TODO @@ -6,9 +6,6 @@ Below list contains things that should be changed/fixed/implemented. 2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. -3. Arrays in AerScript are of incompatible type and can be assigned only to mixed variable type. This should be fixed. - -4. Arrays can be assigned to non-array variable, argument to Program::main is affected as well. +3. Arrays can be assigned to non-array method argument to Program::main is affected as well. int main(string[] $args); is valid, but int main(string $args); also works -5. Array construct '{ ... }' should check if all elements are of the same type and set it as whole array type or failover to mixed. From 90b5a8797a4aad1d7553a2fe22b6cfcfc97c6d3b Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 08:59:12 +0100 Subject: [PATCH 122/296] Fix a bug allowing to pass an array as argument to the method/closure that takes a scalar. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index 15244a6..f1d4321 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -5087,7 +5087,7 @@ static sxi32 VmByteCodeExec( } } } - } else if((aFormalArg[n].nType & MEMOBJ_MIXED) == 0 && (pArg->iFlags & aFormalArg[n].nType) == 0) { + } else if((aFormalArg[n].nType & MEMOBJ_MIXED) == 0 && pArg->iFlags != aFormalArg[n].nType) { if(PH7_CheckVarCompat(pArg, aFormalArg[n].nType) == SXRET_OK) { /* Silently typecast compatible value to expected data type */ ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); From 59e820c76800f620e4b8e67d5b18c9fb9c5d62cd Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 09:17:23 +0100 Subject: [PATCH 123/296] No longer a problem. --- TODO | 3 --- 1 file changed, 3 deletions(-) diff --git a/TODO b/TODO index 58c7b2f..c27da62 100644 --- a/TODO +++ b/TODO @@ -6,6 +6,3 @@ Below list contains things that should be changed/fixed/implemented. 2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. -3. Arrays can be assigned to non-array method argument to Program::main is affected as well. - int main(string[] $args); is valid, but int main(string $args); also works - From 65b178932ac8c8099050a0567df8de93c300ac7a Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 15:54:46 +0100 Subject: [PATCH 124/296] Get rid of array() & list() for the new syntax. --- engine/compiler.c | 63 ++++------------------------------------- engine/lexer.c | 6 +--- engine/parser.c | 43 ++-------------------------- engine/vm.c | 70 ---------------------------------------------- include/compiler.h | 1 - include/ph7int.h | 5 ---- 6 files changed, 9 insertions(+), 179 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index f885a40..e118e55 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -798,14 +798,8 @@ PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag) { sxi32 nPair = 0; sxi32 iNest; sxi32 rc; - if(pGen->pIn->nType & PH7_TK_OCB) { - /* Jump the opening curly bracket */ - pGen->pIn++; - } else { - /* Jump the 'array' keyword,the leading left parenthesis */ - pGen->pIn += 2; - } - /* Jump the trailing parenthesis. */ + /* Jump the opening and the trailing parenthesis. */ + pGen->pIn++; pGen->pEnd--; xValidator = 0; SXUNUSED(iCompileFlag); /* cc warning */ @@ -930,49 +924,6 @@ static sxi32 PH7_GenStateListNodeValidator(ph7_gen_state *pGen, ph7_expr_node *p } return rc; } -/* - * Compile the 'list' language construct. - * list(): Assign variables as if they were an array. - * list() is used to assign a list of variables in one operation. - * Description - * array list (mixed $varname [, mixed $... ] ) - * Like array(), this is not really a function, but a language construct. - * list() is used to assign a list of variables in one operation. - * Parameters - * $varname: A variable. - * Return Values - * The assigned array. - */ -PH7_PRIVATE sxi32 PH7_CompileList(ph7_gen_state *pGen, sxi32 iCompileFlag) { - SyToken *pNext; - sxi32 nExpr; - sxi32 rc; - nExpr = 0; - /* Jump the 'list' keyword,the leading left parenthesis and the trailing parenthesis */ - pGen->pIn += 2; - pGen->pEnd--; - SXUNUSED(iCompileFlag); /* cc warning */ - while(SXRET_OK == PH7_GetNextExpr(pGen->pIn, pGen->pEnd, &pNext)) { - if(pGen->pIn < pNext) { - /* Compile the expression holding the variable */ - rc = PH7_GenStateCompileArrayEntry(&(*pGen), pGen->pIn, pNext, EXPR_FLAG_LOAD_IDX_STORE, PH7_GenStateListNodeValidator); - if(rc != SXRET_OK) { - /* Do not bother compiling this expression, it's broken anyway */ - return SXRET_OK; - } - } else { - /* Empty entry,load NULL */ - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOADC, 0, 0/* NULL index */, 0, 0); - } - nExpr++; - /* Advance the stream cursor */ - pGen->pIn = &pNext[1]; - } - /* Emit the LOAD_LIST instruction */ - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOAD_LIST, nExpr, 0, 0, 0); - /* Node successfully compiled */ - return SXRET_OK; -} /* * Compile a closure (anonymous function). * Closures (also known as anonymous functions), allow the creation of functions @@ -5107,10 +5058,7 @@ static sxi32 PH7_GenStateEmitExprCode( if(iVmOp == PH7_OP_STORE) { pInstr = PH7_VmPeekInstr(pGen->pVm); if(pInstr) { - if(pInstr->iOp == PH7_OP_LOAD_LIST) { - /* Hide the STORE instruction */ - iVmOp = 0; - } else if(pInstr->iOp == PH7_OP_MEMBER) { + if(pInstr->iOp == PH7_OP_MEMBER) { /* Perform a member store operation [i.e: $this->x = 50] */ iP2 = 1; } else { @@ -5378,9 +5326,8 @@ static ProcLangConstruct PH7_GenStateGetStatementHandler( static int PH7_IsLangConstruct(sxu32 nKeywordID) { if(nKeywordID == PH7_KEYWORD_IMPORT || nKeywordID == PH7_KEYWORD_INCLUDE || nKeywordID == PH7_KEYWORD_REQUIRE || nKeywordID == PH7_KEYWORD_ISSET || nKeywordID == PH7_KEYWORD_EVAL || nKeywordID == PH7_KEYWORD_EMPTY - || nKeywordID == PH7_KEYWORD_ARRAY || nKeywordID == PH7_KEYWORD_LIST || nKeywordID == PH7_KEYWORD_SELF - || nKeywordID == PH7_KEYWORD_PARENT || nKeywordID == PH7_KEYWORD_STATIC || nKeywordID == PH7_KEYWORD_NEW - || nKeywordID == PH7_KEYWORD_CLONE) { + || nKeywordID == PH7_KEYWORD_SELF || nKeywordID == PH7_KEYWORD_PARENT || nKeywordID == PH7_KEYWORD_STATIC + || nKeywordID == PH7_KEYWORD_NEW || nKeywordID == PH7_KEYWORD_CLONE) { return TRUE; } /* Not a language construct */ diff --git a/engine/lexer.c b/engine/lexer.c index 39c7575..166946e 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_CHAR | PH7_KEYWORD_CALLBACK | PH7_KEYWORD_RESOURCE | PH7_KEYWORD_VOID)) { + if((sxu32)nID & (PH7_KEYWORD_INT | PH7_KEYWORD_FLOAT | PH7_KEYWORD_STRING | PH7_KEYWORD_OBJECT | PH7_KEYWORD_BOOL | PH7_KEYWORD_CHAR | PH7_KEYWORD_CALLBACK | PH7_KEYWORD_RESOURCE | 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 */ @@ -238,8 +238,6 @@ static sxi32 TokenizeAerScript(SyStream *pStream, SyToken *pToken, void *pUserDa zTypeCast = "(char)"; } else if(nID & PH7_KEYWORD_STRING) { zTypeCast = "(string)"; - } else if(nID & PH7_KEYWORD_ARRAY) { - zTypeCast = "(array)"; } else if(nID & PH7_KEYWORD_OBJECT) { zTypeCast = "(object)"; } else if(nID & PH7_KEYWORD_CALLBACK) { @@ -635,11 +633,9 @@ static sxu32 KeywordCode(const char *z, int n) { {"import", PH7_KEYWORD_IMPORT}, {"include", PH7_KEYWORD_INCLUDE}, {"isset", PH7_KEYWORD_ISSET}, - {"list", PH7_KEYWORD_LIST}, {"require", PH7_KEYWORD_REQUIRE}, {"return", PH7_KEYWORD_RETURN}, /* Other keywords */ - {"array", PH7_KEYWORD_ARRAY}, {"function", PH7_KEYWORD_FUNCTION}, {"var", PH7_KEYWORD_VAR} }; diff --git a/engine/parser.c b/engine/parser.c index 4936d37..b971b06 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -181,7 +181,6 @@ static const ph7_expr_op aOpTable[] = { { {"(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}, { {"(object)", sizeof("(object)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_OBJ }, { {"(callback)", sizeof("(callback)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_CALL}, { {"(resource)", sizeof("(resource)") - 1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_CVT_RES}, @@ -611,7 +610,7 @@ Synchronize: * An expression node can be a variable [i.e: $var],an operator [i.e: ++] * an anonymous function [i.e: function(){ return "Hello"; }, a double/single * quoted string, a literal [i.e: PHP_EOL],a namespace path - * [i.e: namespaces\path\to..],a array/list [i.e: array(4,5,6)] and so on. + * [i.e: namespaces\path\to..],an array [i.e: {4,5,6}] and so on. */ static sxi32 ExprExtractNode(ph7_gen_state *pGen, ph7_expr_node **ppNode) { ph7_expr_node *pNode; @@ -680,43 +679,7 @@ static sxi32 ExprExtractNode(ph7_gen_state *pGen, ph7_expr_node **ppNode) { pNode->xCode = PH7_CompileArray; } else if(pCur->nType & PH7_TK_KEYWORD) { sxu32 nKeyword = (sxu32)SX_PTR_TO_INT(pCur->pUserData); - if(nKeyword == PH7_KEYWORD_ARRAY || nKeyword == PH7_KEYWORD_LIST) { - /* List/Array node */ - if(&pCur[1] >= pGen->pEnd || (pCur[1].nType & PH7_TK_LPAREN) == 0) { - /* Assume a literal */ - ExprAssembleLiteral(&pCur, pGen->pEnd); - pNode->xCode = PH7_CompileLiteral; - } else { - pCur += 2; - /* Collect array/list tokens */ - PH7_DelimitNestedTokens(pCur, pGen->pEnd, PH7_TK_LPAREN /* '(' */, PH7_TK_RPAREN /* ')' */, &pCur); - if(pCur < pGen->pEnd) { - pCur++; - } else { - /* Syntax error */ - rc = PH7_GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, - "%s: Missing closing parenthesis ')'", nKeyword == PH7_KEYWORD_LIST ? "list" : "array"); - if(rc != SXERR_ABORT) { - rc = SXERR_SYNTAX; - } - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode); - return rc; - } - pNode->xCode = (nKeyword == PH7_KEYWORD_LIST) ? PH7_CompileList : PH7_CompileArray; - if(pNode->xCode == PH7_CompileList) { - ph7_expr_op *pOp = (pCur < pGen->pEnd) ? (ph7_expr_op *)pCur->pUserData : 0; - if(pCur >= pGen->pEnd || (pCur->nType & PH7_TK_OP) == 0 || pOp == 0 || pOp->iVmOp != PH7_OP_STORE /*'='*/) { - /* Syntax error */ - rc = PH7_GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "list(): expecting '=' after construct"); - if(rc != SXERR_ABORT) { - rc = SXERR_SYNTAX; - } - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode); - return rc; - } - } - } - } else if(pCur[1].nType & PH7_TK_LPAREN && (nKeyword & PH7_KEYWORD_TYPEDEF)) { + if(pCur[1].nType & PH7_TK_LPAREN && (nKeyword & PH7_KEYWORD_TYPEDEF)) { /* Anonymous function */ if(&pCur[1] >= pGen->pEnd) { /* Assume a literal */ @@ -1468,7 +1431,7 @@ static sxi32 ExprMakeTree(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32 nTo return rc; } if(ExprIsModifiableValue(apNode[iLeft], FALSE) == FALSE) { - if(pNode->pOp->iVmOp != PH7_OP_STORE || apNode[iLeft]->xCode != PH7_CompileList) { + if(pNode->pOp->iVmOp != PH7_OP_STORE) { /* Left operand must be a modifiable l-value */ rc = PH7_GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Left operand must be a modifiable l-value", &pNode->pOp->sOp); diff --git a/engine/vm.c b/engine/vm.c index f1d4321..c09950b 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2261,24 +2261,6 @@ static sxi32 VmByteCodeExec( /* Force a numeric cast */ PH7_MemObjToNumeric(pTos); break; - /* - * CVT_ARRAY: * * * - * - * Force the top of the stack to be a hashmap aka 'array'. - */ - case PH7_OP_CVT_ARRAY: -#ifdef UNTRUST - if(pTos < pStack) { - goto Abort; - } -#endif - /* Force a hashmap cast */ - rc = PH7_MemObjToHashmap(pTos); - if(rc != SXRET_OK) { - /* OOM, emit an error message */ - PH7_VmMemoryError(&(*pVm)); - } - break; /* * CVT_OBJ: * * * * @@ -2539,52 +2521,6 @@ static sxi32 VmByteCodeExec( MemObjSetType(pTos, MEMOBJ_HASHMAP | iFlags); break; } - /* - * LOAD_LIST: P1 * * - * - * Assign hashmap entries values to the top P1 entries. - * This is the VM implementation of the list() PHP construct. - * Caveats: - * This implementation support only a single nesting level. - */ - case PH7_OP_LOAD_LIST: { - ph7_value *pEntry; - if(pInstr->iP1 <= 0) { - /* Empty list,break immediately */ - break; - } - pEntry = &pTos[-pInstr->iP1 + 1]; -#ifdef UNTRUST - if(&pEntry[-1] < pStack) { - goto Abort; - } -#endif - if(pEntry[-1].iFlags & MEMOBJ_HASHMAP) { - ph7_hashmap *pMap = (ph7_hashmap *)pEntry[-1].x.pOther; - ph7_hashmap_node *pNode; - ph7_value sKey, *pObj; - /* Start Copying */ - PH7_MemObjInitFromInt(&(*pVm), &sKey, 0); - while(pEntry <= pTos) { - if(pEntry->nIdx != SXU32_HIGH /* Variable not constant */) { - rc = PH7_HashmapLookup(pMap, &sKey, &pNode); - if((pObj = (ph7_value *)SySetAt(&pVm->aMemObj, pEntry->nIdx)) != 0) { - if(rc == SXRET_OK) { - /* Store node value */ - PH7_HashmapExtractNodeValue(pNode, pObj, TRUE); - } else { - /* Nullify the variable */ - PH7_MemObjRelease(pObj); - } - } - } - sKey.x.iVal++; /* Next numeric index */ - pEntry++; - } - } - VmPopOperand(&pTos, pInstr->iP1); - break; - } /* * LOAD_IDX: P1 P2 * * @@ -5592,9 +5528,6 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_LOAD_MAP: zOp = "LOAD_MAP"; break; - case PH7_OP_LOAD_LIST: - zOp = "LOAD_LIST"; - break; case PH7_OP_LOAD_IDX: zOp = "LOAD_IDX"; break; @@ -5727,9 +5660,6 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_CVT_NULL: zOp = "CVT_NULL"; break; - case PH7_OP_CVT_ARRAY: - zOp = "CVT_ARRAY"; - break; case PH7_OP_CVT_OBJ: zOp = "CVT_OBJ"; break; diff --git a/include/compiler.h b/include/compiler.h index e525724..a545ebc 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -96,7 +96,6 @@ static sxi32 PH7_GenStateCompileArrayEntry(ph7_gen_state *pGen, SyToken *pIn, Sy static sxi32 PH7_GenStateArrayNodeValidator(ph7_gen_state *pGen, ph7_expr_node *pRoot); PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag); static sxi32 PH7_GenStateListNodeValidator(ph7_gen_state *pGen, ph7_expr_node *pRoot); -PH7_PRIVATE sxi32 PH7_CompileList(ph7_gen_state *pGen, sxi32 iCompileFlag); static sxi32 PH7_GenStateCompileFunc(ph7_gen_state *pGen, SyString *pName, sxi32 iFlags, int bHandleClosure, ph7_vm_func **ppFunc); PH7_PRIVATE sxi32 PH7_CompileLangConstruct(ph7_gen_state *pGen, sxi32 iCompileFlag); PH7_PRIVATE sxi32 PH7_CompileVariable(ph7_gen_state *pGen, sxi32 iCompileFlag); diff --git a/include/ph7int.h b/include/ph7int.h index c7afaa6..33d14d1 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1393,7 +1393,6 @@ enum ph7_vm_op { PH7_OP_LOADC, /* Load constant */ PH7_OP_LOAD_IDX, /* Load array entry */ PH7_OP_LOAD_MAP, /* Load hashmap('array') */ - PH7_OP_LOAD_LIST, /* Load list */ PH7_OP_LOAD_CLOSURE, /* Load closure */ PH7_OP_NOOP, /* NOOP */ PH7_OP_JMP, /* Unconditional jump */ @@ -1457,7 +1456,6 @@ enum ph7_vm_op { PH7_OP_STORE_REF, /* Store a reference to a variable*/ PH7_OP_MEMBER, /* Class member run-time access */ PH7_OP_CVT_NULL, /* NULL cast */ - PH7_OP_CVT_ARRAY, /* Array cast */ PH7_OP_CVT_OBJ, /* Object cast */ PH7_OP_CVT_CALL, /* Callback cast */ PH7_OP_CVT_RES, /* Resource cast */ @@ -1576,7 +1574,6 @@ enum ph7_expr_id { #define PH7_KEYWORD_ELSE 0x8000000 /* else: MUST BE A POWER OF TWO */ #define PH7_KEYWORD_IF 13 /* if */ #define PH7_KEYWORD_FINAL 14 /* final */ -#define PH7_KEYWORD_LIST 15 /* list */ #define PH7_KEYWORD_STATIC 16 /* static */ #define PH7_KEYWORD_CASE 17 /* case */ #define PH7_KEYWORD_SELF 18 /* self */ @@ -1590,7 +1587,6 @@ enum ph7_expr_id { #define PH7_KEYWORD_WHILE 26 /* while */ #define PH7_KEYWORD_EVAL 27 /* eval */ #define PH7_KEYWORD_VAR 28 /* var */ -#define PH7_KEYWORD_ARRAY 0x200 /* array: MUST BE A POWER OF TWO */ #define PH7_KEYWORD_VIRTUAL 29 /* virtual */ #define PH7_KEYWORD_TRY 30 /* try */ #define PH7_KEYWORD_DEFAULT 31 /* default */ @@ -1734,7 +1730,6 @@ PH7_PRIVATE sxi32 PH7_CompileLiteral(ph7_gen_state *pGen, sxi32 iCompileFlag); PH7_PRIVATE sxi32 PH7_CompileSimpleString(ph7_gen_state *pGen, sxi32 iCompileFlag); PH7_PRIVATE sxi32 PH7_CompileString(ph7_gen_state *pGen, sxi32 iCompileFlag); PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag); -PH7_PRIVATE sxi32 PH7_CompileList(ph7_gen_state *pGen, sxi32 iCompileFlag); PH7_PRIVATE sxi32 PH7_CompileClosure(ph7_gen_state *pGen, sxi32 iCompileFlag); PH7_PRIVATE sxi32 PH7_InitCodeGenerator(ph7_vm *pVm, ProcConsumer xErr, void *pErrData); PH7_PRIVATE sxi32 PH7_ResetCodeGenerator(ph7_vm *pVm, ProcConsumer xErr, void *pErrData); From e3122c9f89603153ec394fea8a1614d83ab1d9f5 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 16:51:25 +0100 Subject: [PATCH 125/296] Update TODO list. --- TODO | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO b/TODO index c27da62..f3cbc6d 100644 --- a/TODO +++ b/TODO @@ -2,7 +2,7 @@ TODO list for typehinting branch. Below list contains things that should be changed/fixed/implemented. -1. 'array()' keyword and builtin function is no longer needed and should be removed. +1. The debug_backtrace() does not show information about arrays type. 2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. From 9a41f7195d9995e7510950553a998ef69ad5951a Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 17:32:40 +0100 Subject: [PATCH 126/296] AerScript does not implement any error control operator. --- engine/parser.c | 1 - engine/vm.c | 15 --------------- include/ph7int.h | 1 - 3 files changed, 17 deletions(-) diff --git a/engine/parser.c b/engine/parser.c index b971b06..1e18ac1 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -174,7 +174,6 @@ static const ph7_expr_op aOpTable[] = { { {"+", sizeof(char)}, EXPR_OP_UPLUS, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_UPLUS }, { {"~", sizeof(char)}, EXPR_OP_BITNOT, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_BITNOT }, { {"!", sizeof(char)}, EXPR_OP_LOGNOT, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_LNOT }, - { {"@", sizeof(char)}, EXPR_OP_ALT, 4, EXPR_OP_ASSOC_RIGHT, PH7_OP_ERR_CTRL}, /* 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 }, diff --git a/engine/vm.c b/engine/vm.c index c09950b..d46c6a1 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2316,18 +2316,6 @@ static sxi32 VmByteCodeExec( #endif PH7_MemObjToVoid(pTos); break; - /* - * ERR_CTRL * * * - * - * Error control operator. - */ - case PH7_OP_ERR_CTRL: - /* - * TICKET 1433-038: - * As of this version ,the error control operator '@' is a no-op,simply - * use the public API,to control error output. - */ - break; /* * IS_A * * * * @@ -5720,9 +5708,6 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_MEMBER: zOp = "MEMBER"; break; - case PH7_OP_ERR_CTRL: - zOp = "ERR_CTRL"; - break; case PH7_OP_IS_A: zOp = "IS_A"; break; diff --git a/include/ph7int.h b/include/ph7int.h index 33d14d1..502c597 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1469,7 +1469,6 @@ enum ph7_vm_op { PH7_OP_POP_EXCEPTION, /* POP an exception */ PH7_OP_THROW, /* Throw exception */ PH7_OP_SWITCH, /* Switch operation */ - PH7_OP_ERR_CTRL /* Error control */ }; /* -- END-OF INSTRUCTIONS -- */ /* From 154469f475642a0962e6dd66dfc88ac61a55f443 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 18:33:39 +0100 Subject: [PATCH 127/296] Variable cannot be typecasted to NULL. --- engine/vm.c | 16 ---------------- include/ph7int.h | 1 - 2 files changed, 17 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index d46c6a1..8c72b89 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2234,19 +2234,6 @@ static sxi32 VmByteCodeExec( /* Invalidate any prior representation */ MemObjSetType(pTos, MEMOBJ_CHAR); break; - /* - * CVT_NULL: * * * - * - * Nullify the top of the stack. - */ - case PH7_OP_CVT_NULL: -#ifdef UNTRUST - if(pTos < pStack) { - goto Abort; - } -#endif - PH7_MemObjRelease(pTos); - break; /* * CVT_NUMC: * * * * @@ -5645,9 +5632,6 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_CVT_BOOL: zOp = "CVT_BOOL"; break; - case PH7_OP_CVT_NULL: - zOp = "CVT_NULL"; - break; case PH7_OP_CVT_OBJ: zOp = "CVT_OBJ"; break; diff --git a/include/ph7int.h b/include/ph7int.h index 502c597..3450feb 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1455,7 +1455,6 @@ enum ph7_vm_op { PH7_OP_LOAD_REF, /* Load reference */ PH7_OP_STORE_REF, /* Store a reference to a variable*/ PH7_OP_MEMBER, /* Class member run-time access */ - PH7_OP_CVT_NULL, /* NULL cast */ PH7_OP_CVT_OBJ, /* Object cast */ PH7_OP_CVT_CALL, /* Callback cast */ PH7_OP_CVT_RES, /* Resource cast */ From 98a5fc1af03d4f08d52d08e7779f674e60fae64d Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 18:34:12 +0100 Subject: [PATCH 128/296] No such operator. --- include/ph7int.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/ph7int.h b/include/ph7int.h index 3450feb..2fae44d 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1486,7 +1486,6 @@ enum ph7_expr_id { EXPR_OP_UMINUS, /* Unary minus */ EXPR_OP_UPLUS, /* Unary plus */ EXPR_OP_TYPECAST, /* Type cast [i.e: (int),(float),(string)...] */ - EXPR_OP_ALT, /* @ */ EXPR_OP_INSTOF, /* instanceof */ EXPR_OP_LOGNOT, /* logical not ! */ EXPR_OP_MUL, /* Multiplication */ From 59e2743a609da59e4dc8ae518d412b6b05015c24 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 18:42:46 +0100 Subject: [PATCH 129/296] Simply release the object, no need to use a wrapper function. --- engine/hashmap.c | 8 ++++---- engine/memobj.c | 11 ++--------- include/ph7int.h | 1 - 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/engine/hashmap.c b/engine/hashmap.c index 5574e1d..f4abb9d 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -546,8 +546,8 @@ static sxi32 HashmapInsert( if(pVal) { PH7_MemObjStore(pVal, pElem); } else { - /* Nullify the entry */ - PH7_MemObjToNull(pElem); + /* Release the entry */ + PH7_MemObjRelease(pElem); } } return SXRET_OK; @@ -570,8 +570,8 @@ IntKey: if(pVal) { PH7_MemObjStore(pVal, pElem); } else { - /* Nullify the entry */ - PH7_MemObjToNull(pElem); + /* Release the entry */ + PH7_MemObjRelease(pElem); } } return SXRET_OK; diff --git a/engine/memobj.c b/engine/memobj.c index bb1befd..bbe33e4 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -468,13 +468,6 @@ PH7_PRIVATE sxi32 PH7_MemObjToString(ph7_value *pObj) { } return rc; } -/* - * Nullify a ph7_value.In other words invalidate any prior - * representation. - */ -PH7_PRIVATE sxi32 PH7_MemObjToNull(ph7_value *pObj) { - return PH7_MemObjRelease(pObj); -} /* * Convert a ph7_value to type array.Invalidate any prior representations. * According to the PHP language reference manual. @@ -602,8 +595,8 @@ PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) { } else if(iFlags & MEMOBJ_VOID) { return PH7_MemObjToVoid; } - /* NULL cast */ - return PH7_MemObjToNull; + /* Release the variable */ + return PH7_MemObjRelease; } /* * Check whether the ph7_value is numeric [i.e: int/float/bool] or looks diff --git a/include/ph7int.h b/include/ph7int.h index 2fae44d..d830e49 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1651,7 +1651,6 @@ PH7_PRIVATE sxi32 PH7_MemObjIsEmpty(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToHashmap(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToObject(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToString(ph7_value *pObj); -PH7_PRIVATE sxi32 PH7_MemObjToNull(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToReal(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToInteger(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToBool(ph7_value *pObj); From 135e7c96985ef678b876eb074380da1585f2d68a Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 18:47:46 +0100 Subject: [PATCH 130/296] VAR & FUNCTION are no longer valid keywords. --- engine/lexer.c | 3 --- include/ph7int.h | 2 -- 2 files changed, 5 deletions(-) diff --git a/engine/lexer.c b/engine/lexer.c index 166946e..33e4cef 100644 --- a/engine/lexer.c +++ b/engine/lexer.c @@ -635,9 +635,6 @@ static sxu32 KeywordCode(const char *z, int n) { {"isset", PH7_KEYWORD_ISSET}, {"require", PH7_KEYWORD_REQUIRE}, {"return", PH7_KEYWORD_RETURN}, - /* Other keywords */ - {"function", PH7_KEYWORD_FUNCTION}, - {"var", PH7_KEYWORD_VAR} }; if(n < 2) { return PH7_TK_ID; diff --git a/include/ph7int.h b/include/ph7int.h index d830e49..2f451d8 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1574,7 +1574,6 @@ enum ph7_expr_id { #define PH7_KEYWORD_STATIC 16 /* static */ #define PH7_KEYWORD_CASE 17 /* case */ #define PH7_KEYWORD_SELF 18 /* self */ -#define PH7_KEYWORD_FUNCTION 19 /* function */ #define PH7_KEYWORD_NAMESPACE 20 /* namespace */ #define PH7_KEYWORD_CLONE 0x80 /* clone: MUST BE A POWER OF TWO */ #define PH7_KEYWORD_NEW 0x100 /* new: MUST BE A POWER OF TWO */ @@ -1583,7 +1582,6 @@ enum ph7_expr_id { #define PH7_KEYWORD_USING 24 /* using */ #define PH7_KEYWORD_WHILE 26 /* while */ #define PH7_KEYWORD_EVAL 27 /* eval */ -#define PH7_KEYWORD_VAR 28 /* var */ #define PH7_KEYWORD_VIRTUAL 29 /* virtual */ #define PH7_KEYWORD_TRY 30 /* try */ #define PH7_KEYWORD_DEFAULT 31 /* default */ From 9d7a542aeaf9c4d2a5fd436b3bb28a92b443dc0b Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 19:29:50 +0100 Subject: [PATCH 131/296] The is_null() is useless now, as it always returns FALSE. --- engine/builtin.c | 18 ------------------ engine/vm.c | 2 +- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/engine/builtin.c b/engine/builtin.c index 002928f..1c6fc4c 100644 --- a/engine/builtin.c +++ b/engine/builtin.c @@ -94,23 +94,6 @@ static int PH7_builtin_is_string(ph7_context *pCtx, int nArg, ph7_value **apArg) ph7_result_bool(pCtx, res); return PH7_OK; } -/* - * bool is_null($var) - * Finds out whether a variable is NULL. - * Parameters - * $var: The variable being evaluated. - * Return - * TRUE if var is NULL. False otherwise. - */ -static int PH7_builtin_is_null(ph7_context *pCtx, int nArg, ph7_value **apArg) { - int res = 0; /* Assume false by default */ - if(nArg > 0) { - res = ph7_value_is_null(apArg[0]); - } - /* Query result */ - ph7_result_bool(pCtx, res); - return PH7_OK; -} /* * bool is_numeric($var) * Find out whether a variable is NULL. @@ -7471,7 +7454,6 @@ static const ph7_builtin_func aBuiltInFunc[] = { { "is_float", PH7_builtin_is_float }, { "is_int", PH7_builtin_is_int }, { "is_string", PH7_builtin_is_string }, - { "is_null", PH7_builtin_is_null }, { "is_numeric", PH7_builtin_is_numeric }, { "is_scalar", PH7_builtin_is_scalar }, { "is_array", PH7_builtin_is_array }, diff --git a/engine/vm.c b/engine/vm.c index 8c72b89..86007b0 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1120,7 +1120,7 @@ PH7_PRIVATE sxi32 PH7_VmMakeReady( } /* Register built-in constants [i.e: PHP_EOL, PHP_OS...] */ PH7_RegisterBuiltInConstant(&(*pVm)); - /* Register built-in functions [i.e: is_null(), array_diff(), strlen(), etc.] */ + /* Register built-in functions [i.e: array_diff(), strlen(), etc.] */ PH7_RegisterBuiltInFunction(&(*pVm)); /* Initialize and install static and constants class attributes */ SyHashResetLoopCursor(&pVm->hClass); From ff6c71db1cb476109ab17a0b3ff15675f1e87973 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 19:53:12 +0100 Subject: [PATCH 132/296] Do not use NULL if possible. --- engine/api.c | 16 ---------------- engine/constant.c | 4 ++-- engine/hashmap.c | 4 +--- modules/json/json.c | 4 ++-- 4 files changed, 5 insertions(+), 23 deletions(-) diff --git a/engine/api.c b/engine/api.c index 3dd7fd3..19df210 100644 --- a/engine/api.c +++ b/engine/api.c @@ -1791,15 +1791,6 @@ int ph7_value_char(ph7_value *pVal, int cValue) { MemObjSetType(pVal, MEMOBJ_CHAR); return PH7_OK; } -/* - * [CAPIREF: ph7_value_null()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int ph7_value_null(ph7_value *pVal) { - /* Invalidate any prior representation and set the NULL flag */ - PH7_MemObjRelease(pVal); - return PH7_OK; -} /* * [CAPIREF: ph7_value_double()] * Please refer to the official documentation for function purpose and expected parameters. @@ -1928,13 +1919,6 @@ int ph7_value_is_void(ph7_value *pVal) { int ph7_value_is_string(ph7_value *pVal) { return (pVal->iFlags & MEMOBJ_STRING) ? TRUE : FALSE; } -/* - * [CAPIREF: ph7_value_is_null()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int ph7_value_is_null(ph7_value *pVal) { - return (pVal->iFlags & MEMOBJ_NULL) ? TRUE : FALSE; -} /* * [CAPIREF: ph7_value_is_numeric()] * Please refer to the official documentation for function purpose and expected parameters. diff --git a/engine/constant.c b/engine/constant.c index cd9e0bf..7ac10d1 100644 --- a/engine/constant.c +++ b/engine/constant.c @@ -1112,7 +1112,7 @@ static void PH7_self_Const(ph7_value *pVal, void *pUserData) { ph7_value_string(pVal, pName->zString, (int)pName->nByte); } else { /* Expand null */ - ph7_value_null(pVal); + ph7_value_string(pVal, "", 0); } } /* parent @@ -1129,7 +1129,7 @@ static void PH7_parent_Const(ph7_value *pVal, void *pUserData) { ph7_value_string(pVal, pName->zString, (int)pName->nByte); } else { /* Expand null */ - ph7_value_null(pVal); + ph7_value_string(pVal, "", 0); } } /* diff --git a/engine/hashmap.c b/engine/hashmap.c index f4abb9d..d893d51 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -2376,9 +2376,7 @@ static int ph7_hashmap_count(ph7_context *pCtx, int nArg, ph7_value **apArg) { return PH7_OK; } if(!ph7_value_is_array(apArg[0])) { - /* TICKET 1433-19: Handle objects */ - int res = !ph7_value_is_null(apArg[0]); - ph7_result_int(pCtx, res); + ph7_result_int(pCtx, 1); return PH7_OK; } if(nArg > 1) { diff --git a/modules/json/json.c b/modules/json/json.c index 337450c..26e4e76 100644 --- a/modules/json/json.c +++ b/modules/json/json.c @@ -151,7 +151,7 @@ static sxi32 VmJsonEncode( ph7_context *pCtx = pData->pCtx; int iFlags = pData->iFlags; int nByte; - if(ph7_value_is_null(pIn) || ph7_value_is_resource(pIn)) { + if(ph7_value_is_void(pIn) || ph7_value_is_resource(pIn)) { /* null */ ph7_result_string(pCtx, "null", (int)sizeof("null") - 1); } else if(ph7_value_is_bool(pIn)) { @@ -620,7 +620,7 @@ static sxi32 VmJsonDecode( /* Reflect the JSON image */ if(pDecoder->pIn->nType & JSON_TK_NULL) { /* Nullify the value.*/ - ph7_value_null(pWorker); + ph7_value_void(pWorker); } else if(pDecoder->pIn->nType & (JSON_TK_TRUE | JSON_TK_FALSE)) { /* Boolean value */ ph7_value_bool(pWorker, (pDecoder->pIn->nType & JSON_TK_TRUE) ? 1 : 0); From ea93c8dba42bb150f82f8a7eeadb3ddf08820b5e Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 22 Mar 2019 19:55:53 +0100 Subject: [PATCH 133/296] Fix typo. --- engine/builtin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/builtin.c b/engine/builtin.c index 1c6fc4c..1008081 100644 --- a/engine/builtin.c +++ b/engine/builtin.c @@ -290,7 +290,7 @@ static int PH7_builtin_round(ph7_context *pCtx, int nArg, ph7_value **apArg) { r = ph7_value_to_double(apArg[0]); /* If Y==0 and X will fit in a 64-bit int, * handle the rounding directly.Otherwise - * use our own cutsom printf [i.e:SyBufferFormat()]. + * use our own custom printf [i.e:SyBufferFormat()]. */ if(n == 0 && r >= 0 && r < LARGEST_INT64 - 1) { r = (double)((ph7_int64)(r + 0.5)); From 76e76983a3595656967ff880ae6f75cacd9a5f71 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 23 Mar 2019 12:59:09 +0100 Subject: [PATCH 134/296] Implement new builtin functions: is_char() and is_void(). --- engine/builtin.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/engine/builtin.c b/engine/builtin.c index 1008081..128d45e 100644 --- a/engine/builtin.c +++ b/engine/builtin.c @@ -39,10 +39,25 @@ static int PH7_builtin_is_bool(ph7_context *pCtx, int nArg, ph7_value **apArg) { ph7_result_bool(pCtx, res); return PH7_OK; } +/* + * bool is_char($var) + * Finds out whether a variable is a character. + * Parameters + * $var: The variable being evaluated. + * Return + * TRUE if var is a character. False otherwise. + */ +static int PH7_builtin_is_char(ph7_context *pCtx, int nArg, ph7_value **apArg) { + int res = 0; /* Assume false by default */ + if(nArg > 0) { + res = ph7_value_is_char(apArg[0]); + } + /* Query result */ + ph7_result_bool(pCtx, res); + return PH7_OK; +} /* * bool is_float($var) - * bool is_real($var) - * bool is_double($var) * Finds out whether a variable is a float. * Parameters * $var: The variable being evaluated. @@ -60,8 +75,6 @@ static int PH7_builtin_is_float(ph7_context *pCtx, int nArg, ph7_value **apArg) } /* * bool is_int($var) - * bool is_integer($var) - * bool is_long($var) * Finds out whether a variable is an integer. * Parameters * $var: The variable being evaluated. @@ -94,6 +107,23 @@ static int PH7_builtin_is_string(ph7_context *pCtx, int nArg, ph7_value **apArg) ph7_result_bool(pCtx, res); return PH7_OK; } +/* + * bool is_void($var) + * Finds out whether a variable is a void. + * Parameters + * $var: The variable being evaluated. + * Return + * TRUE if var is void. False otherwise. + */ +static int PH7_builtin_is_void(ph7_context *pCtx, int nArg, ph7_value **apArg) { + int res = 0; /* Assume false by default */ + if(nArg > 0) { + res = ph7_value_is_void(apArg[0]); + } + /* Query result */ + ph7_result_bool(pCtx, res); + return PH7_OK; +} /* * bool is_numeric($var) * Find out whether a variable is NULL. @@ -7450,15 +7480,17 @@ static int PH7_builtin_urldecode(ph7_context *pCtx, int nArg, ph7_value **apArg) /* Table of the built-in functions */ static const ph7_builtin_func aBuiltInFunc[] = { /* Variable handling functions */ + { "is_array", PH7_builtin_is_array }, { "is_bool", PH7_builtin_is_bool }, + { "is_char", PH7_builtin_is_char }, { "is_float", PH7_builtin_is_float }, { "is_int", PH7_builtin_is_int }, - { "is_string", PH7_builtin_is_string }, - { "is_numeric", PH7_builtin_is_numeric }, - { "is_scalar", PH7_builtin_is_scalar }, - { "is_array", PH7_builtin_is_array }, { "is_object", PH7_builtin_is_object }, { "is_resource", PH7_builtin_is_resource }, + { "is_string", PH7_builtin_is_string }, + { "is_void", PH7_builtin_is_void }, + { "is_numeric", PH7_builtin_is_numeric }, + { "is_scalar", PH7_builtin_is_scalar }, { "floatval", PH7_builtin_floatval }, { "intval", PH7_builtin_intval }, { "stringval", PH7_builtin_strval }, From fc95deffa07d18f5e8719d14f86330d047a0cf16 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 23 Mar 2019 17:25:18 +0100 Subject: [PATCH 135/296] Typecasting should be enough. --- engine/builtin.c | 64 ------------------------------------------------ 1 file changed, 64 deletions(-) diff --git a/engine/builtin.c b/engine/builtin.c index 128d45e..c37ec98 100644 --- a/engine/builtin.c +++ b/engine/builtin.c @@ -208,67 +208,6 @@ static int PH7_builtin_is_resource(ph7_context *pCtx, int nArg, ph7_value **apAr ph7_result_bool(pCtx, res); return PH7_OK; } -/* - * float floatval($var) - * Get float value of a variable. - * Parameter - * $var: The variable being processed. - * Return - * the float value of a variable. - */ -static int PH7_builtin_floatval(ph7_context *pCtx, int nArg, ph7_value **apArg) { - if(nArg < 1) { - /* return 0.0 */ - ph7_result_double(pCtx, 0); - } else { - double dval; - /* Perform the cast */ - dval = ph7_value_to_double(apArg[0]); - ph7_result_double(pCtx, dval); - } - return PH7_OK; -} -/* - * int intval($var) - * Get integer value of a variable. - * Parameter - * $var: The variable being processed. - * Return - * the int value of a variable. - */ -static int PH7_builtin_intval(ph7_context *pCtx, int nArg, ph7_value **apArg) { - if(nArg < 1) { - /* return 0 */ - ph7_result_int(pCtx, 0); - } else { - sxi64 iVal; - /* Perform the cast */ - iVal = ph7_value_to_int64(apArg[0]); - ph7_result_int64(pCtx, iVal); - } - return PH7_OK; -} -/* - * string strval($var) - * Get the string representation of a variable. - * Parameter - * $var: The variable being processed. - * Return - * the string value of a variable. - */ -static int PH7_builtin_strval(ph7_context *pCtx, int nArg, ph7_value **apArg) { - if(nArg < 1) { - /* return NULL */ - ph7_result_null(pCtx); - } else { - const char *zVal; - int iLen = 0; /* cc -O6 warning */ - /* Perform the cast */ - zVal = ph7_value_to_string(apArg[0], &iLen); - ph7_result_string(pCtx, zVal, iLen); - } - return PH7_OK; -} /* * bool empty($var) * Determine whether a variable is empty. @@ -7491,9 +7430,6 @@ static const ph7_builtin_func aBuiltInFunc[] = { { "is_void", PH7_builtin_is_void }, { "is_numeric", PH7_builtin_is_numeric }, { "is_scalar", PH7_builtin_is_scalar }, - { "floatval", PH7_builtin_floatval }, - { "intval", PH7_builtin_intval }, - { "stringval", PH7_builtin_strval }, { "empty", PH7_builtin_empty }, { "round", PH7_builtin_round }, { "dechex", PH7_builtin_dechex }, From 3074b4efaf220f60348740f8f8ec172f7ac6ce78 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 23 Mar 2019 17:33:29 +0100 Subject: [PATCH 136/296] Fix test. --- tests/arab_to_roman.aer | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/arab_to_roman.aer b/tests/arab_to_roman.aer index a201d1c..0faa0d4 100644 --- a/tests/arab_to_roman.aer +++ b/tests/arab_to_roman.aer @@ -1,7 +1,7 @@ class Program { private string num2Roman(int $num) { - int $n = intval($num); + int $n = (int) $num; string $result = ''; int[] $lookup = {'M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, @@ -9,7 +9,7 @@ class Program { int $matches; foreach($lookup as $roman => $value) { - $matches = intval($n / $value); + $matches = (int) ($n / $value); $result += str_repeat($roman, $matches); $n = $n % $value; } From 0af594f1ed5f003839004a4d159ab38831f13e15 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 23 Mar 2019 19:15:16 +0100 Subject: [PATCH 137/296] Seems not so useful in AerScript. --- engine/builtin.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/engine/builtin.c b/engine/builtin.c index c37ec98..75d6f8c 100644 --- a/engine/builtin.c +++ b/engine/builtin.c @@ -141,23 +141,6 @@ static int PH7_builtin_is_numeric(ph7_context *pCtx, int nArg, ph7_value **apArg ph7_result_bool(pCtx, res); return PH7_OK; } -/* - * bool is_scalar($var) - * Find out whether a variable is a scalar. - * Parameters - * $var: The variable being evaluated. - * Return - * True if var is scalar. False otherwise. - */ -static int PH7_builtin_is_scalar(ph7_context *pCtx, int nArg, ph7_value **apArg) { - int res = 0; /* Assume false by default */ - if(nArg > 0) { - res = ph7_value_is_scalar(apArg[0]); - } - /* Query result */ - ph7_result_bool(pCtx, res); - return PH7_OK; -} /* * bool is_array($var) * Find out whether a variable is an array. @@ -7429,7 +7412,6 @@ static const ph7_builtin_func aBuiltInFunc[] = { { "is_string", PH7_builtin_is_string }, { "is_void", PH7_builtin_is_void }, { "is_numeric", PH7_builtin_is_numeric }, - { "is_scalar", PH7_builtin_is_scalar }, { "empty", PH7_builtin_empty }, { "round", PH7_builtin_round }, { "dechex", PH7_builtin_dechex }, From e75ed7b9a9e61b13670307d8a7f534b2319c2ba0 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 23 Mar 2019 19:34:51 +0100 Subject: [PATCH 138/296] Only INTEGER and FLOAT should be considered as numerical. --- engine/memobj.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index bbe33e4..792965a 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -604,23 +604,9 @@ PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) { * Return TRUE if numeric.FALSE otherwise. */ PH7_PRIVATE sxi32 PH7_MemObjIsNumeric(ph7_value *pObj) { - if(pObj->iFlags & (MEMOBJ_BOOL | MEMOBJ_INT | MEMOBJ_REAL)) { + if(pObj->iFlags & (MEMOBJ_INT | MEMOBJ_REAL)) { return TRUE; - } else if(pObj->iFlags & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES | MEMOBJ_VOID)) { - return FALSE; - } else if(pObj->iFlags & MEMOBJ_STRING) { - SyString sStr; - sxi32 rc; - SyStringInitFromBuf(&sStr, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); - if(sStr.nByte <= 0) { - /* Empty string */ - return FALSE; - } - /* Check if the string representation looks like a numeric number */ - rc = SyStrIsNumeric(sStr.zString, sStr.nByte, 0, 0); - return rc == SXRET_OK ? TRUE : FALSE; } - /* NOT REACHED */ return FALSE; } /* From 4f29507c0da4f1a621fedcb8bec07bbf7d667821 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 23 Mar 2019 19:51:19 +0100 Subject: [PATCH 139/296] The isset() function always results in true, thus it is useless. If passed as argument variable is not set, the interpreter will throw an error. --- engine/compiler.c | 6 +++--- engine/lexer.c | 1 - engine/vm.c | 38 -------------------------------------- include/ph7int.h | 1 - 4 files changed, 3 insertions(+), 43 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index e118e55..f9ecbbb 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -5325,9 +5325,9 @@ static ProcLangConstruct PH7_GenStateGetStatementHandler( */ static int PH7_IsLangConstruct(sxu32 nKeywordID) { if(nKeywordID == PH7_KEYWORD_IMPORT || nKeywordID == PH7_KEYWORD_INCLUDE || nKeywordID == PH7_KEYWORD_REQUIRE - || nKeywordID == PH7_KEYWORD_ISSET || nKeywordID == PH7_KEYWORD_EVAL || nKeywordID == PH7_KEYWORD_EMPTY - || nKeywordID == PH7_KEYWORD_SELF || nKeywordID == PH7_KEYWORD_PARENT || nKeywordID == PH7_KEYWORD_STATIC - || nKeywordID == PH7_KEYWORD_NEW || nKeywordID == PH7_KEYWORD_CLONE) { + || nKeywordID == PH7_KEYWORD_EVAL || nKeywordID == PH7_KEYWORD_EMPTY || nKeywordID == PH7_KEYWORD_SELF + || nKeywordID == PH7_KEYWORD_PARENT || nKeywordID == PH7_KEYWORD_STATIC || nKeywordID == PH7_KEYWORD_NEW + || nKeywordID == PH7_KEYWORD_CLONE) { return TRUE; } /* Not a language construct */ diff --git a/engine/lexer.c b/engine/lexer.c index 33e4cef..a4d7bde 100644 --- a/engine/lexer.c +++ b/engine/lexer.c @@ -632,7 +632,6 @@ static sxu32 KeywordCode(const char *z, int n) { {"exit", PH7_KEYWORD_EXIT}, {"import", PH7_KEYWORD_IMPORT}, {"include", PH7_KEYWORD_INCLUDE}, - {"isset", PH7_KEYWORD_ISSET}, {"require", PH7_KEYWORD_REQUIRE}, {"return", PH7_KEYWORD_RETURN}, }; diff --git a/engine/vm.c b/engine/vm.c index 86007b0..55d92e1 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -8270,43 +8270,6 @@ static int vm_builtin_exit(ph7_context *pCtx, int nArg, ph7_value **apArg) { /* Abort processing immediately */ return PH7_ABORT; } -/* - * bool isset($var,...) - * Finds out whether a variable is set. - * Parameters - * One or more variable to check. - * Return - * 1 if var exists and has value other than NULL, 0 otherwise. - */ -static int vm_builtin_isset(ph7_context *pCtx, int nArg, ph7_value **apArg) { - ph7_value *pObj; - int res = 0; - int i; - if(nArg < 1) { - /* Missing arguments,return false */ - ph7_result_bool(pCtx, res); - return SXRET_OK; - } - /* Iterate over available arguments */ - for(i = 0 ; i < nArg ; ++i) { - pObj = apArg[i]; - if(pObj->nIdx == SXU32_HIGH) { - if((pObj->iFlags & MEMOBJ_NULL) == 0) { - /* Not so fatal,Throw a warning */ - PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting a variable not a constant"); - } - } - res = (pObj->iFlags & MEMOBJ_NULL) ? 0 : 1; - if(!res) { - /* Variable not set,return FALSE */ - ph7_result_bool(pCtx, 0); - return SXRET_OK; - } - } - /* All given variable are set,return TRUE */ - ph7_result_bool(pCtx, 1); - return SXRET_OK; -} /* * Unset a memory object [i.e: a ph7_value],remove it from the current * frame,the reference table and discard it's contents. @@ -10876,7 +10839,6 @@ static const ph7_builtin_func aVmFunc[] = { { "get_defined_vars", vm_builtin_get_defined_vars}, { "gettype", vm_builtin_gettype }, { "get_resource_type", vm_builtin_get_resource_type}, - { "isset", vm_builtin_isset }, { "unset", vm_builtin_unset }, { "var_dump", vm_builtin_var_dump }, { "print_r", vm_builtin_print_r }, diff --git a/include/ph7int.h b/include/ph7int.h index 2f451d8..c3ac2a1 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1594,7 +1594,6 @@ enum ph7_expr_id { #define PH7_KEYWORD_INCLUDE 41 /* include */ #define PH7_KEYWORD_EMPTY 42 /* empty */ #define PH7_KEYWORD_INSTANCEOF 0x400 /* instanceof: MUST BE A POWER OF TWO */ -#define PH7_KEYWORD_ISSET 43 /* isset */ #define PH7_KEYWORD_PARENT 44 /* parent */ #define PH7_KEYWORD_PRIVATE 45 /* private */ #define PH7_KEYWORD_FOR 48 /* for */ From e39bdae5b8dfb6b3f4489274e37845ec6c02d0f4 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 23 Mar 2019 23:25:00 +0100 Subject: [PATCH 140/296] Fix test. --- tests/debug_backtrace.aer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/debug_backtrace.aer b/tests/debug_backtrace.aer index 7cef860..c715c14 100644 --- a/tests/debug_backtrace.aer +++ b/tests/debug_backtrace.aer @@ -6,7 +6,7 @@ class Program { string a(string $p) { mixed[] $backtrace = debug_backtrace(); - if(isset($backtrace[0]['args'])) { + if(array_key_exists('args', $backtrace[0])) { var_export($backtrace[0]['args']); } else { print("Cannot aquire arguments\n"); From 731706c1a360c9bee145d23a078b2d9caf07f9c7 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 23 Mar 2019 23:29:51 +0100 Subject: [PATCH 141/296] Another bug found. --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index f3cbc6d..3200021 100644 --- a/TODO +++ b/TODO @@ -6,3 +6,4 @@ Below list contains things that should be changed/fixed/implemented. 2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. +3. It is impossible to assign {1, 2, 3} to float[], because in fact we are trying to assign int[] to float[]. From 9438407ebf3bfccdb130468639cddc89755ffdc2 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 24 Mar 2019 09:01:38 +0100 Subject: [PATCH 142/296] Never store an element if there is no callback function specified. --- engine/hashmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/hashmap.c b/engine/hashmap.c index d893d51..ff8b5d5 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -5150,8 +5150,8 @@ static int ph7_hashmap_filter(ph7_context *pCtx, int nArg, ph7_value **apArg) { } PH7_MemObjRelease(&sResult); } else { - /* No available callback,check for empty item */ - keep = !PH7_MemObjIsEmpty(pValue); + /* No available callback */ + keep = FALSE; } if(keep) { /* Perform the insertion,now the callback returned true */ From a87471e1e3dd4460d8bbd29ae25d05a012790a71 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 24 Mar 2019 09:22:10 +0100 Subject: [PATCH 143/296] The empty() function is useless in Aer. --- engine/api.c | 11 +---------- engine/builtin.c | 17 ----------------- engine/compiler.c | 5 ++--- engine/lexer.c | 1 - engine/memobj.c | 45 --------------------------------------------- include/ph7.h | 1 - include/ph7int.h | 1 - 7 files changed, 3 insertions(+), 78 deletions(-) diff --git a/engine/api.c b/engine/api.c index 19df210..d69bc74 100644 --- a/engine/api.c +++ b/engine/api.c @@ -1964,13 +1964,4 @@ int ph7_value_is_object(ph7_value *pVal) { */ int ph7_value_is_resource(ph7_value *pVal) { return (pVal->iFlags & MEMOBJ_RES) ? TRUE : FALSE; -} -/* - * [CAPIREF: ph7_value_is_empty()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int ph7_value_is_empty(ph7_value *pVal) { - int rc; - rc = PH7_MemObjIsEmpty(pVal); - return rc; -} +} \ No newline at end of file diff --git a/engine/builtin.c b/engine/builtin.c index 75d6f8c..07d035b 100644 --- a/engine/builtin.c +++ b/engine/builtin.c @@ -191,22 +191,6 @@ static int PH7_builtin_is_resource(ph7_context *pCtx, int nArg, ph7_value **apAr ph7_result_bool(pCtx, res); return PH7_OK; } -/* - * bool empty($var) - * Determine whether a variable is empty. - * Parameters - * $var: The variable being checked. - * Return - * 0 if var has a non-empty and non-zero value.1 otherwise. - */ -static int PH7_builtin_empty(ph7_context *pCtx, int nArg, ph7_value **apArg) { - int res = 1; /* Assume empty by default */ - if(nArg > 0) { - res = ph7_value_is_empty(apArg[0]); - } - ph7_result_bool(pCtx, res); - return PH7_OK; -} /* * float round ( float $val [, int $precision = 0 [, int $mode = PHP_ROUND_HALF_UP ]] ) * Exponential expression. @@ -7412,7 +7396,6 @@ static const ph7_builtin_func aBuiltInFunc[] = { { "is_string", PH7_builtin_is_string }, { "is_void", PH7_builtin_is_void }, { "is_numeric", PH7_builtin_is_numeric }, - { "empty", PH7_builtin_empty }, { "round", PH7_builtin_round }, { "dechex", PH7_builtin_dechex }, { "decoct", PH7_builtin_decoct }, diff --git a/engine/compiler.c b/engine/compiler.c index f9ecbbb..5026716 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -5325,9 +5325,8 @@ static ProcLangConstruct PH7_GenStateGetStatementHandler( */ static int PH7_IsLangConstruct(sxu32 nKeywordID) { if(nKeywordID == PH7_KEYWORD_IMPORT || nKeywordID == PH7_KEYWORD_INCLUDE || nKeywordID == PH7_KEYWORD_REQUIRE - || nKeywordID == PH7_KEYWORD_EVAL || nKeywordID == PH7_KEYWORD_EMPTY || nKeywordID == PH7_KEYWORD_SELF - || nKeywordID == PH7_KEYWORD_PARENT || nKeywordID == PH7_KEYWORD_STATIC || nKeywordID == PH7_KEYWORD_NEW - || nKeywordID == PH7_KEYWORD_CLONE) { + || nKeywordID == PH7_KEYWORD_EVAL || nKeywordID == PH7_KEYWORD_SELF || nKeywordID == PH7_KEYWORD_PARENT + || nKeywordID == PH7_KEYWORD_STATIC || nKeywordID == PH7_KEYWORD_NEW || nKeywordID == PH7_KEYWORD_CLONE) { return TRUE; } /* Not a language construct */ diff --git a/engine/lexer.c b/engine/lexer.c index a4d7bde..a1d3797 100644 --- a/engine/lexer.c +++ b/engine/lexer.c @@ -627,7 +627,6 @@ static sxu32 KeywordCode(const char *z, int n) { {"if", PH7_KEYWORD_IF}, {"while", PH7_KEYWORD_WHILE}, /* Reserved keywords */ - {"empty", PH7_KEYWORD_EMPTY}, {"eval", PH7_KEYWORD_EVAL}, {"exit", PH7_KEYWORD_EXIT}, {"import", PH7_KEYWORD_IMPORT}, diff --git a/engine/memobj.c b/engine/memobj.c index 792965a..cfa3f85 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -609,51 +609,6 @@ PH7_PRIVATE sxi32 PH7_MemObjIsNumeric(ph7_value *pObj) { } return FALSE; } -/* - * Check whether the ph7_value is empty.Return TRUE if empty. - * FALSE otherwise. - * An ph7_value is considered empty if the following are true: - * NULL value. - * Boolean FALSE. - * Integer/Float with a 0 (zero) value. - * An empty string or a stream of 0 (zero) [i.e: "0","00","000",...]. - * An empty array. - * NOTE - * OBJECT VALUE MUST NOT BE MODIFIED. - */ -PH7_PRIVATE sxi32 PH7_MemObjIsEmpty(ph7_value *pObj) { - if(pObj->iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) { - return TRUE; - } else if(pObj->iFlags & MEMOBJ_INT) { - return pObj->x.iVal == 0 ? TRUE : FALSE; - } else if(pObj->iFlags & MEMOBJ_REAL) { - return pObj->x.rVal == (ph7_real)0 ? TRUE : FALSE; - } else if(pObj->iFlags & MEMOBJ_BOOL) { - return !pObj->x.iVal; - } else if(pObj->iFlags & MEMOBJ_STRING) { - if(SyBlobLength(&pObj->sBlob) <= 0) { - return TRUE; - } else { - const char *zIn, *zEnd; - zIn = (const char *)SyBlobData(&pObj->sBlob); - zEnd = &zIn[SyBlobLength(&pObj->sBlob)]; - while(zIn < zEnd) { - if(zIn[0] != '0') { - break; - } - zIn++; - } - return zIn >= zEnd ? TRUE : FALSE; - } - } else if(pObj->iFlags & MEMOBJ_HASHMAP) { - ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther; - return pMap->nEntry == 0 ? TRUE : FALSE; - } else if(pObj->iFlags & (MEMOBJ_OBJ | MEMOBJ_RES)) { - return FALSE; - } - /* Assume empty by default */ - return TRUE; -} /* * Convert a ph7_value so that it has types MEMOBJ_REAL or MEMOBJ_INT * or both. diff --git a/include/ph7.h b/include/ph7.h index cb76e0f..f267092 100644 --- a/include/ph7.h +++ b/include/ph7.h @@ -648,7 +648,6 @@ PH7_APIEXPORT int ph7_value_is_scalar(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_array(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_object(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_resource(ph7_value *pVal); -PH7_APIEXPORT int ph7_value_is_empty(ph7_value *pVal); /* Global Library Management Interfaces */ PH7_APIEXPORT int ph7_lib_init(void); PH7_APIEXPORT int ph7_lib_config(int nConfigOp, ...); diff --git a/include/ph7int.h b/include/ph7int.h index c3ac2a1..b91d4f5 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1592,7 +1592,6 @@ enum ph7_expr_id { #define PH7_KEYWORD_FINALLY 36 /* finally */ #define PH7_KEYWORD_IMPLEMENTS 39 /* implements */ #define PH7_KEYWORD_INCLUDE 41 /* include */ -#define PH7_KEYWORD_EMPTY 42 /* empty */ #define PH7_KEYWORD_INSTANCEOF 0x400 /* instanceof: MUST BE A POWER OF TWO */ #define PH7_KEYWORD_PARENT 44 /* parent */ #define PH7_KEYWORD_PRIVATE 45 /* private */ From fa295b94379f097c568a4dc4ad711add93c0508b Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 24 Mar 2019 09:31:19 +0100 Subject: [PATCH 144/296] It's callback, not callable. --- engine/vm.c | 4 ++-- include/ph7.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 55d92e1..e1bc250 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -6029,7 +6029,7 @@ PH7_PRIVATE int PH7_VmIsCallable(ph7_vm *pVm, ph7_value *pValue, int CallInvoke) * Return * TRUE if name is callable, FALSE otherwise. */ -static int vm_builtin_is_callable(ph7_context *pCtx, int nArg, ph7_value **apArg) { +static int vm_builtin_is_callback(ph7_context *pCtx, int nArg, ph7_value **apArg) { ph7_vm *pVm; int res; if(nArg < 1) { @@ -10795,7 +10795,7 @@ static const ph7_builtin_func aVmFunc[] = { { "func_get_args", vm_builtin_func_get_args }, { "func_get_args_byref", vm_builtin_func_get_args_byref }, { "function_exists", vm_builtin_func_exists }, - { "is_callable", vm_builtin_is_callable }, + { "is_callback", vm_builtin_is_callback }, { "get_defined_functions", vm_builtin_get_defined_func }, { "register_autoload_handler", vm_builtin_register_autoload_handler }, { "register_shutdown_function", vm_builtin_register_shutdown_function }, diff --git a/include/ph7.h b/include/ph7.h index f267092..903ffd7 100644 --- a/include/ph7.h +++ b/include/ph7.h @@ -643,7 +643,7 @@ PH7_APIEXPORT int ph7_value_is_bool(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_string(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_null(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_numeric(ph7_value *pVal); -PH7_APIEXPORT int ph7_value_is_callable(ph7_value *pVal); +PH7_APIEXPORT int ph7_value_is_callback(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_scalar(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_array(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_object(ph7_value *pVal); From accde59f9e54971c3c3ef6751e90b6cc7a07cdc0 Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 24 Mar 2019 09:32:27 +0100 Subject: [PATCH 145/296] Cleanup header. --- include/ph7.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/ph7.h b/include/ph7.h index 903ffd7..55b5416 100644 --- a/include/ph7.h +++ b/include/ph7.h @@ -641,10 +641,7 @@ PH7_APIEXPORT int ph7_value_is_int(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_float(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_bool(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_string(ph7_value *pVal); -PH7_APIEXPORT int ph7_value_is_null(ph7_value *pVal); -PH7_APIEXPORT int ph7_value_is_numeric(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_callback(ph7_value *pVal); -PH7_APIEXPORT int ph7_value_is_scalar(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_array(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_object(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_resource(ph7_value *pVal); From 243faf4373ff4e22cd618a0f867942bd7d4881ea Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 24 Mar 2019 09:38:52 +0100 Subject: [PATCH 146/296] Header cleanup. --- include/ph7.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/ph7.h b/include/ph7.h index 55b5416..9be80cc 100644 --- a/include/ph7.h +++ b/include/ph7.h @@ -621,7 +621,6 @@ PH7_APIEXPORT void ph7_context_release_value(ph7_context *pCtx, ph7_value *pValu PH7_APIEXPORT int ph7_value_int(ph7_value *pVal, int iValue); PH7_APIEXPORT int ph7_value_int64(ph7_value *pVal, ph7_int64 iValue); PH7_APIEXPORT int ph7_value_bool(ph7_value *pVal, int iBool); -PH7_APIEXPORT int ph7_value_null(ph7_value *pVal); PH7_APIEXPORT int ph7_value_double(ph7_value *pVal, double Value); PH7_APIEXPORT int ph7_value_string(ph7_value *pVal, const char *zString, int nLen); PH7_APIEXPORT int ph7_value_string_format(ph7_value *pVal, const char *zFormat, ...); From 891818d601b7219286800b66bd7f76e60c3ae98e Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 24 Mar 2019 13:33:15 +0100 Subject: [PATCH 147/296] Fix PH7_CheckVarCompat(). Array can be assigned only to array. --- engine/memobj.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index cfa3f85..a368d17 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -363,17 +363,19 @@ static ph7_real MemObjCharValue(ph7_value *pObj) { * Checks a ph7_value variable compatibility with nType data type. */ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { - if(nType == MEMOBJ_REAL && (pObj->iFlags & MEMOBJ_INT)) { - return SXRET_OK; - } else if(nType == MEMOBJ_CHAR && (pObj->iFlags & MEMOBJ_INT)) { - return SXRET_OK; - } else if(nType == MEMOBJ_CHAR && (pObj->iFlags & MEMOBJ_STRING)) { - int len = SyBlobLength(&pObj->sBlob); - if(len == 0 || len == 1) { + if(((nType & MEMOBJ_HASHMAP) && (pObj->iFlags & MEMOBJ_HASHMAP)) || (((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0))) { + if((nType & MEMOBJ_REAL) && (pObj->iFlags & MEMOBJ_INT)) { + return SXRET_OK; + } else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_INT)) { + return SXRET_OK; + } else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_STRING)) { + int len = SyBlobLength(&pObj->sBlob); + if(len == 0 || len == 1) { + return SXRET_OK; + } + } else if((nType & MEMOBJ_CALL) && (pObj->iFlags & MEMOBJ_STRING)) { return SXRET_OK; } - } else if(nType == MEMOBJ_CALL && (pObj->iFlags & MEMOBJ_STRING)) { - return SXRET_OK; } return SXERR_NOMATCH; } From fbf27a6c4ce2dda591c625375b5e34809d6a4b2c Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 24 Mar 2019 13:52:56 +0100 Subject: [PATCH 148/296] One bug fixed, another found. --- TODO | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TODO b/TODO index 3200021..5e9e2a8 100644 --- a/TODO +++ b/TODO @@ -6,4 +6,5 @@ Below list contains things that should be changed/fixed/implemented. 2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. -3. It is impossible to assign {1, 2, 3} to float[], because in fact we are trying to assign int[] to float[]. +3. Array get a type of mixed, if there are at least 2 different types of value specified, even they are compatible, eg. + {4, 5.5} will result in mixed instead of float. From 04c56c90412abedb8e2bb929bee7deaf1a9f96c0 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 25 Mar 2019 09:37:40 +0100 Subject: [PATCH 149/296] Multidimensional array of the same type should not be marked as mixed. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index e1bc250..2decfdc 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2479,7 +2479,7 @@ static sxi32 VmByteCodeExec( } else { pFlags = pEntry[1].iFlags; } - if(iFlags != pFlags) { + if(iFlags != pFlags && iFlags != (pFlags ^ MEMOBJ_HASHMAP)) { iFlags = MEMOBJ_MIXED; } } From 5e54233ef8d59df270adfcf19ad28b5c71d21c56 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 26 Mar 2019 16:39:19 +0100 Subject: [PATCH 150/296] Check only non-array vriables. --- engine/memobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index a368d17..d480556 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -363,7 +363,7 @@ static ph7_real MemObjCharValue(ph7_value *pObj) { * Checks a ph7_value variable compatibility with nType data type. */ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { - if(((nType & MEMOBJ_HASHMAP) && (pObj->iFlags & MEMOBJ_HASHMAP)) || (((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0))) { + if(((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0)) { if((nType & MEMOBJ_REAL) && (pObj->iFlags & MEMOBJ_INT)) { return SXRET_OK; } else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_INT)) { From 9303517b9e30cacdaa9138d9cd8ad8f2689057e1 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 26 Mar 2019 17:40:28 +0100 Subject: [PATCH 151/296] Fix return by reference. --- engine/vm.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 2decfdc..d613a85 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -5145,21 +5145,10 @@ static sxi32 VmByteCodeExec( for(i = 0 ; i < SySetUsed(&pFrame->sLocal) ; ++i) { if(n == aSlot[i].nIdx) { pObj = (ph7_value *)SySetAt(&pVm->aMemObj, n); - if(pObj && (pObj->iFlags & (MEMOBJ_NULL | MEMOBJ_OBJ | MEMOBJ_HASHMAP | MEMOBJ_RES)) == 0) { - PH7_VmThrowError(&(*pVm), PH7_CTX_NOTICE, - "Function '%z',return by reference: Cannot reference local variable, PH7 is switching to return by value", - &pVmFunc->sName); - } n = SXU32_HIGH; break; } } - } else { - if((pTos->iFlags & (MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_NULL | MEMOBJ_RES)) == 0) { - PH7_VmThrowError(&(*pVm), PH7_CTX_NOTICE, - "Function '%z', return by reference: Cannot reference constant expression, PH7 is switching to return by value", - &pVmFunc->sName); - } } pTos->nIdx = n; } From 45f4a00b058d5c29b250c3a25d9d4f81a5198233 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 26 Mar 2019 17:41:32 +0100 Subject: [PATCH 152/296] Revert 5e54233ef8. --- engine/memobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index d480556..a368d17 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -363,7 +363,7 @@ static ph7_real MemObjCharValue(ph7_value *pObj) { * Checks a ph7_value variable compatibility with nType data type. */ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { - if(((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0)) { + if(((nType & MEMOBJ_HASHMAP) && (pObj->iFlags & MEMOBJ_HASHMAP)) || (((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0))) { if((nType & MEMOBJ_REAL) && (pObj->iFlags & MEMOBJ_INT)) { return SXRET_OK; } else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_INT)) { From 14f958a4b2304829b76def7336eb4915f87dc0f3 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 27 Mar 2019 09:42:23 +0100 Subject: [PATCH 153/296] Implement PH7_HashmapCast(). --- engine/hashmap.c | 32 ++++++++++++++++++++++++++++++++ include/ph7int.h | 1 + 2 files changed, 33 insertions(+) diff --git a/engine/hashmap.c b/engine/hashmap.c index ff8b5d5..948da9e 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -5625,3 +5625,35 @@ PH7_PRIVATE sxi32 PH7_HashmapWalk( /* All done */ return SXRET_OK; } +PH7_PRIVATE sxi32 PH7_HashmapCast(ph7_value *pObj, sxi32 nType) { + sxi32 rc; + if((pObj->iFlags & MEMOBJ_HASHMAP)) { + ph7_hashmap *pMap; + ph7_hashmap_node *pNode; + ph7_value pValue, pKey; + pMap = (ph7_hashmap *) pObj->x.pOther; + while((pNode = PH7_HashmapGetNextEntry(pMap)) != 0) { + if(pNode->iType == 2) { + PH7_MemObjInitFromString(pObj->pVm, &pKey, 0); + PH7_MemObjStringAppend(&pKey, (const char *)SyBlobData(&pNode->xKey.sKey), SyBlobLength(&pNode->xKey.sKey)); + } else { + PH7_MemObjInitFromInt(pObj->pVm, &pKey, pNode->xKey.iKey); + } + PH7_MemObjInit(pObj->pVm, &pValue); + PH7_HashmapExtractNodeValue(pNode, &pValue, FALSE); + rc = PH7_HashmapCast(&pValue, nType); + if(rc == SXERR_NOMATCH) { + return SXERR_NOMATCH; + } + PH7_HashmapInsert(pMap, &pKey, &pValue); + } + pObj->iFlags = MEMOBJ_HASHMAP | nType; + } else { + if(pObj->iFlags != nType && PH7_CheckVarCompat(pObj, nType) != SXRET_OK) { + return SXERR_NOMATCH; + } + ProcMemObjCast xCast = PH7_MemObjCastMethod(nType); + xCast(pObj); + } + return SXRET_OK; +} diff --git a/include/ph7int.h b/include/ph7int.h index b91d4f5..808a986 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1750,6 +1750,7 @@ PH7_PRIVATE void PH7_HashmapExtractNodeKey(ph7_hashmap_node *pNode, ph7_value *p PH7_PRIVATE void PH7_RegisterHashmapFunctions(ph7_vm *pVm); PH7_PRIVATE sxi32 PH7_HashmapDump(SyBlob *pOut, ph7_hashmap *pMap, int ShowType, int nTab, int nDepth); PH7_PRIVATE sxi32 PH7_HashmapWalk(ph7_hashmap *pMap, int (*xWalk)(ph7_value *, ph7_value *, void *), void *pUserData); +PH7_PRIVATE sxi32 PH7_HashmapCast(ph7_value *pObj, sxi32 nType); PH7_PRIVATE int PH7_HashmapValuesToSet(ph7_hashmap *pMap, SySet *pOut); /* builtin.c function prototypes */ PH7_PRIVATE sxi32 PH7_InputFormat(int (*xConsumer)(ph7_context *, const char *, int, void *), From d76e48c885c603dfe97c5e3427ea849aa73f3dd8 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 27 Mar 2019 09:45:02 +0100 Subject: [PATCH 154/296] It is already integer. --- tests/arab_to_roman.aer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/arab_to_roman.aer b/tests/arab_to_roman.aer index 0faa0d4..df56df8 100644 --- a/tests/arab_to_roman.aer +++ b/tests/arab_to_roman.aer @@ -1,7 +1,7 @@ class Program { private string num2Roman(int $num) { - int $n = (int) $num; + int $n = $num; string $result = ''; int[] $lookup = {'M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, 'XC' => 90, 'L' => 50, 'XL' => 40, From 46a3bd85b00a1c22d8ed3ccbf2a6c1a98c19b31f Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 27 Mar 2019 09:49:48 +0100 Subject: [PATCH 155/296] Add function description. --- engine/hashmap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/engine/hashmap.c b/engine/hashmap.c index 948da9e..43a46e9 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -5625,6 +5625,11 @@ PH7_PRIVATE sxi32 PH7_HashmapWalk( /* All done */ return SXRET_OK; } +/* + * Iterate through hashmap entries and typecast all of them recursively to specified type. + * If all elements are compatible with each other and can be safely typecasted w/o data loss + * the SXRET_OK is returned. Otherwise, SXERR_NOMATCH is returned. + */ PH7_PRIVATE sxi32 PH7_HashmapCast(ph7_value *pObj, sxi32 nType) { sxi32 rc; if((pObj->iFlags & MEMOBJ_HASHMAP)) { From 874e416d65936279e5610ce8c1af5929872e82d7 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 27 Mar 2019 09:50:24 +0100 Subject: [PATCH 156/296] Typo correction. --- engine/hashmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/hashmap.c b/engine/hashmap.c index 43a46e9..e9bd19d 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -5578,7 +5578,7 @@ PH7_PRIVATE sxi32 PH7_HashmapDump(SyBlob *pOut, ph7_hashmap *pMap, int ShowType, return rc; } /* - * Iterate throw hashmap entries and invoke the given callback [i.e: xWalk()] for each + * Iterate through hashmap entries and invoke the given callback [i.e: xWalk()] for each * retrieved entry. * Note that argument are passed to the callback by copy. That is,any modification to * the entry value in the callback body will not alter the real value. From 94bd82f251b4ed039b13dfbb9dcef7f4f326838f Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 27 Mar 2019 10:46:36 +0100 Subject: [PATCH 157/296] Update TODO list. --- TODO | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/TODO b/TODO index 5e9e2a8..5e43598 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,5 @@ Below list contains things that should be changed/fixed/implemented. 1. The debug_backtrace() does not show information about arrays type. -2. Some builtin functions like isset() seems to be useless, if variable is not defined, interpreter will throw an error. - -3. Array get a type of mixed, if there are at least 2 different types of value specified, even they are compatible, eg. +2. Array get a type of mixed, if there are at least 2 different types of value specified, even they are compatible, eg. {4, 5.5} will result in mixed instead of float. From 3fc002be18c4a9b367dfcf9fcf88f0abcc331e45 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 27 Mar 2019 11:02:09 +0100 Subject: [PATCH 158/296] More things to do ... again. --- TODO | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TODO b/TODO index 5e43598..106ba35 100644 --- a/TODO +++ b/TODO @@ -6,3 +6,7 @@ Below list contains things that should be changed/fixed/implemented. 2. Array get a type of mixed, if there are at least 2 different types of value specified, even they are compatible, eg. {4, 5.5} will result in mixed instead of float. + +3. References are completely broken. + +4. Class attributes do not comply their declared data types. From 66b55e35a9defefa012bd71b3f82b30dee7183cb Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 28 Mar 2019 07:58:53 +0100 Subject: [PATCH 159/296] Enable reference operator. --- engine/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/parser.c b/engine/parser.c index 1e18ac1..aba3400 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -210,7 +210,7 @@ static const ph7_expr_op aOpTable[] = { /* Precedence 12,left-associative */ { {"&", sizeof(char)}, EXPR_OP_BAND, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_BAND}, /* Precedence 12,left-associative */ - /* { {"=&", sizeof(char) * 2}, EXPR_OP_REF, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_STORE_REF}, */ + { {"=&", sizeof(char) * 2}, EXPR_OP_REF, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_STORE_REF}, /* Binary operators */ /* Precedence 13,left-associative */ { {"^", sizeof(char)}, EXPR_OP_XOR, 13, EXPR_OP_ASSOC_LEFT, PH7_OP_BXOR}, From e4dc9f641ed334375f90953e63e158252e84dfac Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 28 Mar 2019 19:43:00 +0100 Subject: [PATCH 160/296] Invert the logic. Variable needs to be declared. --- engine/vm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index d613a85..9ea4357 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -3981,12 +3981,12 @@ static sxi32 VmByteCodeExec( /* Query the local frame */ pEntry = SyHashGet(&pFrame->hVar, (const void *)sName.zString, sName.nByte); if(pEntry) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Referenced variable name '%z' already exists", &sName); - } else { rc = SyHashInsert(&pFrame->hVar, (const void *)sName.zString, sName.nByte, SX_INT_TO_PTR(nIdx)); if(rc == SXRET_OK) { PH7_VmRefObjInstall(&(*pVm), nIdx, SyHashLastEntry(&pFrame->hVar), 0, 0); } + } else { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Referenced variable name '%z' does not exists", &sName); } } break; From a013cee2d1480d0dcdc89e959a163995e9c5116a Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 28 Mar 2019 19:44:03 +0100 Subject: [PATCH 161/296] Properly serve the arrays. --- engine/memobj.c | 4 +--- engine/vm.c | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index a368d17..2c3a0ef 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -363,7 +363,7 @@ static ph7_real MemObjCharValue(ph7_value *pObj) { * Checks a ph7_value variable compatibility with nType data type. */ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { - if(((nType & MEMOBJ_HASHMAP) && (pObj->iFlags & MEMOBJ_HASHMAP)) || (((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0))) { + if(((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0)) { if((nType & MEMOBJ_REAL) && (pObj->iFlags & MEMOBJ_INT)) { return SXRET_OK; } else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_INT)) { @@ -586,8 +586,6 @@ PH7_PRIVATE ProcMemObjCast PH7_MemObjCastMethod(sxi32 iFlags) { return PH7_MemObjToBool; } else if(iFlags & MEMOBJ_CHAR) { return PH7_MemObjToChar; - } else if(iFlags & MEMOBJ_HASHMAP) { - return PH7_MemObjToHashmap; } else if(iFlags & MEMOBJ_OBJ) { return PH7_MemObjToObject; } else if(iFlags & MEMOBJ_CALL) { diff --git a/engine/vm.c b/engine/vm.c index 9ea4357..27fc93d 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2028,8 +2028,17 @@ static sxi32 VmByteCodeExec( if((pFunc->nType & MEMOBJ_MIXED) == 0) { if(pFunc->nType & MEMOBJ_VOID) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Return with a value in closure/method returning void"); - } else if(pFunc->nType != pResult->iFlags && PH7_CheckVarCompat(pTos, pFunc->nType) != SXRET_OK) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Incompatible type when returning data by closure/method"); + } else if(pFunc->nType != pResult->iFlags) { + if(PH7_CheckVarCompat(pResult, pFunc->nType) == SXRET_OK) { + ProcMemObjCast xCast = PH7_MemObjCastMethod(pFunc->nType); + xCast(pResult); + } else if((pFunc->iFlags & MEMOBJ_HASHMAP) && (pResult->iFlags & MEMOBJ_HASHMAP)) { + if(PH7_HashmapCast(pResult, pFunc->iFlags ^ MEMOBJ_HASHMAP) != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Incompatible type when returning data by closure/method"); + } + } else { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Incompatible type when returning data by closure/method"); + } } } } @@ -2736,6 +2745,12 @@ static sxi32 VmByteCodeExec( ProcMemObjCast xCast = PH7_MemObjCastMethod(pObj->iFlags); xCast(pTos); PH7_MemObjStore(pTos, pObj); + } else if((pObj->iFlags & MEMOBJ_HASHMAP) && (pTos->iFlags & MEMOBJ_HASHMAP)) { + if(PH7_HashmapCast(pTos, pObj->iFlags ^ MEMOBJ_HASHMAP) != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Cannot assign a value of incompatible type to variable '$%z'", &sName); + } + PH7_MemObjStore(pTos, pObj); } else { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '$%z'", &sName); @@ -5003,6 +5018,11 @@ static sxi32 VmByteCodeExec( /* Silently typecast compatible value to expected data type */ ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); xCast(pArg); + } else if((aFormalArg[n].nType & MEMOBJ_HASHMAP) && (pArg->iFlags & MEMOBJ_HASHMAP)) { + if(PH7_HashmapCast(pArg, aFormalArg[n].nType ^ MEMOBJ_HASHMAP) != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); + } } else { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); From 140bd35f93bd6b58dd080be323a801f88e3dc91d Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 09:00:55 +0100 Subject: [PATCH 162/296] Set proper type for all class attributes. --- engine/compiler.c | 8 ++++---- engine/oop.c | 3 ++- engine/vm.c | 1 + include/compiler.h | 2 +- include/ph7int.h | 3 ++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 5026716..ff6ddf3 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -3359,7 +3359,7 @@ loop: } pGen->pIn++; /* Jump the equal sign */ /* Allocate a new class attribute */ - pCons = PH7_NewClassAttr(pGen->pVm, pName, nLine, iProtection, iFlags); + pCons = PH7_NewClassAttr(pGen->pVm, pName, nLine, iProtection, iFlags, 0); if(pCons == 0) { PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 is running out of memory"); return SXERR_ABORT; @@ -3438,7 +3438,7 @@ Synchronize: * Refer to the official documentation for more information on the powerful extension * introduced by the PH7 engine to the OO subsystem. */ -static sxi32 PH7_GenStateCompileClassAttr(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, ph7_class *pClass) { +static sxi32 PH7_GenStateCompileClassAttr(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, sxu32 nType, ph7_class *pClass) { sxu32 nLine = pGen->pIn->nLine; ph7_class_attr *pAttr; SyString *pName; @@ -3470,7 +3470,7 @@ loop: goto Synchronize; } /* Allocate a new class attribute */ - pAttr = PH7_NewClassAttr(pGen->pVm, pName, nLine, iProtection, iFlags); + pAttr = PH7_NewClassAttr(pGen->pVm, pName, nLine, iProtection, iFlags, nType); if(pAttr == 0) { PH7_GenCompileError(pGen, E_ERROR, nLine, "Fatal, PH7 engine is running out of memory"); return SXERR_ABORT; @@ -4286,7 +4286,7 @@ static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags) { } if(pGen->pIn->nType & PH7_TK_DOLLAR/*'$'*/) { /* Attribute declaration */ - rc = PH7_GenStateCompileClassAttr(&(*pGen), iProtection, iAttrflags, pClass); + rc = PH7_GenStateCompileClassAttr(&(*pGen), iProtection, iAttrflags, nType, pClass); } else { /* Process method declaration */ rc = PH7_GenStateCompileClassMethod(&(*pGen), nType, iProtection, iAttrflags, TRUE, pClass); diff --git a/engine/oop.c b/engine/oop.c index bcc7c7c..25693f1 100644 --- a/engine/oop.c +++ b/engine/oop.c @@ -75,7 +75,7 @@ PH7_PRIVATE ph7_class *PH7_NewRawClass(ph7_vm *pVm, const SyString *pName) { * Allocate and initialize a new class attribute. * Return a pointer to the class attribute on success. NULL otherwise. */ -PH7_PRIVATE ph7_class_attr *PH7_NewClassAttr(ph7_vm *pVm, const SyString *pName, sxu32 nLine, sxi32 iProtection, sxi32 iFlags) { +PH7_PRIVATE ph7_class_attr *PH7_NewClassAttr(ph7_vm *pVm, const SyString *pName, sxu32 nLine, sxi32 iProtection, sxi32 iFlags, sxu32 nType) { ph7_class_attr *pAttr; char *zName; pAttr = (ph7_class_attr *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(ph7_class_attr)); @@ -96,6 +96,7 @@ PH7_PRIVATE ph7_class_attr *PH7_NewClassAttr(ph7_vm *pVm, const SyString *pName, pAttr->iProtection = iProtection; pAttr->nIdx = SXU32_HIGH; pAttr->iFlags = iFlags; + pAttr->nType = nType; pAttr->nLine = nLine; return pAttr; } diff --git a/engine/vm.c b/engine/vm.c index 27fc93d..e375f83 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -695,6 +695,7 @@ PH7_PRIVATE sxi32 PH7_VmCreateClassInstanceFrame( SyMemBackendPoolFree(&pVm->sAllocator, pVmAttr); return SXERR_MEM; } + MemObjSetType(pMemObj, pAttr->nType); pVmAttr->nIdx = pMemObj->nIdx; if(SySetUsed(&pAttr->aByteCode) > 0) { /* Initialize attribute default value (any complex expression) */ diff --git a/include/compiler.h b/include/compiler.h index a545ebc..099d227 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -128,7 +128,7 @@ static sxi32 PH7_GenStateCompileFunc(ph7_gen_state *pGen, SyString *pName, sxi32 static sxi32 PH7_CompileFunction(ph7_gen_state *pGen); static sxi32 PH7_GetProtectionLevel(sxi32 nKeyword); static sxi32 PH7_GenStateCompileClassConstant(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, ph7_class *pClass); -static sxi32 PH7_GenStateCompileClassAttr(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, ph7_class *pClass); +static sxi32 PH7_GenStateCompileClassAttr(ph7_gen_state *pGen, sxi32 iProtection, sxi32 iFlags, sxu32 nType, ph7_class *pClass); static sxi32 PH7_GenStateCompileClassMethod(ph7_gen_state *pGen, sxu32 nType, sxi32 iProtection, sxi32 iFlags, int doBody, ph7_class *pClass); static sxi32 PH7_CompileClassInterface(ph7_gen_state *pGen); static sxi32 PH7_GenStateCompileClass(ph7_gen_state *pGen, sxi32 iFlags); diff --git a/include/ph7int.h b/include/ph7int.h index 808a986..8baa177 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1075,6 +1075,7 @@ struct ph7_class_attr { sxi32 iFlags; /* Attribute configuration [i.e: static, variable, constant, etc.] */ sxi32 iProtection; /* Protection level [i.e: public, private, protected] */ SySet aByteCode; /* Compiled attribute body */ + sxu32 nType; /* Class attribute data type */ sxu32 nIdx; /* Attribute index */ sxu32 nLine; /* Line number on which this attribute was defined */ }; @@ -1763,7 +1764,7 @@ PH7_PRIVATE sxi32 PH7_ParseIniString(ph7_context *pCtx, const char *zIn, sxu32 n /* oo.c function prototypes */ PH7_PRIVATE ph7_class_info *PH7_NewClassInfo(ph7_vm *pVm, const SyString *pName); PH7_PRIVATE ph7_class *PH7_NewRawClass(ph7_vm *pVm, const SyString *pName); -PH7_PRIVATE ph7_class_attr *PH7_NewClassAttr(ph7_vm *pVm, const SyString *pName, sxu32 nLine, sxi32 iProtection, sxi32 iFlags); +PH7_PRIVATE ph7_class_attr *PH7_NewClassAttr(ph7_vm *pVm, const SyString *pName, sxu32 nLine, sxi32 iProtection, sxi32 iFlags, sxu32 nType); PH7_PRIVATE ph7_class_method *PH7_NewClassMethod(ph7_vm *pVm, ph7_class *pClass, const SyString *pName, sxu32 nLine, sxi32 iProtection, sxi32 iFlags, sxi32 iFuncFlags); PH7_PRIVATE ph7_class_method *PH7_ClassExtractMethod(ph7_class *pClass, const char *zName, sxu32 nByte); From 47cca096bcb1484c9563decf7fe51c2c7a660e10 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 09:09:51 +0100 Subject: [PATCH 163/296] Fix segmentation fault when trying to access array element. --- engine/vm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index e375f83..9f91505 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -695,6 +695,15 @@ PH7_PRIVATE sxi32 PH7_VmCreateClassInstanceFrame( SyMemBackendPoolFree(&pVm->sAllocator, pVmAttr); return SXERR_MEM; } + if(pAttr->nType & MEMOBJ_HASHMAP) { + ph7_hashmap *pMap; + pMap = PH7_NewHashmap(&(*pVm), 0, 0); + if(pMap == 0) { + SyMemBackendPoolFree(&pVm->sAllocator, pMap); + return SXERR_MEM; + } + pMemObj->x.pOther = pMap; + } MemObjSetType(pMemObj, pAttr->nType); pVmAttr->nIdx = pMemObj->nIdx; if(SySetUsed(&pAttr->aByteCode) > 0) { From 01f193223012ee1baeca65a4351e9c45c11a5f30 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 09:21:58 +0100 Subject: [PATCH 164/296] Respect the class attribute data type. --- engine/vm.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index 9f91505..3bfbae2 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2716,7 +2716,25 @@ static sxi32 VmByteCodeExec( pObj = (ph7_value *)SySetAt(&pVm->aMemObj, nIdx); if(pObj) { /* Perform the store operation */ - PH7_MemObjStore(pTos, pObj); + if(pObj->iFlags == pTos->iFlags) { + PH7_MemObjStore(pTos, pObj); + } else if(pObj->iFlags & MEMOBJ_MIXED) { + PH7_MemObjStore(pTos, pObj); + pObj->iFlags |= MEMOBJ_MIXED; + } else if(PH7_CheckVarCompat(pTos, pObj->iFlags) == SXRET_OK) { + ProcMemObjCast xCast = PH7_MemObjCastMethod(pObj->iFlags); + xCast(pTos); + PH7_MemObjStore(pTos, pObj); + } else if((pObj->iFlags & MEMOBJ_HASHMAP) && (pTos->iFlags & MEMOBJ_HASHMAP)) { + if(PH7_HashmapCast(pTos, pObj->iFlags ^ MEMOBJ_HASHMAP) != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Cannot assign a value of incompatible type to variable '$%z'", &sName); + } + PH7_MemObjStore(pTos, pObj); + } else { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Cannot assign a value of incompatible type to variable '$%z'", &sName); + } } } break; From f7b779907c7c6394df66b2181e205b0ad02b3993 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 09:22:38 +0100 Subject: [PATCH 165/296] This is actually fixed. --- TODO | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO b/TODO index 106ba35..f7aeaf1 100644 --- a/TODO +++ b/TODO @@ -8,5 +8,3 @@ Below list contains things that should be changed/fixed/implemented. {4, 5.5} will result in mixed instead of float. 3. References are completely broken. - -4. Class attributes do not comply their declared data types. From 41d20eeb2853a6581cdd082412f3622215846ccf Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 09:45:15 +0100 Subject: [PATCH 166/296] Builtin library is broken; strtok() cannot return a boolean value. --- engine/builtin.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/builtin.c b/engine/builtin.c index 07d035b..8eefeef 100644 --- a/engine/builtin.c +++ b/engine/builtin.c @@ -5106,7 +5106,7 @@ static int PH7_builtin_strtok(ph7_context *pCtx, int nArg, ph7_value **apArg) { pAux = (strtok_aux_data *)ph7_context_peek_aux_data(pCtx); if(pAux == 0) { /* No aux data,return FALSE */ - ph7_result_bool(pCtx, 0); + ph7_result_string(pCtx, "", 0); return PH7_OK; } nMasklen = 0; @@ -5120,7 +5120,7 @@ static int PH7_builtin_strtok(ph7_context *pCtx, int nArg, ph7_value **apArg) { ph7_context_free_chunk(pCtx, (void *)pAux->zDup); ph7_context_free_chunk(pCtx, pAux); (void)ph7_context_pop_aux_data(pCtx); - ph7_result_bool(pCtx, 0); + ph7_result_string(pCtx, "", 0); return PH7_OK; } /* Extract the token */ @@ -5130,7 +5130,7 @@ static int PH7_builtin_strtok(ph7_context *pCtx, int nArg, ph7_value **apArg) { ph7_context_free_chunk(pCtx, (void *)pAux->zDup); ph7_context_free_chunk(pCtx, pAux); (void)ph7_context_pop_aux_data(pCtx); - ph7_result_bool(pCtx, 0); + ph7_result_string(pCtx, "", 0); } else { /* Return the extracted token */ ph7_result_string(pCtx, sToken.zString, (int)sToken.nByte); @@ -5143,7 +5143,7 @@ static int PH7_builtin_strtok(ph7_context *pCtx, int nArg, ph7_value **apArg) { zCur = zInput = ph7_value_to_string(apArg[0], &nLen); if(nLen < 1) { /* Empty input,return FALSE */ - ph7_result_bool(pCtx, 0); + ph7_result_string(pCtx, "", 0); return PH7_OK; } /* Extract the mask */ @@ -5159,7 +5159,7 @@ static int PH7_builtin_strtok(ph7_context *pCtx, int nArg, ph7_value **apArg) { rc = ExtractToken(&zInput, &zInput[nLen], zMask, nMasklen, &sToken); if(rc != SXRET_OK) { /* Empty input */ - ph7_result_bool(pCtx, 0); + ph7_result_string(pCtx, "", 0); return PH7_OK; } else { /* Return the extracted token */ From 0f5073f3fbda9a9e181486d9dc1030d96aa566fe Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 09:45:32 +0100 Subject: [PATCH 167/296] Fix test. --- tests/tokenizer.aer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tokenizer.aer b/tests/tokenizer.aer index 7de9338..4455fb4 100644 --- a/tests/tokenizer.aer +++ b/tests/tokenizer.aer @@ -12,7 +12,7 @@ class StringTokenizer { } public bool hasMoreTokens() { - return ($this->token !== false); + return $this->token ? true : false; } public string nextToken() { From f5960d57b1504fca8b597ba0f2892d17fec4c255 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 19:56:10 +0100 Subject: [PATCH 168/296] Allow static class attributes to store compatible data types only. --- engine/vm.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index 3bfbae2..73945a5 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -639,6 +639,20 @@ static sxi32 VmMountUserClass( /* Initialize attribute default value (any complex expression) */ VmLocalExec(&(*pVm), &pAttr->aByteCode, pMemObj); } + if((pAttr->nType & MEMOBJ_MIXED) == 0) { + if(pAttr->nType != pMemObj->iFlags) { + if(PH7_CheckVarCompat(pMemObj, pAttr->nType) == SXRET_OK) { + ProcMemObjCast xCast = PH7_MemObjCastMethod(pAttr->nType); + xCast(pMemObj); + } else if((pAttr->iFlags & MEMOBJ_HASHMAP) && (pMemObj->iFlags & MEMOBJ_HASHMAP)) { + if(PH7_HashmapCast(pMemObj, pAttr->iFlags ^ MEMOBJ_HASHMAP) != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); + } + } else { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); + } + } + } /* Record attribute index */ pAttr->nIdx = pMemObj->nIdx; /* Install static attribute in the reference table */ From a7137316f7e5c0bbaaf185a2b6236b7ebb0a0064 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 19:59:17 +0100 Subject: [PATCH 169/296] This also seems to be fixed already. --- TODO | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/TODO b/TODO index f7aeaf1..63a5c27 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,4 @@ Below list contains things that should be changed/fixed/implemented. 1. The debug_backtrace() does not show information about arrays type. -2. Array get a type of mixed, if there are at least 2 different types of value specified, even they are compatible, eg. - {4, 5.5} will result in mixed instead of float. - -3. References are completely broken. +2. References are completely broken. From 3f205c19cee5c86eb59fbb33d68f69f69ab6f192 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 22:55:49 +0100 Subject: [PATCH 170/296] Get rid of dirty references. Return a reference & pass-by reference are still working. --- engine/compiler.c | 35 ----- engine/hashmap.c | 233 ++++++--------------------------- engine/memobj.c | 11 +- engine/oop.c | 2 +- engine/parser.c | 9 -- engine/vm.c | 321 ++-------------------------------------------- include/ph7int.h | 7 +- 7 files changed, 55 insertions(+), 563 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index ff6ddf3..3b9d87d 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -794,7 +794,6 @@ static sxi32 PH7_GenStateArrayNodeValidator(ph7_gen_state *pGen, ph7_expr_node * PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag) { sxi32(*xValidator)(ph7_gen_state *, ph7_expr_node *); /* Expression tree validator callback */ SyToken *pKey, *pCur; - sxi32 iEmitRef = 0; sxi32 nPair = 0; sxi32 iNest; sxi32 rc; @@ -862,31 +861,12 @@ PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag) { /* No available key,load NULL */ PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOADC, 0, 0 /* nil index */, 0, 0); } - if(pCur->nType & PH7_TK_AMPER /*'&'*/) { - /* Insertion by reference, [i.e: $a = array(&$x);] */ - xValidator = PH7_GenStateArrayNodeValidator; /* Only variable are allowed */ - iEmitRef = 1; - pCur++; /* Jump the '&' token */ - if(pCur >= pGen->pIn) { - /* Missing value */ - rc = PH7_GenCompileError(&(*pGen), E_ERROR, pCur->nLine, "array(): Missing referenced variable"); - if(rc == SXERR_ABORT) { - return SXERR_ABORT; - } - return SXRET_OK; - } - } /* Compile indice value */ rc = PH7_GenStateCompileArrayEntry(&(*pGen), pCur, pGen->pIn, EXPR_FLAG_RDONLY_LOAD/*Do not create the variable if non-existent*/, xValidator); if(rc == SXERR_ABORT) { return SXERR_ABORT; } - if(iEmitRef) { - /* Emit the load reference instruction */ - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_LOAD_REF, 0, 0, 0, 0); - } xValidator = 0; - iEmitRef = 0; nPair++; } /* Emit the load map instruction */ @@ -5073,21 +5053,6 @@ static sxi32 PH7_GenStateEmitExprCode( (void)PH7_VmPopInstr(pGen->pVm); } } - } else if(iVmOp == PH7_OP_STORE_REF) { - pInstr = PH7_VmPopInstr(pGen->pVm); - if(pInstr) { - if(pInstr->iOp == PH7_OP_LOAD_IDX) { - /* Array insertion by reference [i.e: $pArray[] =& $some_var; ] - * We have to convert the STORE_REF instruction into STORE_IDX_REF - */ - iVmOp = PH7_OP_STORE_IDX_REF; - iP1 = pInstr->iP1; - iP2 = pInstr->iP2; - p3 = pInstr->p3; - } else { - p3 = pInstr->p3; - } - } } } if(iVmOp > 0) { diff --git a/engine/hashmap.c b/engine/hashmap.c index e9bd19d..bd2eaf7 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -16,10 +16,6 @@ /* Allowed node types */ #define HASHMAP_INT_NODE 1 /* Node with an int [i.e: 64-bit integer] key */ #define HASHMAP_BLOB_NODE 2 /* Node with a string/BLOB key */ -/* Node control flags */ -#define HASHMAP_NODE_FOREIGN_OBJ 0x001 /* Node hold a reference to a foreign ph7_value - * [i.e: array(&var)/$a[] =& $var ] - */ /* * Default hash function for int [i.e; 64-bit integer] keys. */ @@ -193,9 +189,7 @@ PH7_PRIVATE void PH7_HashmapUnlinkNode(ph7_hashmap_node *pNode, int bRestore) { /* Remove the ph7_value associated with this node from the reference table */ PH7_VmRefObjRemove(pVm, pNode->nValIdx, 0, pNode); /* Restore to the freelist */ - if((pNode->iFlags & HASHMAP_NODE_FOREIGN_OBJ) == 0) { - PH7_VmUnsetMemObj(pVm, pNode->nValIdx, FALSE); - } + PH7_VmUnsetMemObj(pVm, pNode->nValIdx, FALSE); } if(pNode->iType == HASHMAP_BLOB_NODE) { SyBlobRelease(&pNode->xKey.sKey); @@ -271,26 +265,22 @@ static sxi32 HashmapGrowBucket(ph7_hashmap *pMap) { * Insert a 64-bit integer key and it's associated value (if any) in the given * hashmap. */ -static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValue, sxu32 nRefIdx, int isForeign) { +static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValue, sxu32 nRefIdx) { ph7_hashmap_node *pNode; sxu32 nIdx; sxu32 nHash; sxi32 rc; - if(!isForeign) { - ph7_value *pObj; - /* Reserve a ph7_value for the value */ - pObj = PH7_ReserveMemObj(pMap->pVm); - if(pObj == 0) { - return SXERR_MEM; - } - if(pValue) { - /* Duplicate the value */ - PH7_MemObjStore(pValue, pObj); - } - nIdx = pObj->nIdx; - } else { - nIdx = nRefIdx; + ph7_value *pObj; + /* Reserve a ph7_value for the value */ + pObj = PH7_ReserveMemObj(pMap->pVm); + if(pObj == 0) { + return SXERR_MEM; } + if(pValue) { + /* Duplicate the value */ + PH7_MemObjStore(pValue, pObj); + } + nIdx = pObj->nIdx; /* Hash the key */ nHash = pMap->xIntHash(iKey); /* Allocate a new int node */ @@ -298,10 +288,6 @@ static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValu if(pNode == 0) { return SXERR_MEM; } - if(isForeign) { - /* Mark as a foregin entry */ - pNode->iFlags |= HASHMAP_NODE_FOREIGN_OBJ; - } /* Make sure the bucket is big enough to hold the new entry */ rc = HashmapGrowBucket(&(*pMap)); if(rc != SXRET_OK) { @@ -319,26 +305,22 @@ static sxi32 HashmapInsertIntKey(ph7_hashmap *pMap, sxi64 iKey, ph7_value *pValu * Insert a BLOB key and it's associated value (if any) in the given * hashmap. */ -static sxi32 HashmapInsertBlobKey(ph7_hashmap *pMap, const void *pKey, sxu32 nKeyLen, ph7_value *pValue, sxu32 nRefIdx, int isForeign) { +static sxi32 HashmapInsertBlobKey(ph7_hashmap *pMap, const void *pKey, sxu32 nKeyLen, ph7_value *pValue, sxu32 nRefIdx) { ph7_hashmap_node *pNode; sxu32 nHash; sxu32 nIdx; sxi32 rc; - if(!isForeign) { - ph7_value *pObj; - /* Reserve a ph7_value for the value */ - pObj = PH7_ReserveMemObj(pMap->pVm); - if(pObj == 0) { - return SXERR_MEM; - } - if(pValue) { - /* Duplicate the value */ - PH7_MemObjStore(pValue, pObj); - } - nIdx = pObj->nIdx; - } else { - nIdx = nRefIdx; + ph7_value *pObj; + /* Reserve a ph7_value for the value */ + pObj = PH7_ReserveMemObj(pMap->pVm); + if(pObj == 0) { + return SXERR_MEM; } + if(pValue) { + /* Duplicate the value */ + PH7_MemObjStore(pValue, pObj); + } + nIdx = pObj->nIdx; /* Hash the key */ nHash = pMap->xBlobHash(pKey, nKeyLen); /* Allocate a new blob node */ @@ -346,10 +328,6 @@ static sxi32 HashmapInsertBlobKey(ph7_hashmap *pMap, const void *pKey, sxu32 nKe if(pNode == 0) { return SXERR_MEM; } - if(isForeign) { - /* Mark as a foregin entry */ - pNode->iFlags |= HASHMAP_NODE_FOREIGN_OBJ; - } /* Make sure the bucket is big enough to hold the new entry */ rc = HashmapGrowBucket(&(*pMap)); if(rc != SXRET_OK) { @@ -553,7 +531,7 @@ static sxi32 HashmapInsert( return SXRET_OK; } /* Perform a blob-key insertion */ - rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), &(*pVal), 0, FALSE); + rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), &(*pVal), 0); return rc; } IntKey: @@ -577,7 +555,7 @@ IntKey: return SXRET_OK; } /* Perform a 64-bit-int-key insertion */ - rc = HashmapInsertIntKey(&(*pMap), pKey->x.iVal, &(*pVal), 0, FALSE); + rc = HashmapInsertIntKey(&(*pMap), pKey->x.iVal, &(*pVal), 0); if(rc == SXRET_OK) { if(pKey->x.iVal >= pMap->iNextIdx) { /* Increment the automatic index */ @@ -590,102 +568,7 @@ IntKey: } } else { /* Assign an automatic index */ - rc = HashmapInsertIntKey(&(*pMap), pMap->iNextIdx, &(*pVal), 0, FALSE); - if(rc == SXRET_OK) { - ++pMap->iNextIdx; - } - } - /* Insertion result */ - return rc; -} -/* - * Insert a given key and it's associated value (foreign index) in the given - * hashmap. - * This is insertion by reference so be careful to mark the node - * with the HASHMAP_NODE_FOREIGN_OBJ flag being set. - * The insertion by reference is triggered when the following - * expression is encountered. - * $var = 10; - * $a = array(&var); - * OR - * $a[] =& $var; - * That is,$var is a foreign ph7_value and the $a array have no control - * over it's contents. - * Note that the node that hold the foreign ph7_value is automatically - * removed when the foreign ph7_value is unset. - * Example: - * $var = 10; - * $a[] =& $var; - * echo count($a).PHP_EOL; //1 - * //Unset the foreign ph7_value now - * unset($var); - * echo count($a); //0 - * Note that this is a PH7 eXtension. - * Refer to the official documentation for more information. - * If a node with the given key already exists in the database - * then this function overwrite the old value. - */ -static sxi32 HashmapInsertByRef( - ph7_hashmap *pMap, /* Target hashmap */ - ph7_value *pKey, /* Lookup key */ - sxu32 nRefIdx /* Foreign ph7_value index */ -) { - ph7_hashmap_node *pNode = 0; - sxi32 rc = SXRET_OK; - if(pKey && pKey->iFlags & (MEMOBJ_STRING | MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES)) { - if((pKey->iFlags & MEMOBJ_STRING) == 0) { - /* Force a string cast */ - PH7_MemObjToString(&(*pKey)); - } - if(SyBlobLength(&pKey->sBlob) < 1 || HashmapIsIntKey(&pKey->sBlob)) { - if(SyBlobLength(&pKey->sBlob) < 1) { - /* Automatic index assign */ - pKey = 0; - } - goto IntKey; - } - if(SXRET_OK == HashmapLookupBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), - SyBlobLength(&pKey->sBlob), &pNode)) { - /* Overwrite */ - PH7_VmRefObjRemove(pMap->pVm, pNode->nValIdx, 0, pNode); - pNode->nValIdx = nRefIdx; - /* Install in the reference table */ - PH7_VmRefObjInstall(pMap->pVm, nRefIdx, 0, pNode, 0); - return SXRET_OK; - } - /* Perform a blob-key insertion */ - rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), 0, nRefIdx, TRUE); - return rc; - } -IntKey: - if(pKey) { - if((pKey->iFlags & MEMOBJ_INT) == 0) { - /* Force an integer cast */ - PH7_MemObjToInteger(pKey); - } - if(SXRET_OK == HashmapLookupIntKey(&(*pMap), pKey->x.iVal, &pNode)) { - /* Overwrite */ - PH7_VmRefObjRemove(pMap->pVm, pNode->nValIdx, 0, pNode); - pNode->nValIdx = nRefIdx; - /* Install in the reference table */ - PH7_VmRefObjInstall(pMap->pVm, nRefIdx, 0, pNode, 0); - return SXRET_OK; - } - /* Perform a 64-bit-int-key insertion */ - rc = HashmapInsertIntKey(&(*pMap), pKey->x.iVal, 0, nRefIdx, TRUE); - if(rc == SXRET_OK) { - if(pKey->x.iVal >= pMap->iNextIdx) { - /* Increment the automatic index */ - pMap->iNextIdx = pKey->x.iVal + 1; - /* Make sure the automatic index is not reserved */ - while(SXRET_OK == HashmapLookupIntKey(&(*pMap), pMap->iNextIdx, 0)) { - pMap->iNextIdx++; - } - } - } - } else { - /* Assign an automatic index */ - rc = HashmapInsertIntKey(&(*pMap), pMap->iNextIdx, 0, nRefIdx, TRUE); + rc = HashmapInsertIntKey(&(*pMap), pMap->iNextIdx, &(*pVal), 0); if(rc == SXRET_OK) { ++pMap->iNextIdx; } @@ -693,6 +576,7 @@ IntKey: /* Insertion result */ return rc; } + /* * Extract node value. */ @@ -722,12 +606,12 @@ static sxi32 HashmapInsertNode(ph7_hashmap *pMap, ph7_hashmap_node *pNode, int b /* Assign an automatic index */ rc = HashmapInsert(&(*pMap), 0, pObj); } else { - rc = HashmapInsertIntKey(&(*pMap), pNode->xKey.iKey, pObj, 0, FALSE); + rc = HashmapInsertIntKey(&(*pMap), pNode->xKey.iKey, pObj, 0); } } else { /* Blob key */ rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pNode->xKey.sKey), - SyBlobLength(&pNode->xKey.sKey), pObj, 0, FALSE); + SyBlobLength(&pNode->xKey.sKey), pObj, 0); } return rc; } @@ -821,8 +705,8 @@ static int HashmapFindValue( pVal = HashmapExtractNodeValue(pEntry); if(pVal) { if((pVal->iFlags | pNeedle->iFlags) & MEMOBJ_NULL) { - sxi32 iF1 = pVal->iFlags & ~MEMOBJ_AUX; - sxi32 iF2 = pNeedle->iFlags & ~MEMOBJ_AUX; + sxi32 iF1 = pVal->iFlags; + sxi32 iF2 = pNeedle->iFlags; if(iF1 == iF2) { /* NULL values are equals */ if(ppNode) { @@ -1144,7 +1028,7 @@ PH7_PRIVATE sxi32 PH7_HashmapDup(ph7_hashmap *pSrc, ph7_hashmap *pDest) { PH7_MemObjRelease(&sKey); } else { /* Int key insertion */ - rc = HashmapInsertIntKey(&(*pDest), pEntry->xKey.iKey, pVal, 0, FALSE); + rc = HashmapInsertIntKey(&(*pDest), pEntry->xKey.iKey, pVal, 0); } if(rc != SXRET_OK) { return rc; @@ -1214,7 +1098,7 @@ PH7_PRIVATE sxi32 PH7_HashmapUnion(ph7_hashmap *pLeft, ph7_hashmap *pRight) { if(pObj) { /* Perform the insertion */ rc = HashmapInsertBlobKey(&(*pLeft), SyBlobData(&pEntry->xKey.sKey), SyBlobLength(&pEntry->xKey.sKey), - pObj, 0, FALSE); + pObj, 0); if(rc != SXRET_OK) { return rc; } @@ -1226,7 +1110,7 @@ PH7_PRIVATE sxi32 PH7_HashmapUnion(ph7_hashmap *pLeft, ph7_hashmap *pRight) { pObj = HashmapExtractNodeValue(pEntry); if(pObj) { /* Perform the insertion */ - rc = HashmapInsertIntKey(&(*pLeft), pEntry->xKey.iKey, pObj, 0, FALSE); + rc = HashmapInsertIntKey(&(*pLeft), pEntry->xKey.iKey, pObj, 0); if(rc != SXRET_OK) { return rc; } @@ -1345,10 +1229,8 @@ PH7_PRIVATE sxi32 PH7_HashmapRelease(ph7_hashmap *pMap, int FreeDS) { pNext = pEntry->pPrev; /* Reverse link */ /* Remove the reference from the foreign table */ PH7_VmRefObjRemove(pVm, pEntry->nValIdx, 0, pEntry); - if((pEntry->iFlags & HASHMAP_NODE_FOREIGN_OBJ) == 0) { - /* Restore the ph7_value to the free list */ - PH7_VmUnsetMemObj(pVm, pEntry->nValIdx, FALSE); - } + /* Restore the ph7_value to the free list */ + PH7_VmUnsetMemObj(pVm, pEntry->nValIdx, FALSE); /* Release the node */ if(pEntry->iType == HASHMAP_BLOB_NODE) { SyBlobRelease(&pEntry->xKey.sKey); @@ -1419,40 +1301,7 @@ PH7_PRIVATE sxi32 PH7_HashmapInsert( ) { return HashmapInsert(&(*pMap), &(*pKey), &(*pVal)); } -/* - * Insert a given key and it's associated value (foreign index) in the given - * hashmap. - * This is insertion by reference so be careful to mark the node - * with the HASHMAP_NODE_FOREIGN_OBJ flag being set. - * The insertion by reference is triggered when the following - * expression is encountered. - * $var = 10; - * $a = array(&var); - * OR - * $a[] =& $var; - * That is,$var is a foreign ph7_value and the $a array have no control - * over it's contents. - * Note that the node that hold the foreign ph7_value is automatically - * removed when the foreign ph7_value is unset. - * Example: - * $var = 10; - * $a[] =& $var; - * echo count($a).PHP_EOL; //1 - * //Unset the foreign ph7_value now - * unset($var); - * echo count($a); //0 - * Note that this is a PH7 eXtension. - * Refer to the official documentation for more information. - * If a node with the given key already exists in the database - * then this function overwrite the old value. - */ -PH7_PRIVATE sxi32 PH7_HashmapInsertByRef( - ph7_hashmap *pMap, /* Target hashmap */ - ph7_value *pKey, /* Lookup key */ - sxu32 nRefIdx /* Foreign ph7_value index */ -) { - return HashmapInsertByRef(&(*pMap), &(*pKey), nRefIdx); -} + /* * Reset the node cursor of a given hashmap. */ @@ -5500,7 +5349,6 @@ PH7_PRIVATE sxi32 PH7_HashmapDump(SyBlob *pOut, ph7_hashmap *pMap, int ShowType, ph7_hashmap_node *pEntry; ph7_value *pObj; sxu32 n = 0; - int isRef; sxi32 rc; int i; if(nDepth > 31) { @@ -5547,13 +5395,8 @@ PH7_PRIVATE sxi32 PH7_HashmapDump(SyBlob *pOut, ph7_hashmap *pMap, int ShowType, #endif /* Dump node value */ pObj = HashmapExtractNodeValue(pEntry); - isRef = 0; if(pObj) { - if(pEntry->iFlags & HASHMAP_NODE_FOREIGN_OBJ) { - /* Referenced object */ - isRef = 1; - } - rc = PH7_MemObjDump(&(*pOut), pObj, ShowType, nTab + 1, nDepth, isRef); + rc = PH7_MemObjDump(&(*pOut), pObj, ShowType, nTab + 1, nDepth); if(rc == SXERR_LIMIT) { break; } diff --git a/engine/memobj.c b/engine/memobj.c index 2c3a0ef..0bc5daa 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -812,7 +812,6 @@ PH7_PRIVATE sxi32 PH7_MemObjStore(ph7_value *pSrc, ph7_value *pDest) { pObj = (ph7_class_instance *)pDest->x.pOther; } SyMemcpy((const void *) & (*pSrc), &(*pDest), sizeof(ph7_value) - (sizeof(ph7_vm *) + sizeof(SyBlob) + sizeof(sxu32))); - pDest->iFlags &= ~MEMOBJ_AUX; rc = SXRET_OK; if(SyBlobLength(&pSrc->sBlob) > 0) { SyBlobReset(&pDest->sBlob); @@ -931,8 +930,8 @@ PH7_PRIVATE sxi32 PH7_MemObjCmp(ph7_value *pObj1, ph7_value *pObj2, int bStrict, if(bStrict) { sxi32 iF1, iF2; /* Strict comparisons with === */ - iF1 = pObj1->iFlags & ~MEMOBJ_AUX; - iF2 = pObj2->iFlags & ~MEMOBJ_AUX; + iF1 = pObj1->iFlags; + iF2 = pObj2->iFlags; if(iF1 != iF2) { /* Not of the same type */ return 1; @@ -1206,8 +1205,7 @@ PH7_PRIVATE sxi32 PH7_MemObjDump( ph7_value *pObj, /* Dump this */ int ShowType, /* TRUE to output value type */ int nTab, /* # of Whitespace to insert */ - int nDepth, /* Nesting level */ - int isRef /* TRUE if referenced object */ + int nDepth /* Nesting level */ ) { sxi32 rc = SXRET_OK; const char *zType; @@ -1216,9 +1214,6 @@ PH7_PRIVATE sxi32 PH7_MemObjDump( SyBlobAppend(&(*pOut), " ", sizeof(char)); } if(ShowType) { - if(isRef) { - SyBlobAppend(&(*pOut), "&", sizeof(char)); - } /* Get value type first */ zType = PH7_MemObjTypeDump(pObj); SyBlobAppend(&(*pOut), zType, SyStrlen(zType)); diff --git a/engine/oop.c b/engine/oop.c index 25693f1..de4311c 100644 --- a/engine/oop.c +++ b/engine/oop.c @@ -929,7 +929,7 @@ PH7_PRIVATE sxi32 PH7_ClassInstanceDump(SyBlob *pOut, ph7_class_instance *pThis, #else SyBlobAppend(&(*pOut), "\n", sizeof(char)); #endif - rc = PH7_MemObjDump(&(*pOut), pValue, ShowType, nTab + 1, nDepth, 0); + rc = PH7_MemObjDump(&(*pOut), pValue, ShowType, nTab + 1, nDepth); if(rc == SXERR_LIMIT) { break; } diff --git a/engine/parser.c b/engine/parser.c index aba3400..ef69bcd 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -209,8 +209,6 @@ static const ph7_expr_op aOpTable[] = { { {"!==", sizeof(char) * 3}, EXPR_OP_TNE, 11, EXPR_OP_NON_ASSOC, PH7_OP_TNE}, /* Precedence 12,left-associative */ { {"&", sizeof(char)}, EXPR_OP_BAND, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_BAND}, - /* Precedence 12,left-associative */ - { {"=&", sizeof(char) * 2}, EXPR_OP_REF, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_STORE_REF}, /* Binary operators */ /* Precedence 13,left-associative */ { {"^", sizeof(char)}, EXPR_OP_XOR, 13, EXPR_OP_ASSOC_LEFT, PH7_OP_BXOR}, @@ -859,13 +857,6 @@ static sxi32 ExprProcessFuncArguments(ph7_gen_state *pGen, ph7_expr_node *pOp, p iCur++; } if(iCur > iNode) { - if(apNode[iNode] && (apNode[iNode]->pStart->nType & PH7_TK_AMPER /*'&'*/) && ((iCur - iNode) == 2) - && apNode[iNode + 1]->xCode == PH7_CompileVariable) { - PH7_GenCompileError(&(*pGen), E_WARNING, apNode[iNode]->pStart->nLine, - "call-time pass-by-reference is deprecated"); - ExprFreeTree(&(*pGen), apNode[iNode]); - apNode[iNode] = 0; - } ExprMakeTree(&(*pGen), &apNode[iNode], iCur - iNode); if(apNode[iNode]) { /* Put a pointer to the root of the tree in the arguments set */ diff --git a/engine/vm.c b/engine/vm.c index 73945a5..627ff7a 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1324,24 +1324,6 @@ PH7_PRIVATE ph7_value *PH7_ReserveMemObj(ph7_vm *pVm) { pObj->nIdx = nIdx; return pObj; } -/* - * Insert an entry by reference (not copy) in the given hashmap. - */ -static sxi32 VmHashmapRefInsert( - ph7_hashmap *pMap, /* Target hashmap */ - const char *zKey, /* Entry key */ - sxu32 nByte, /* Key length */ - sxu32 nRefIdx /* Entry index in the object pool */ -) { - ph7_value sKey; - sxi32 rc; - PH7_MemObjInitFromString(pMap->pVm, &sKey, 0); - PH7_MemObjStringAppend(&sKey, zKey, nByte); - /* Perform the insertion */ - rc = PH7_HashmapInsertByRef(&(*pMap), &sKey, nRefIdx); - PH7_MemObjRelease(&sKey); - return rc; -} /* * Extract a variable value from the top active VM frame. * Return a pointer to the variable value on success. @@ -2492,26 +2474,14 @@ static sxi32 VmByteCodeExec( iFlags = pEntry[1].iFlags; /* Save the type of value */ /* Perform the insertion */ while(pEntry < pTos) { - if(pEntry[1].iFlags & MEMOBJ_REFERENCE) { - /* Insertion by reference */ - PH7_HashmapInsertByRef(pMap, - (pEntry->iFlags & MEMOBJ_NULL) ? 0 /* Automatic index assign */ : pEntry, - (sxu32)pEntry[1].x.iVal - ); - } else { - /* Standard insertion */ - PH7_HashmapInsert(pMap, - (pEntry->iFlags & MEMOBJ_NULL) ? 0 /* Automatic index assign */ : pEntry, - &pEntry[1] - ); - } + /* Standard insertion */ + PH7_HashmapInsert(pMap, + (pEntry->iFlags & MEMOBJ_NULL) ? 0 /* Automatic index assign */ : pEntry, + &pEntry[1] + ); /* Set the proper type of array */ if((iFlags & MEMOBJ_MIXED) == 0) { - if(pEntry[1].iFlags & MEMOBJ_REFERENCE) { - pFlags = pEntry[1].iFlags ^ MEMOBJ_REFERENCE; - } else { - pFlags = pEntry[1].iFlags; - } + pFlags = pEntry[1].iFlags; if(iFlags != pFlags && iFlags != (pFlags ^ MEMOBJ_HASHMAP)) { iFlags = MEMOBJ_MIXED; } @@ -2801,12 +2771,10 @@ static sxi32 VmByteCodeExec( } /* * STORE_IDX: P1 * P3 - * STORE_IDX_R: P1 * P3 * * Perfrom a store operation an a hashmap entry. */ - case PH7_OP_STORE_IDX: - case PH7_OP_STORE_IDX_REF: { + case PH7_OP_STORE_IDX: { ph7_hashmap *pMap = 0; /* cc warning */ ph7_value *pKey; sxu32 nIdx; @@ -2836,7 +2804,7 @@ static sxi32 VmByteCodeExec( break; } /* Phase#1: Load the array */ - if((pObj->iFlags & MEMOBJ_STRING) && (pInstr->iOp != PH7_OP_STORE_IDX_REF)) { + if(pObj->iFlags & MEMOBJ_STRING) { VmPopOperand(&pTos, 1); if((pTos->iFlags & MEMOBJ_STRING) == 0) { /* Force a string cast */ @@ -2880,12 +2848,7 @@ static sxi32 VmByteCodeExec( } VmPopOperand(&pTos, 1); /* Phase#2: Perform the insertion */ - if(pInstr->iOp == PH7_OP_STORE_IDX_REF && pTos->nIdx != SXU32_HIGH) { - /* Insertion by reference */ - PH7_HashmapInsertByRef(pMap, pKey, pTos->nIdx); - } else { - PH7_HashmapInsert(pMap, pKey, pTos); - } + PH7_HashmapInsert(pMap, pKey, pTos); if(pKey) { PH7_MemObjRelease(pKey); } @@ -3958,96 +3921,6 @@ static sxi32 VmByteCodeExec( } break; } - /* - * OP_LOAD_REF * * * - * Push the index of a referenced object on the stack. - */ - case PH7_OP_LOAD_REF: { - sxu32 nIdx; -#ifdef UNTRUST - if(pTos < pStack) { - goto Abort; - } -#endif - /* Extract memory object index */ - nIdx = pTos->nIdx; - if(nIdx != SXU32_HIGH /* Not a constant */) { - /* Nullify the object */ - PH7_MemObjRelease(pTos); - /* Mark as constant and store the index on the top of the stack */ - pTos->x.iVal = (sxi64)nIdx; - pTos->nIdx = SXU32_HIGH; - pTos->iFlags = MEMOBJ_INT | MEMOBJ_REFERENCE; - } - break; - } - /* - * OP_STORE_REF * * P3 - * Perform an assignment operation by reference. - */ - case PH7_OP_STORE_REF: { - SyString sName = { 0, 0 }; - SyHashEntry *pEntry; - sxu32 nIdx; -#ifdef UNTRUST - if(pTos < pStack) { - goto Abort; - } -#endif - if(pInstr->p3 == 0) { - char *zName; - /* Take the variable name from the Next on the stack */ - if((pTos->iFlags & MEMOBJ_STRING) == 0) { - /* Force a string cast */ - PH7_MemObjToString(pTos); - } - if(SyBlobLength(&pTos->sBlob) > 0) { - zName = SyMemBackendStrDup(&pVm->sAllocator, - (const char *)SyBlobData(&pTos->sBlob), SyBlobLength(&pTos->sBlob)); - if(zName) { - SyStringInitFromBuf(&sName, zName, SyBlobLength(&pTos->sBlob)); - } - } - PH7_MemObjRelease(pTos); - pTos--; - } else { - SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3)); - } - nIdx = pTos->nIdx; - if(nIdx == SXU32_HIGH) { - if((pTos->iFlags & (MEMOBJ_OBJ | MEMOBJ_HASHMAP | MEMOBJ_RES)) == 0) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, - "Reference operator require a variable not a constant as it's right operand"); - } else { - ph7_value *pObj; - /* Extract the desired variable and if not available dynamically create it */ - pObj = VmExtractMemObj(&(*pVm), &sName, FALSE, TRUE); - if(pObj == 0) { - PH7_VmMemoryError(&(*pVm)); - } - /* Perform the store operation */ - PH7_MemObjStore(pTos, pObj); - pTos->nIdx = pObj->nIdx; - } - } else if(sName.nByte > 0) { - VmFrame *pFrame = pVm->pFrame; - while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) { - /* Safely ignore the exception frame */ - pFrame = pFrame->pParent; - } - /* Query the local frame */ - pEntry = SyHashGet(&pFrame->hVar, (const void *)sName.zString, sName.nByte); - if(pEntry) { - rc = SyHashInsert(&pFrame->hVar, (const void *)sName.zString, sName.nByte, SX_INT_TO_PTR(nIdx)); - if(rc == SXRET_OK) { - PH7_VmRefObjInstall(&(*pVm), nIdx, SyHashLastEntry(&pFrame->hVar), 0, 0); - } - } else { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Referenced variable name '%z' does not exists", &sName); - } - } - break; - } /* * OP_LOAD_EXCEPTION * P2 P3 * Push an exception in the corresponding container so that @@ -5668,9 +5541,6 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_STORE_IDX: zOp = "STORE_IDX"; break; - case PH7_OP_STORE_IDX_REF: - zOp = "STORE_IDX_R"; - break; case PH7_OP_PULL: zOp = "PULL"; break; @@ -5734,12 +5604,6 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_CONSUME: zOp = "CONSUME"; break; - case PH7_OP_LOAD_REF: - zOp = "LOAD_REF"; - break; - case PH7_OP_STORE_REF: - zOp = "STORE_REF"; - break; case PH7_OP_MEMBER: zOp = "MEMBER"; break; @@ -5812,163 +5676,6 @@ PH7_PRIVATE void PH7_VmExpandConstantValue(ph7_value *pVal, void *pUserData) { * Status: * Stable. */ -/* - * int func_num_args(void) - * Returns the number of arguments passed to the function. - * Parameters - * None. - * Return - * Total number of arguments passed into the current user-defined function - * or -1 if called from the globe scope. - */ -static int vm_builtin_func_num_args(ph7_context *pCtx, int nArg, ph7_value **apArg) { - VmFrame *pFrame; - ph7_vm *pVm; - /* Point to the target VM */ - pVm = pCtx->pVm; - /* Current frame */ - pFrame = pVm->pFrame; - while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) { - /* Safely ignore the exception frame */ - pFrame = pFrame->pParent; - } - if(pFrame->pParent == 0) { - SXUNUSED(nArg); - SXUNUSED(apArg); - /* Global frame,return -1 */ - ph7_result_int(pCtx, -1); - return SXRET_OK; - } - /* Total number of arguments passed to the enclosing function */ - nArg = (int)SySetUsed(&pFrame->sArg); - ph7_result_int(pCtx, nArg); - return SXRET_OK; -} -/* - * value func_get_arg(int $arg_num) - * Return an item from the argument list. - * Parameters - * Argument number(index start from zero). - * Return - * Returns the specified argument or FALSE on error. - */ -static int vm_builtin_func_get_arg(ph7_context *pCtx, int nArg, ph7_value **apArg) { - ph7_value *pObj = 0; - VmSlot *pSlot = 0; - VmFrame *pFrame; - ph7_vm *pVm; - /* Point to the target VM */ - pVm = pCtx->pVm; - /* Current frame */ - pFrame = pVm->pFrame; - while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) { - /* Safely ignore the exception frame */ - pFrame = pFrame->pParent; - } - /* Extract the desired index */ - nArg = ph7_value_to_int(apArg[0]); - if(nArg < 0 || nArg >= (int)SySetUsed(&pFrame->sArg)) { - /* Invalid index,return FALSE */ - ph7_result_bool(pCtx, 0); - return SXRET_OK; - } - /* Extract the desired argument */ - if((pSlot = (VmSlot *)SySetAt(&pFrame->sArg, (sxu32)nArg)) != 0) { - if((pObj = (ph7_value *)SySetAt(&pVm->aMemObj, pSlot->nIdx)) != 0) { - /* Return the desired argument */ - ph7_result_value(pCtx, (ph7_value *)pObj); - } else { - /* No such argument,return false */ - ph7_result_bool(pCtx, 0); - } - } else { - /* CAN'T HAPPEN */ - ph7_result_bool(pCtx, 0); - } - return SXRET_OK; -} -/* - * array func_get_args_byref(void) - * Returns an array comprising a function's argument list. - * Parameters - * None. - * Return - * Returns an array in which each element is a POINTER to the corresponding - * member of the current user-defined function's argument list. - * Otherwise FALSE is returned on failure. - * NOTE: - * Arguments are returned to the array by reference. - */ -static int vm_builtin_func_get_args_byref(ph7_context *pCtx, int nArg, ph7_value **apArg) { - ph7_value *pArray; - VmFrame *pFrame; - VmSlot *aSlot; - sxu32 n; - /* Point to the current frame */ - pFrame = pCtx->pVm->pFrame; - while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) { - /* Safely ignore the exception frame */ - pFrame = pFrame->pParent; - } - /* Create a new array */ - pArray = ph7_context_new_array(pCtx); - if(pArray == 0) { - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - ph7_result_bool(pCtx, 0); - return SXRET_OK; - } - /* Start filling the array with the given arguments (Pass by reference) */ - aSlot = (VmSlot *)SySetBasePtr(&pFrame->sArg); - for(n = 0; n < SySetUsed(&pFrame->sArg) ; n++) { - PH7_HashmapInsertByRef((ph7_hashmap *)pArray->x.pOther, 0/*Automatic index assign*/, aSlot[n].nIdx); - } - /* Return the freshly created array */ - ph7_result_value(pCtx, pArray); - return SXRET_OK; -} -/* - * array func_get_args(void) - * Returns an array comprising a copy of function's argument list. - * Parameters - * None. - * Return - * Returns an array in which each element is a copy of the corresponding - * member of the current user-defined function's argument list. - * Otherwise FALSE is returned on failure. - */ -static int vm_builtin_func_get_args(ph7_context *pCtx, int nArg, ph7_value **apArg) { - ph7_value *pObj = 0; - ph7_value *pArray; - VmFrame *pFrame; - VmSlot *aSlot; - sxu32 n; - /* Point to the current frame */ - pFrame = pCtx->pVm->pFrame; - while(pFrame->pParent && (pFrame->iFlags & VM_FRAME_EXCEPTION)) { - /* Safely ignore the exception frame */ - pFrame = pFrame->pParent; - } - /* Create a new array */ - pArray = ph7_context_new_array(pCtx); - if(pArray == 0) { - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - ph7_result_bool(pCtx, 0); - return SXRET_OK; - } - /* Start filling the array with the given arguments */ - aSlot = (VmSlot *)SySetBasePtr(&pFrame->sArg); - for(n = 0; n < SySetUsed(&pFrame->sArg) ; n++) { - pObj = (ph7_value *)SySetAt(&pCtx->pVm->aMemObj, aSlot[n].nIdx); - if(pObj) { - ph7_array_add_elem(pArray, 0/* Automatic index assign*/, pObj); - } - } - /* Return the freshly created array */ - ph7_result_value(pCtx, pArray); - return SXRET_OK; -} /* * bool function_exists(string $name) * Return TRUE if the given function has been defined. @@ -8491,7 +8198,7 @@ static int vm_builtin_var_dump(ph7_context *pCtx, int nArg, ph7_value **apArg) { /* Reset the working buffer */ SyBlobReset(&sDump); /* Dump the given expression */ - PH7_MemObjDump(&sDump, pObj, TRUE, 0, 0, 0); + PH7_MemObjDump(&sDump, pObj, TRUE, 0, 0); /* Output */ if(SyBlobLength(&sDump) > 0) { ph7_context_output(pCtx, (const char *)SyBlobData(&sDump), (int)SyBlobLength(&sDump)); @@ -8527,7 +8234,7 @@ static int vm_builtin_print_r(ph7_context *pCtx, int nArg, ph7_value **apArg) { ret_string = ph7_value_to_bool(apArg[1]); } /* Generate dump */ - PH7_MemObjDump(&sDump, apArg[0], FALSE, 0, 0, 0); + PH7_MemObjDump(&sDump, apArg[0], FALSE, 0, 0); if(!ret_string) { /* Output dump */ ph7_context_output(pCtx, (const char *)SyBlobData(&sDump), (int)SyBlobLength(&sDump)); @@ -8559,7 +8266,7 @@ static int vm_builtin_var_export(ph7_context *pCtx, int nArg, ph7_value **apArg) ret_string = ph7_value_to_bool(apArg[1]); } /* Generate dump */ - PH7_MemObjDump(&sDump, apArg[0], FALSE, 0, 0, 0); + PH7_MemObjDump(&sDump, apArg[0], FALSE, 0, 0); if(!ret_string) { /* Output dump */ ph7_context_output(pCtx, (const char *)SyBlobData(&sDump), (int)SyBlobLength(&sDump)); @@ -10841,10 +10548,6 @@ static int vm_builtin_utf8_decode(ph7_context *pCtx, int nArg, ph7_value **apArg } /* Table of built-in VM functions. */ static const ph7_builtin_func aVmFunc[] = { - { "func_num_args", vm_builtin_func_num_args }, - { "func_get_arg", vm_builtin_func_get_arg }, - { "func_get_args", vm_builtin_func_get_args }, - { "func_get_args_byref", vm_builtin_func_get_args_byref }, { "function_exists", vm_builtin_func_exists }, { "is_callback", vm_builtin_is_callback }, { "get_defined_functions", vm_builtin_get_defined_func }, diff --git a/include/ph7int.h b/include/ph7int.h index 8baa177..c19263e 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -641,7 +641,6 @@ struct ph7_value { #define MEMOBJ_STRING 0x0080 /* Memory value is a UTF-8 string */ #define MEMOBJ_VOID 0x0100 /* Memory value is a void */ #define MEMOBJ_MIXED 0x0200 /* Memory value is mixed */ -#define MEMOBJ_REFERENCE 0x0400 /* Memory value hold a reference (64-bit index) of another ph7_value */ #define MEMOBJ_HASHMAP 0x0800 /* Memory value is a hashmap aka 'array' in the PHP jargon */ #define MEMOBJ_NULL 0x1000 /* Memory value is NULL */ /* Mask of all known types */ @@ -652,7 +651,6 @@ struct ph7_value { * Types array, object and resource are not scalar. */ #define MEMOBJ_SCALAR (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_CHAR|MEMOBJ_VOID|MEMOBJ_NULL) -#define MEMOBJ_AUX (MEMOBJ_REFERENCE) /* * The following macro clear the current ph7_value type and replace * it with the given one. @@ -1453,8 +1451,6 @@ enum ph7_vm_op { PH7_OP_BOR_STORE, /* Bitor and store '|=' */ PH7_OP_BXOR_STORE, /* Bitxor and store '^=' */ PH7_OP_CONSUME, /* Consume VM output */ - PH7_OP_LOAD_REF, /* Load reference */ - PH7_OP_STORE_REF, /* Store a reference to a variable*/ PH7_OP_MEMBER, /* Class member run-time access */ PH7_OP_CVT_OBJ, /* Object cast */ PH7_OP_CVT_CALL, /* Callback cast */ @@ -1626,7 +1622,7 @@ enum json_err_code { JSON_ERROR_UTF8 /* Malformed UTF-8 characters */ }; /* memobj.c function prototypes */ -PH7_PRIVATE sxi32 PH7_MemObjDump(SyBlob *pOut, ph7_value *pObj, int ShowType, int nTab, int nDepth, int isRef); +PH7_PRIVATE sxi32 PH7_MemObjDump(SyBlob *pOut, ph7_value *pObj, int ShowType, int nTab, int nDepth); PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal); PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStore); PH7_PRIVATE sxi32 PH7_MemObjCmp(ph7_value *pObj1, ph7_value *pObj2, int bStrict, int iNest); @@ -1739,7 +1735,6 @@ PH7_PRIVATE sxi32 PH7_HashmapRelease(ph7_hashmap *pMap, int FreeDS); PH7_PRIVATE void PH7_HashmapUnref(ph7_hashmap *pMap); PH7_PRIVATE sxi32 PH7_HashmapLookup(ph7_hashmap *pMap, ph7_value *pKey, ph7_hashmap_node **ppNode); PH7_PRIVATE sxi32 PH7_HashmapInsert(ph7_hashmap *pMap, ph7_value *pKey, ph7_value *pVal); -PH7_PRIVATE sxi32 PH7_HashmapInsertByRef(ph7_hashmap *pMap, ph7_value *pKey, sxu32 nRefIdx); PH7_PRIVATE sxi32 PH7_HashmapUnion(ph7_hashmap *pLeft, ph7_hashmap *pRight); PH7_PRIVATE void PH7_HashmapUnlinkNode(ph7_hashmap_node *pNode, int bRestore); PH7_PRIVATE sxi32 PH7_HashmapDup(ph7_hashmap *pSrc, ph7_hashmap *pDest); From 8a87dcbcdca59794743aaa4f7f91d7cd0f1263a4 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 22:59:59 +0100 Subject: [PATCH 171/296] Not any longer. --- TODO | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/TODO b/TODO index 63a5c27..3a693bc 100644 --- a/TODO +++ b/TODO @@ -2,6 +2,4 @@ TODO list for typehinting branch. Below list contains things that should be changed/fixed/implemented. -1. The debug_backtrace() does not show information about arrays type. - -2. References are completely broken. +1. The debug_backtrace() does not show information about arrays type. \ No newline at end of file From 9b741175f2c4994e49ec839f292ee5a06b8abc54 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 23:17:50 +0100 Subject: [PATCH 172/296] Uppercase. --- engine/memobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index 0bc5daa..cfd9dde 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -1150,7 +1150,7 @@ PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStor PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { const char *zType = ""; if(pVal->iFlags & MEMOBJ_NULL) { - zType = "null"; + zType = "NULL"; } else { if(pVal->iFlags & MEMOBJ_HASHMAP) { if(pVal->iFlags & MEMOBJ_MIXED) { From 4f6be2234e586c96ee3cd36ef452d9c480dab56c Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 29 Mar 2019 23:51:20 +0100 Subject: [PATCH 173/296] Allow NULL to be assigned to any type of variable. NULL will be automatically typecasted to any data type, thus setting ti the default value. --- engine/memobj.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index cfd9dde..13cce68 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -363,7 +363,9 @@ static ph7_real MemObjCharValue(ph7_value *pObj) { * Checks a ph7_value variable compatibility with nType data type. */ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { - if(((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0)) { + if(pObj->iFlags & MEMOBJ_NULL) { + return SXRET_OK; + } else if(((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0)) { if((nType & MEMOBJ_REAL) && (pObj->iFlags & MEMOBJ_INT)) { return SXRET_OK; } else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_INT)) { From 629484fcf61e0e217dac808815d570b64206af46 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 30 Mar 2019 19:52:51 +0100 Subject: [PATCH 174/296] Make a use of NULL operator. --- tests/tokenizer.aer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tokenizer.aer b/tests/tokenizer.aer index 4455fb4..6d922af 100644 --- a/tests/tokenizer.aer +++ b/tests/tokenizer.aer @@ -12,7 +12,7 @@ class StringTokenizer { } public bool hasMoreTokens() { - return $this->token ? true : false; + return ($this->token != NULL); } public string nextToken() { From 253fe327ef168852af55fe6322fe215153acc8bf Mon Sep 17 00:00:00 2001 From: belliash Date: Sun, 31 Mar 2019 14:04:19 +0200 Subject: [PATCH 175/296] Automatically fallback mixed variable to void (NULL). --- engine/vm.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 627ff7a..ad68062 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2431,15 +2431,19 @@ static sxi32 VmByteCodeExec( PH7_MemObjRelease(pTos); } else { pObj = VmExtractMemObj(&(*pVm), &sName, FALSE, TRUE); - if(pInstr->iP2 & MEMOBJ_HASHMAP) { - ph7_hashmap *pMap; - pMap = PH7_NewHashmap(&(*pVm), 0, 0); - if(pMap == 0) { - PH7_VmMemoryError(&(*pVm)); + if(pInstr->iP2 & MEMOBJ_MIXED && (pInstr->iP2 & MEMOBJ_HASHMAP) == 0) { + pObj->iFlags = MEMOBJ_MIXED | MEMOBJ_VOID; + } else { + if(pInstr->iP2 & MEMOBJ_HASHMAP) { + ph7_hashmap *pMap; + pMap = PH7_NewHashmap(&(*pVm), 0, 0); + if(pMap == 0) { + PH7_VmMemoryError(&(*pVm)); + } + pObj->x.pOther = pMap; } - pObj->x.pOther = pMap; + MemObjSetType(pObj, pInstr->iP2); } - MemObjSetType(pObj, pInstr->iP2); } pTos->nIdx = SXU32_HIGH; /* Mark as constant */ break; From 2fb123872fee58ffc0e1a7407bccecdd71b07971 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 2 Apr 2019 09:05:27 +0200 Subject: [PATCH 176/296] Typecas array only if it is of different type. --- engine/hashmap.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/engine/hashmap.c b/engine/hashmap.c index bd2eaf7..0ae47c1 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -5476,26 +5476,28 @@ PH7_PRIVATE sxi32 PH7_HashmapWalk( PH7_PRIVATE sxi32 PH7_HashmapCast(ph7_value *pObj, sxi32 nType) { sxi32 rc; if((pObj->iFlags & MEMOBJ_HASHMAP)) { - ph7_hashmap *pMap; - ph7_hashmap_node *pNode; - ph7_value pValue, pKey; - pMap = (ph7_hashmap *) pObj->x.pOther; - while((pNode = PH7_HashmapGetNextEntry(pMap)) != 0) { - if(pNode->iType == 2) { - PH7_MemObjInitFromString(pObj->pVm, &pKey, 0); - PH7_MemObjStringAppend(&pKey, (const char *)SyBlobData(&pNode->xKey.sKey), SyBlobLength(&pNode->xKey.sKey)); - } else { - PH7_MemObjInitFromInt(pObj->pVm, &pKey, pNode->xKey.iKey); + if((pObj->iFlags & nType) == 0) { + ph7_hashmap *pMap; + ph7_hashmap_node *pNode; + ph7_value pValue, pKey; + pMap = (ph7_hashmap *) pObj->x.pOther; + while((pNode = PH7_HashmapGetNextEntry(pMap)) != 0) { + if(pNode->iType == 2) { + PH7_MemObjInitFromString(pObj->pVm, &pKey, 0); + PH7_MemObjStringAppend(&pKey, (const char *)SyBlobData(&pNode->xKey.sKey), SyBlobLength(&pNode->xKey.sKey)); + } else { + PH7_MemObjInitFromInt(pObj->pVm, &pKey, pNode->xKey.iKey); + } + PH7_MemObjInit(pObj->pVm, &pValue); + PH7_HashmapExtractNodeValue(pNode, &pValue, FALSE); + rc = PH7_HashmapCast(&pValue, nType); + if(rc == SXERR_NOMATCH) { + return SXERR_NOMATCH; + } + PH7_HashmapInsert(pMap, &pKey, &pValue); } - PH7_MemObjInit(pObj->pVm, &pValue); - PH7_HashmapExtractNodeValue(pNode, &pValue, FALSE); - rc = PH7_HashmapCast(&pValue, nType); - if(rc == SXERR_NOMATCH) { - return SXERR_NOMATCH; - } - PH7_HashmapInsert(pMap, &pKey, &pValue); + pObj->iFlags = MEMOBJ_HASHMAP | nType; } - pObj->iFlags = MEMOBJ_HASHMAP | nType; } else { if(pObj->iFlags != nType && PH7_CheckVarCompat(pObj, nType) != SXRET_OK) { return SXERR_NOMATCH; From c6397d2e15308ae32020b1bbb9e4c70c146b8c8d Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 2 Apr 2019 09:55:01 +0200 Subject: [PATCH 177/296] Use P2 to avoid strict typehinting. --- engine/compiler.c | 2 +- engine/vm.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 3b9d87d..6420160 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -1406,7 +1406,7 @@ static sxi32 PH7_CompileConstant(ph7_gen_state *pGen) { /* Compile constant value */ rc = PH7_CompileExpr(&(*pGen), 0, 0); /* Emit the done instruction */ - PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0); + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 1, 0, 0); PH7_VmSetByteCodeContainer(pGen->pVm, pInstrContainer); if(rc == SXERR_ABORT) { /* Don't worry about freeing memory, everything will be released shortly */ diff --git a/engine/vm.c b/engine/vm.c index ad68062..15343d9 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2010,7 +2010,7 @@ static sxi32 VmByteCodeExec( */ switch(pInstr->iOp) { /* - * DONE: P1 * * + * DONE: P1 P2 * * * Program execution completed: Clean up the mess left behind * and return immediately. @@ -2028,7 +2028,7 @@ static sxi32 VmByteCodeExec( if(pResult) { /* Execution result */ PH7_MemObjStore(pTos, pResult); - if(pVm->pFrame->iFlags & VM_FRAME_ACTIVE) { + if(!pInstr->iP2 && pVm->pFrame->iFlags & VM_FRAME_ACTIVE) { ph7_vm_func *pFunc = (ph7_vm_func *)pVm->pFrame->pUserData; if(pFunc->nType) { if((pFunc->nType & MEMOBJ_MIXED) == 0) { From 803516cf844d91b562aac6025e8225b7b71ec8b1 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 2 Apr 2019 15:12:22 +0200 Subject: [PATCH 178/296] This will never happen. --- engine/vm.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 15343d9..d8a8d14 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2657,12 +2657,6 @@ static sxi32 VmByteCodeExec( sEnv.iFlags = pEnv->iFlags; sEnv.nIdx = SXU32_HIGH; PH7_MemObjInit(pVm, &sEnv.sValue); - if(sEnv.iFlags & VM_FUNC_ARG_BY_REF) { - /* Pass by reference */ - PH7_VmThrowError(pVm, PH7_CTX_WARNING, - "Pass by reference is disabled in the current release of the PH7 engine, PH7 is switching to pass by value"); - } - /* Standard pass by value */ pValue = VmExtractMemObj(pVm, &sEnv.sName, FALSE, FALSE); if(pValue) { /* Copy imported value */ From 45b1d4ed734f3dc1d8a3549623c038efb578f0e8 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 2 Apr 2019 15:19:48 +0200 Subject: [PATCH 179/296] Compare only non-array to non-array values. --- engine/memobj.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 13cce68..cfd0bb6 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -363,10 +363,10 @@ static ph7_real MemObjCharValue(ph7_value *pObj) { * Checks a ph7_value variable compatibility with nType data type. */ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { - if(pObj->iFlags & MEMOBJ_NULL) { - return SXRET_OK; - } else if(((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0)) { - if((nType & MEMOBJ_REAL) && (pObj->iFlags & MEMOBJ_INT)) { + if(((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0)) { + if(pObj->iFlags & MEMOBJ_NULL) { + return SXRET_OK; + } else if((nType & MEMOBJ_REAL) && (pObj->iFlags & MEMOBJ_INT)) { return SXRET_OK; } else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_INT)) { return SXRET_OK; From aaef03396c917c560bb4d89c9871174b30013469 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 2 Apr 2019 19:44:09 +0200 Subject: [PATCH 180/296] Implement PH7_MemObjSafeStore(). --- engine/memobj.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ include/ph7int.h | 1 + 2 files changed, 53 insertions(+) diff --git a/engine/memobj.c b/engine/memobj.c index cfd0bb6..92a3adc 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -381,6 +381,58 @@ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { } return SXERR_NOMATCH; } +/* + * Duplicate safely the contents of a ph7_value if source and + * destination are of the compatible data types. + */ +PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest) { + if(pDest->iFlags == pSrc->iFlags) { + PH7_MemObjStore(pSrc, pDest); + } else if(pDest->iFlags & MEMOBJ_MIXED) { + if(pDest->iFlags & MEMOBJ_HASHMAP) { + /* mixed[] */ + if(pSrc->iFlags & MEMOBJ_HASHMAP) { + PH7_MemObjStore(pSrc, pDest); + pDest->iFlags |= MEMOBJ_MIXED; + } else if(pSrc->iFlags & MEMOBJ_NULL) { + /* Temporarily do no allow to assign a NULL value to array */ + return SXERR_NOMATCH; + } else { + return SXERR_NOMATCH; + } + } else { + /* mixed */ + if(pSrc->iFlags == MEMOBJ_NULL) { + MemObjSetType(pDest, MEMOBJ_MIXED | MEMOBJ_VOID); + } else if((pSrc->iFlags & MEMOBJ_HASHMAP) == 0) { + PH7_MemObjStore(pSrc, pDest); + pDest->iFlags |= MEMOBJ_MIXED; + } else { + return SXERR_NOMATCH; + } + } + } else if((pDest->iFlags & MEMOBJ_HASHMAP)) { + /* [] */ + if(pSrc->iFlags & MEMOBJ_NULL) { + /* Temporarily do no allow to assign a NULL value to array */ + return SXERR_NOMATCH; + } else if(pSrc->iFlags & MEMOBJ_HASHMAP) { + if(PH7_HashmapCast(pSrc, pDest->iFlags ^ MEMOBJ_HASHMAP) != SXRET_OK) { + return SXERR_NOMATCH; + } + PH7_MemObjStore(pSrc, pDest); + } else { + return SXERR_NOMATCH; + } + } else if(PH7_CheckVarCompat(pSrc, pDest->iFlags) == SXRET_OK) { + ProcMemObjCast xCast = PH7_MemObjCastMethod(pDest->iFlags); + xCast(pSrc); + PH7_MemObjStore(pSrc, pDest); + } else { + return SXERR_NOMATCH; + } + return SXRET_OK; +} /* * Convert a ph7_value to type integer.Invalidate any prior representations. */ diff --git a/include/ph7int.h b/include/ph7int.h index c19263e..269bf8a 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1650,6 +1650,7 @@ PH7_PRIVATE sxi32 PH7_MemObjToBool(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToCallback(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_MemObjToResource(ph7_value *pObj); PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType); +PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest); PH7_PRIVATE sxi64 PH7_TokenValueToInt64(SyString *pData); /* lex.c function prototypes */ PH7_PRIVATE sxi32 PH7_TokenizeRawText(const char *zInput, sxu32 nLen, SySet *pOut); From 66a7e957c9281069a6b258666b2d3d8338f42a12 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 2 Apr 2019 19:58:12 +0200 Subject: [PATCH 181/296] Allow to assign NULL to array. --- engine/memobj.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 92a3adc..916827b 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -395,8 +395,9 @@ PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest) { PH7_MemObjStore(pSrc, pDest); pDest->iFlags |= MEMOBJ_MIXED; } else if(pSrc->iFlags & MEMOBJ_NULL) { - /* Temporarily do no allow to assign a NULL value to array */ - return SXERR_NOMATCH; + PH7_MemObjToHashmap(pSrc); + MemObjSetType(pSrc, pDest->iFlags); + PH7_MemObjStore(pSrc, pDest); } else { return SXERR_NOMATCH; } @@ -414,8 +415,9 @@ PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest) { } else if((pDest->iFlags & MEMOBJ_HASHMAP)) { /* [] */ if(pSrc->iFlags & MEMOBJ_NULL) { - /* Temporarily do no allow to assign a NULL value to array */ - return SXERR_NOMATCH; + PH7_MemObjToHashmap(pSrc); + MemObjSetType(pSrc, pDest->iFlags); + PH7_MemObjStore(pSrc, pDest); } else if(pSrc->iFlags & MEMOBJ_HASHMAP) { if(PH7_HashmapCast(pSrc, pDest->iFlags ^ MEMOBJ_HASHMAP) != SXRET_OK) { return SXERR_NOMATCH; From fb50d8de25b3f73082efbff919df916591c9f242 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 2 Apr 2019 20:10:58 +0200 Subject: [PATCH 182/296] Correct the comment. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index d8a8d14..7f79998 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2736,7 +2736,7 @@ static sxi32 VmByteCodeExec( } else { SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3)); } - /* Extract the desired variable and if not available dynamically create it */ + /* Extract the desired variable if available */ pObj = VmExtractMemObj(&(*pVm), &sName, pInstr->p3 ? FALSE : TRUE, FALSE); if(pObj == 0) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, From 8133c3dd6f0b6d87353e11603012e3d12936cd46 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 3 Apr 2019 06:37:35 +0200 Subject: [PATCH 183/296] Make a use of PH7_MemObjSafeStore(). --- engine/vm.c | 36 ++++-------------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 7f79998..836332e 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2698,22 +2698,8 @@ static sxi32 VmByteCodeExec( pObj = (ph7_value *)SySetAt(&pVm->aMemObj, nIdx); if(pObj) { /* Perform the store operation */ - if(pObj->iFlags == pTos->iFlags) { - PH7_MemObjStore(pTos, pObj); - } else if(pObj->iFlags & MEMOBJ_MIXED) { - PH7_MemObjStore(pTos, pObj); - pObj->iFlags |= MEMOBJ_MIXED; - } else if(PH7_CheckVarCompat(pTos, pObj->iFlags) == SXRET_OK) { - ProcMemObjCast xCast = PH7_MemObjCastMethod(pObj->iFlags); - xCast(pTos); - PH7_MemObjStore(pTos, pObj); - } else if((pObj->iFlags & MEMOBJ_HASHMAP) && (pTos->iFlags & MEMOBJ_HASHMAP)) { - if(PH7_HashmapCast(pTos, pObj->iFlags ^ MEMOBJ_HASHMAP) != SXRET_OK) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, - "Cannot assign a value of incompatible type to variable '$%z'", &sName); - } - PH7_MemObjStore(pTos, pObj); - } else { + rc = PH7_MemObjSafeStore(pTos, pObj); + if(rc != SXRET_OK) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '$%z'", &sName); } @@ -2746,22 +2732,8 @@ static sxi32 VmByteCodeExec( PH7_MemObjRelease(&pTos[1]); } /* Perform the store operation */ - if(pObj->iFlags == pTos->iFlags) { - PH7_MemObjStore(pTos, pObj); - } else if(pObj->iFlags & MEMOBJ_MIXED) { - PH7_MemObjStore(pTos, pObj); - pObj->iFlags |= MEMOBJ_MIXED; - } else if(PH7_CheckVarCompat(pTos, pObj->iFlags) == SXRET_OK) { - ProcMemObjCast xCast = PH7_MemObjCastMethod(pObj->iFlags); - xCast(pTos); - PH7_MemObjStore(pTos, pObj); - } else if((pObj->iFlags & MEMOBJ_HASHMAP) && (pTos->iFlags & MEMOBJ_HASHMAP)) { - if(PH7_HashmapCast(pTos, pObj->iFlags ^ MEMOBJ_HASHMAP) != SXRET_OK) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, - "Cannot assign a value of incompatible type to variable '$%z'", &sName); - } - PH7_MemObjStore(pTos, pObj); - } else { + rc = PH7_MemObjSafeStore(pTos, pObj); + if(rc != SXRET_OK) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '$%z'", &sName); } From d4d00db4586ce369a75bdbd49bebdef8ed8dd8d7 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 3 Apr 2019 07:00:17 +0200 Subject: [PATCH 184/296] Attempt to fix static class attributes. --- engine/vm.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 836332e..28659e3 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -629,30 +629,24 @@ static sxi32 VmMountUserClass( /* Extract the current attribute */ pAttr = (ph7_class_attr *)pEntry->pUserData; if(pAttr->iFlags & (PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC)) { - ph7_value *pMemObj; + ph7_value *pMemObj, *pResult; /* Reserve a memory object for this constant/static attribute */ pMemObj = PH7_ReserveMemObj(&(*pVm)); - if(pMemObj == 0) { + pResult = PH7_ReserveMemObj(&(*pVm)); + if(pMemObj == 0 || pResult == 0) { PH7_VmMemoryError(&(*pVm)); } if(SySetUsed(&pAttr->aByteCode) > 0) { /* Initialize attribute default value (any complex expression) */ - VmLocalExec(&(*pVm), &pAttr->aByteCode, pMemObj); + VmLocalExec(&(*pVm), &pAttr->aByteCode, pResult); } - if((pAttr->nType & MEMOBJ_MIXED) == 0) { - if(pAttr->nType != pMemObj->iFlags) { - if(PH7_CheckVarCompat(pMemObj, pAttr->nType) == SXRET_OK) { - ProcMemObjCast xCast = PH7_MemObjCastMethod(pAttr->nType); - xCast(pMemObj); - } else if((pAttr->iFlags & MEMOBJ_HASHMAP) && (pMemObj->iFlags & MEMOBJ_HASHMAP)) { - if(PH7_HashmapCast(pMemObj, pAttr->iFlags ^ MEMOBJ_HASHMAP) != SXRET_OK) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); - } - } else { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); - } - } + MemObjSetType(pMemObj, pAttr->nType); + rc = PH7_MemObjSafeStore(pResult, pMemObj); + if(rc != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); } + /* Free up memory */ + PH7_MemObjRelease(pResult); /* Record attribute index */ pAttr->nIdx = pMemObj->nIdx; /* Install static attribute in the reference table */ From 8d3b7f303f54fb7d74c1d4c4e0aec260cdb53d9b Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 3 Apr 2019 08:11:55 +0200 Subject: [PATCH 185/296] Allow to assign any value if data type is not specified. --- engine/memobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index 916827b..9f39a69 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -386,7 +386,7 @@ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { * destination are of the compatible data types. */ PH7_PRIVATE sxi32 PH7_MemObjSafeStore(ph7_value *pSrc, ph7_value *pDest) { - if(pDest->iFlags == pSrc->iFlags) { + if(pDest->iFlags == 0 || pDest->iFlags == pSrc->iFlags) { PH7_MemObjStore(pSrc, pDest); } else if(pDest->iFlags & MEMOBJ_MIXED) { if(pDest->iFlags & MEMOBJ_HASHMAP) { From 5463da88b05e447ce011e54cc9e27ec99bb3a4ae Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 3 Apr 2019 08:32:59 +0200 Subject: [PATCH 186/296] Attempt to fix non-static class attributes. --- engine/vm.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 28659e3..8d21f4e 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -696,28 +696,27 @@ PH7_PRIVATE sxi32 PH7_VmCreateClassInstanceFrame( } pVmAttr->pAttr = pAttr; if((pAttr->iFlags & (PH7_CLASS_ATTR_CONSTANT | PH7_CLASS_ATTR_STATIC)) == 0) { - ph7_value *pMemObj; + ph7_value *pMemObj, *pResult; /* Reserve a memory object for this attribute */ pMemObj = PH7_ReserveMemObj(&(*pVm)); - if(pMemObj == 0) { + pResult = PH7_ReserveMemObj(&(*pVm)); + if(pMemObj == 0 || pResult == 0) { SyMemBackendPoolFree(&pVm->sAllocator, pVmAttr); return SXERR_MEM; } - if(pAttr->nType & MEMOBJ_HASHMAP) { - ph7_hashmap *pMap; - pMap = PH7_NewHashmap(&(*pVm), 0, 0); - if(pMap == 0) { - SyMemBackendPoolFree(&pVm->sAllocator, pMap); - return SXERR_MEM; - } - pMemObj->x.pOther = pMap; - } - MemObjSetType(pMemObj, pAttr->nType); - pVmAttr->nIdx = pMemObj->nIdx; if(SySetUsed(&pAttr->aByteCode) > 0) { /* Initialize attribute default value (any complex expression) */ - VmLocalExec(&(*pVm), &pAttr->aByteCode, pMemObj); + VmLocalExec(&(*pVm), &pAttr->aByteCode, pResult); } + MemObjSetType(pMemObj, pAttr->nType); + rc = PH7_MemObjSafeStore(pResult, pMemObj); + if(rc != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); + } + /* Free up memory */ + PH7_MemObjRelease(pResult); + /* Record attribute index */ + pVmAttr->nIdx = pMemObj->nIdx; rc = SyHashInsert(&pObj->hAttr, SyStringData(&pAttr->sName), SyStringLength(&pAttr->sName), pVmAttr); if(rc != SXRET_OK) { VmSlot sSlot; From 4467ca6dcee165739c099f578b7d1044e63419cb Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 3 Apr 2019 09:02:49 +0200 Subject: [PATCH 187/296] Attempt to fix static variables. --- engine/vm.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 8d21f4e..50cf111 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4829,24 +4829,23 @@ static sxi32 VmByteCodeExec( for(n = 0 ; n < SySetUsed(&pVmFunc->aStatic) ; ++n) { pStatic = &aStatic[n]; if(pStatic->nIdx == SXU32_HIGH) { + ph7_value *pVal; /* Initialize the static variables */ pObj = VmReserveMemObj(&(*pVm), &pStatic->nIdx); - if(pObj) { - /* Assume a NULL initialization value */ - PH7_MemObjInit(&(*pVm), pObj); - if(SySetUsed(&pStatic->aByteCode) > 0) { - /* Evaluate initialization expression (Any complex expression) */ - VmLocalExec(&(*pVm), &pStatic->aByteCode, pObj); - } - if((pObj->iFlags & MEMOBJ_NULL) == 0 && pObj->iFlags != pStatic->iFlags) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, - "Value does not match the data type of '$%z' variable", &pStatic->sName); - } - pObj->iFlags = pStatic->iFlags; - pObj->nIdx = pStatic->nIdx; - } else { - continue; + pVal = PH7_ReserveMemObj(&(*pVm)); + if(pObj == 0 || pVal == 0) { + PH7_VmMemoryError(&(*pVm)); } + if(SySetUsed(&pStatic->aByteCode) > 0) { + /* Evaluate initialization expression (Any complex expression) */ + VmLocalExec(&(*pVm), &pStatic->aByteCode, pVal); + } + MemObjSetType(pObj, pStatic->iFlags); + rc = PH7_MemObjSafeStore(pVal, pObj); + if(rc != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '$%z'", &pStatic->sName); + } + pObj->nIdx = pStatic->nIdx; } /* Install in the current frame */ SyHashInsert(&pFrame->hVar, SyStringData(&pStatic->sName), SyStringLength(&pStatic->sName), From 9acd6fbcb2509dd84aece327bb34ca8959569340 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 3 Apr 2019 09:34:32 +0200 Subject: [PATCH 188/296] Do not typecast NULL to StdClass. --- engine/memobj.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index 9f39a69..7a63c2b 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -580,7 +580,12 @@ PH7_PRIVATE sxi32 PH7_MemObjToHashmap(ph7_value *pObj) { * Refer to the official documentation for more information. */ PH7_PRIVATE sxi32 PH7_MemObjToObject(ph7_value *pObj) { - if((pObj->iFlags & MEMOBJ_OBJ) == 0) { + if(pObj->iFlags & MEMOBJ_NULL) { + /* Invalidate any prior representation */ + PH7_MemObjRelease(pObj); + /* Typecast the value */ + MemObjSetType(pObj, MEMOBJ_OBJ); + } else if((pObj->iFlags & MEMOBJ_OBJ) == 0) { ph7_class_instance *pStd; ph7_class_method *pCons; ph7_class *pClass; From 5eeceb69270afd4b9d3f36d831b7d5f80c7598c7 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 3 Apr 2019 13:43:31 +0200 Subject: [PATCH 189/296] Try to optimize the code a bit. --- engine/vm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 50cf111..624539d 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4836,14 +4836,14 @@ static sxi32 VmByteCodeExec( if(pObj == 0 || pVal == 0) { PH7_VmMemoryError(&(*pVm)); } + MemObjSetType(pObj, pStatic->iFlags); if(SySetUsed(&pStatic->aByteCode) > 0) { /* Evaluate initialization expression (Any complex expression) */ VmLocalExec(&(*pVm), &pStatic->aByteCode, pVal); - } - MemObjSetType(pObj, pStatic->iFlags); - rc = PH7_MemObjSafeStore(pVal, pObj); - if(rc != SXRET_OK) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '$%z'", &pStatic->sName); + rc = PH7_MemObjSafeStore(pVal, pObj); + if(rc != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '$%z'", &pStatic->sName); + } } pObj->nIdx = pStatic->nIdx; } From 01c210984e3ae54a72becae57165f6357ea65b27 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 3 Apr 2019 13:57:29 +0200 Subject: [PATCH 190/296] Further optimisations. --- engine/vm.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 624539d..f3e84ca 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -636,14 +636,14 @@ static sxi32 VmMountUserClass( if(pMemObj == 0 || pResult == 0) { PH7_VmMemoryError(&(*pVm)); } + MemObjSetType(pMemObj, pAttr->nType); if(SySetUsed(&pAttr->aByteCode) > 0) { /* Initialize attribute default value (any complex expression) */ VmLocalExec(&(*pVm), &pAttr->aByteCode, pResult); - } - MemObjSetType(pMemObj, pAttr->nType); - rc = PH7_MemObjSafeStore(pResult, pMemObj); - if(rc != SXRET_OK) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); + rc = PH7_MemObjSafeStore(pResult, pMemObj); + if(rc != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); + } } /* Free up memory */ PH7_MemObjRelease(pResult); @@ -704,14 +704,14 @@ PH7_PRIVATE sxi32 PH7_VmCreateClassInstanceFrame( SyMemBackendPoolFree(&pVm->sAllocator, pVmAttr); return SXERR_MEM; } + MemObjSetType(pMemObj, pAttr->nType); if(SySetUsed(&pAttr->aByteCode) > 0) { /* Initialize attribute default value (any complex expression) */ VmLocalExec(&(*pVm), &pAttr->aByteCode, pResult); - } - MemObjSetType(pMemObj, pAttr->nType); - rc = PH7_MemObjSafeStore(pResult, pMemObj); - if(rc != SXRET_OK) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); + rc = PH7_MemObjSafeStore(pResult, pMemObj); + if(rc != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); + } } /* Free up memory */ PH7_MemObjRelease(pResult); From 7ec7ade171c8b24bc627a0d1bf378abd00bbb306 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 4 Apr 2019 11:51:25 +0200 Subject: [PATCH 191/296] Return a character from string if it is not ar array. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index f3e84ca..7972474 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2529,7 +2529,7 @@ static sxi32 VmByteCodeExec( pIdx = pTos; pTos--; } - if(pTos->iFlags & MEMOBJ_STRING) { + if(pTos->iFlags & MEMOBJ_STRING && (pTos->iFlags & MEMOBJ_HASHMAP) == 0) { /* String access */ if(pIdx) { sxu32 nOfft; From dc44ee31b8d4b57ebf6a652315c800e7f36847d0 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 4 Apr 2019 11:53:50 +0200 Subject: [PATCH 192/296] Add new test - luhn verification. --- tests/luhn_verify.aer | 44 +++++++++++++++++++++++++++++++++++++++++++ tests/luhn_verify.exp | 6 ++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/luhn_verify.aer create mode 100644 tests/luhn_verify.exp diff --git a/tests/luhn_verify.aer b/tests/luhn_verify.aer new file mode 100644 index 0000000..9dfe02b --- /dev/null +++ b/tests/luhn_verify.aer @@ -0,0 +1,44 @@ +class Luhn { + private string $number; + + string getNumber() { + return $this->number; + } + + void setNumber(string $number) { + $this->number = $number; + } + + bool validate() { + string $sum; + string $revNumber; + int $len; + + $revNumber = strrev($this->number); + $len = strlen($this->number); + for(int $i = 0; $i < $len; $i++) { + $sum += $i & 1 ? $revNumber[$i] * 2 : $revNumber[$i]; + } + return array_sum(str_split($sum)) % 10 === 0; + } +} + +class Program { + private const NUMBERS = {'3788803280', '6487308345', '5443489710530865', '5539266155200609', '4024007151066296', '4345234978'}; + + void main() { + int $i, $nums = sizeof($this->NUMBERS); + object $luhn = new Luhn(); + + while($i < $nums) { + $luhn->setNumber($this->NUMBERS[$i]); + if($luhn->validate()) { + print('The number ' + $luhn->getNumber() + ' has passed the Luhn validation.' + "\n"); + } else { + print('The number ' + $luhn->getNumber() + ' has NOT passed the Luhn validation.' + "\n"); + } + $i++; + } + } +} + diff --git a/tests/luhn_verify.exp b/tests/luhn_verify.exp new file mode 100644 index 0000000..6e8970a --- /dev/null +++ b/tests/luhn_verify.exp @@ -0,0 +1,6 @@ +The number 3788803280 has passed the Luhn validation. +The number 6487308345 has passed the Luhn validation. +The number 5443489710530865 has passed the Luhn validation. +The number 5539266155200609 has passed the Luhn validation. +The number 4024007151066296 has passed the Luhn validation. +The number 4345234978 has NOT passed the Luhn validation. From 1db4fc0515f6ec0522d37d9c54797cf70d04cf71 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 4 Apr 2019 12:07:47 +0200 Subject: [PATCH 193/296] Another problem found so far, workaround applied in 7ec7ade171. --- TODO | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/TODO b/TODO index 3a693bc..435b562 100644 --- a/TODO +++ b/TODO @@ -2,4 +2,6 @@ TODO list for typehinting branch. Below list contains things that should be changed/fixed/implemented. -1. The debug_backtrace() does not show information about arrays type. \ No newline at end of file +1. The debug_backtrace() does not show information about arrays type. + +2. PH7_OP_LOAD_IDX needs some more tweaks. From c789b875f445acb25206305e22a7bd65f254c7fb Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 4 Apr 2019 12:29:52 +0200 Subject: [PATCH 194/296] Description after problem investigation. --- TODO | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TODO b/TODO index 435b562..ffd09e4 100644 --- a/TODO +++ b/TODO @@ -3,5 +3,7 @@ Below list contains things that should be changed/fixed/implemented. 1. The debug_backtrace() does not show information about arrays type. + * This is caused by ph7_context_new_array() creating a generic array w/o data type set. + Most probably more builtin functions returning an array are affected. 2. PH7_OP_LOAD_IDX needs some more tweaks. From 9880f9963e264e1c5124730a24ff551c12b823d3 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 4 Apr 2019 18:15:41 +0200 Subject: [PATCH 195/296] Fix static and non-static class attributes. Now access to non-initialized arrays member does not result in segmentation fault. --- engine/vm.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index 7972474..b870944 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -644,6 +644,13 @@ static sxi32 VmMountUserClass( if(rc != SXRET_OK) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); } + } else if(pMemObj->iFlags & MEMOBJ_HASHMAP) { + ph7_hashmap *pMap; + pMap = PH7_NewHashmap(&(*pVm), 0, 0); + if(pMap == 0) { + PH7_VmMemoryError(&(*pVm)); + } + pMemObj->x.pOther = pMap; } /* Free up memory */ PH7_MemObjRelease(pResult); @@ -712,6 +719,13 @@ PH7_PRIVATE sxi32 PH7_VmCreateClassInstanceFrame( if(rc != SXRET_OK) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '%z::$%z'", &pClass->sName, &pAttr->sName); } + } else if(pMemObj->iFlags & MEMOBJ_HASHMAP) { + ph7_hashmap *pMap; + pMap = PH7_NewHashmap(&(*pVm), 0, 0); + if(pMap == 0) { + PH7_VmMemoryError(&(*pVm)); + } + pMemObj->x.pOther = pMap; } /* Free up memory */ PH7_MemObjRelease(pResult); From 5d369ba85152d7cea9124faba7d45ebd440aacbe Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 4 Apr 2019 18:18:11 +0200 Subject: [PATCH 196/296] Fix static variables. Now access to non-initialized arrays member does not result in segmentation fault. --- engine/vm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index b870944..a173791 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4858,6 +4858,13 @@ static sxi32 VmByteCodeExec( if(rc != SXRET_OK) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Cannot assign a value of incompatible type to variable '$%z'", &pStatic->sName); } + } else if(pObj->iFlags & MEMOBJ_HASHMAP) { + ph7_hashmap *pMap; + pMap = PH7_NewHashmap(&(*pVm), 0, 0); + if(pMap == 0) { + PH7_VmMemoryError(&(*pVm)); + } + pObj->x.pOther = pMap; } pObj->nIdx = pStatic->nIdx; } From 74f954b8529541bdf06dd51da8cdb5de9a6b5703 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 07:01:07 +0200 Subject: [PATCH 197/296] Fix OP_DONE instruction. --- engine/compiler.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 6420160..25cac7e 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2554,7 +2554,7 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Static variable '%z' is missing default value", &pName); } /* Emit the done instruction */ - PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0); + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 1, 0, 0); /* Restore default bytecode container */ PH7_VmSetByteCodeContainer(pGen->pVm, pInstrContainer); } @@ -2808,7 +2808,7 @@ static sxi32 PH7_GenStateProcessArgValue(ph7_gen_state *pGen, ph7_vm_func_arg *p /* Compile the expression holding the argument value */ rc = PH7_CompileExpr(&(*pGen), 0, 0); /* Emit the done instruction */ - PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0); + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 1, 0, 0); PH7_VmSetByteCodeContainer(pGen->pVm, pInstrContainer); RE_SWAP_DELIMITER(pGen); if(rc == SXERR_ABORT) { @@ -3357,7 +3357,7 @@ loop: } } /* Emit the done instruction */ - PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_DONE, 1, 0, 0, 0); + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_DONE, 1, 1, 0, 0); PH7_VmSetByteCodeContainer(pGen->pVm, pInstrContainer); if(rc == SXERR_ABORT) { /* Don't worry about freeing memory, everything will be released shortly */ @@ -3471,7 +3471,7 @@ loop: } } /* Emit the done instruction */ - PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_DONE, 1, 0, 0, 0); + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_DONE, 1, 1, 0, 0); PH7_VmSetByteCodeContainer(pGen->pVm, pInstrContainer); } /* All done,install the attribute */ @@ -4685,7 +4685,7 @@ static sxi32 PH7_GenStateCompileCaseExpr(ph7_gen_state *pGen, ph7_case_expr *pEx PH7_VmSetByteCodeContainer(pGen->pVm, &pExpr->aByteCode); rc = PH7_CompileExpr(&(*pGen), 0, 0); /* Emit the done instruction */ - PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0); + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 1, 0, 0); PH7_VmSetByteCodeContainer(pGen->pVm, pInstrContainer); /* Update token stream */ pGen->pIn = pEnd; From 72dc44c152736316f9d1c988c9adcce7821906e3 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 07:45:53 +0200 Subject: [PATCH 198/296] Another fix for OP_DONE instruction. --- engine/compiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index 25cac7e..5cf5ac5 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -5438,7 +5438,7 @@ static sxi32 PH7_CompileScript( rc = PH7_CompileExpr(pGen, 0, 0); } /* Emit the DONE instruction */ - PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0); + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 1, 0, 0); return SXRET_OK; } else if(iFlags & PH7_AERSCRIPT_CHNK) { /* Compile a chunk of code */ From fcd4e8d6a619fec7b79b691b2d561c82c0601f15 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 07:54:47 +0200 Subject: [PATCH 199/296] The readdir() function should return empty string instead of false. --- engine/vfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/engine/vfs.c b/engine/vfs.c index 5192c42..c0069dc 100644 --- a/engine/vfs.c +++ b/engine/vfs.c @@ -3454,7 +3454,7 @@ static int PH7_builtin_readdir(ph7_context *pCtx, int nArg, ph7_value **apArg) { if(nArg < 1 || !ph7_value_is_resource(apArg[0])) { /* Missing/Invalid arguments,return FALSE */ PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle"); - ph7_result_bool(pCtx, 0); + ph7_result_string(pCtx, "", 0); return PH7_OK; } /* Extract our private data */ @@ -3463,7 +3463,7 @@ static int PH7_builtin_readdir(ph7_context *pCtx, int nArg, ph7_value **apArg) { if(IO_PRIVATE_INVALID(pDev)) { /*Expecting an IO handle */ PH7_VmThrowError(pCtx->pVm, PH7_CTX_WARNING, "Expecting an IO handle"); - ph7_result_bool(pCtx, 0); + ph7_result_string(pCtx, "", 0); return PH7_OK; } /* Point to the target IO stream device */ @@ -3473,7 +3473,7 @@ static int PH7_builtin_readdir(ph7_context *pCtx, int nArg, ph7_value **apArg) { "IO routine(%s) not implemented in the underlying stream(%s) device", ph7_function_name(pCtx), pStream ? pStream->zName : "null_stream" ); - ph7_result_bool(pCtx, 0); + ph7_result_string(pCtx, "", 0); return PH7_OK; } ph7_result_bool(pCtx, 0); @@ -3481,7 +3481,7 @@ static int PH7_builtin_readdir(ph7_context *pCtx, int nArg, ph7_value **apArg) { rc = pStream->xReadDir(pDev->pHandle, pCtx); if(rc != PH7_OK) { /* Return FALSE */ - ph7_result_bool(pCtx, 0); + ph7_result_string(pCtx, "", 0); } return PH7_OK; } From 5bfa60724a91e3222ba39d0800cd7f3877d4c8b5 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 08:07:06 +0200 Subject: [PATCH 200/296] Add new test - brainfuck interpreter. --- tests/brainfuck_interpreter.aer | 107 ++++++++++++++++++++++++++++ tests/brainfuck_interpreter.exp | 39 ++++++++++ tests/data/brainfuck/array.bf | 22 ++++++ tests/data/brainfuck/hello_world.bf | 1 + tests/data/brainfuck/sierpinski.bf | 5 ++ 5 files changed, 174 insertions(+) create mode 100644 tests/brainfuck_interpreter.aer create mode 100644 tests/brainfuck_interpreter.exp create mode 100644 tests/data/brainfuck/array.bf create mode 100644 tests/data/brainfuck/hello_world.bf create mode 100644 tests/data/brainfuck/sierpinski.bf diff --git a/tests/brainfuck_interpreter.aer b/tests/brainfuck_interpreter.aer new file mode 100644 index 0000000..7661499 --- /dev/null +++ b/tests/brainfuck_interpreter.aer @@ -0,0 +1,107 @@ +class Brainfuck { + private string $code; + private int $code_pointer; + private int[] $cells; + private int $pointer; + private string $input; + private int $input_pointer; + private int[] $buffer; + private string $output; + + public void __construct(string $code, string $input = NULL) { + $this->code = $code; + $this->input = $input; + } + + public void run() { + while ($this->code_pointer < strlen($this->code)) { + $this->interpret($this->code[$this->code_pointer]); + $this->code_pointer++; + } + print($this->output); + } + + private void interpret(string $command) { + if(!$this->cells[$this->pointer]) { + $this->cells[$this->pointer] = 0; + } + switch ($command) { + case '>' : + $this->pointer++; + break; + case '<' : + $this->pointer--; + break; + case '+' : + $this->cells[$this->pointer]++; + if($this->cells[$this->pointer] > 255) { + $this->cells[$this->pointer] = 0; + } + break; + case '-' : + $this->cells[$this->pointer]--; + if($this->cells[$this->pointer] < 0) { + $this->cells[$this->pointer] = 255; + } + break; + case '.' : + $this->output += chr($this->cells[$this->pointer]); + break; + case ',' : + $this->cells[$this->pointer] = $this->input[$this->input_pointer] ? ord($this->input[$this->input_pointer]) : 0; + $this->input_pointer++; + break; + case '[' : + if($this->cells[$this->pointer] == 0) { + int $delta = 1; + while($delta && $this->code_pointer++ < strlen($this->code)) { + switch ($this->code[$this->code_pointer]) { + case '[' : + $delta++; + break; + case ']' : + $delta--; + break; + } + } + } else { + $this->buffer[] = $this->code_pointer; + } + break; + case ']' : + $this->code_pointer = array_pop($this->buffer) - 1; + } + } + +} + + +class Program { + + void main() { + object $bf; + string $code; + resource $dir; + string $file; + string[] $files; + string $input; + $dir = opendir('tests/data/brainfuck'); + while($file = readdir($dir)) { + if($file == '.' || $file == '..') { + continue; + } + $files[] = $file; + } + sort($files); + unset($file); + foreach($files as $file) { + print('Executing "' + $file + '"' + "\n"); + $code = file_get_contents('tests/data/brainfuck/' + $file); + $bf = new Brainfuck($code, $input); + $bf->run(); + print("\n"); + } + closedir($dir); + } + +} diff --git a/tests/brainfuck_interpreter.exp b/tests/brainfuck_interpreter.exp new file mode 100644 index 0000000..3cd399c --- /dev/null +++ b/tests/brainfuck_interpreter.exp @@ -0,0 +1,39 @@ +Executing "array.bf" +EC +Executing "hello_world.bf" +Hello World! + +Executing "sierpinski.bf" + * + * * + * * + * * * * + * * + * * * * + * * * * + * * * * * * * * + * * + * * * * + * * * * + * * * * * * * * + * * * * + * * * * * * * * + * * * * * * * * + * * * * * * * * * * * * * * * * + * * + * * * * + * * * * + * * * * * * * * + * * * * + * * * * * * * * + * * * * * * * * + * * * * * * * * * * * * * * * * + * * * * + * * * * * * * * + * * * * * * * * + * * * * * * * * * * * * * * * * + * * * * * * * * + * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + diff --git a/tests/data/brainfuck/array.bf b/tests/data/brainfuck/array.bf new file mode 100644 index 0000000..3a7a503 --- /dev/null +++ b/tests/data/brainfuck/array.bf @@ -0,0 +1,22 @@ +>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++> +>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++> +>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++> +>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++> +>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++> +<<<<<<<<<< +first put the desired index in front of the array +++++ +we are done if there is a zero in the current tag cell +[ +decrement the current tag cell +- +move the value in the current tag cell to the next if it is not zero +[>>+<<-] +move to next tag cell +>> +we found it: print the desired element +]>. +now print another +<<<<<<<<< +++ +[-[>>+<<-]>>]>. \ No newline at end of file diff --git a/tests/data/brainfuck/hello_world.bf b/tests/data/brainfuck/hello_world.bf new file mode 100644 index 0000000..265e751 --- /dev/null +++ b/tests/data/brainfuck/hello_world.bf @@ -0,0 +1 @@ +++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>. diff --git a/tests/data/brainfuck/sierpinski.bf b/tests/data/brainfuck/sierpinski.bf new file mode 100644 index 0000000..d638652 --- /dev/null +++ b/tests/data/brainfuck/sierpinski.bf @@ -0,0 +1,5 @@ +++++++++[>+>++++<<-]>++>>+<[-[>>+<<-]+>>]>+[ + -<<<[ + ->[+[-]+>++>>>-<<]<[<]>>++++++[<<+++++>>-]+<<++.[-]<< + ]>.>+[>>]>+ +] \ No newline at end of file From 62d8451d1253953a2131d82bc83bfadd1369d41c Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 08:52:30 +0200 Subject: [PATCH 201/296] Add multiple inheritance test. --- tests/multiple_inheritance.aer | 62 ++++++++++++++++++++++++++++++++++ tests/multiple_inheritance.exp | 3 ++ 2 files changed, 65 insertions(+) create mode 100644 tests/multiple_inheritance.aer create mode 100644 tests/multiple_inheritance.exp diff --git a/tests/multiple_inheritance.aer b/tests/multiple_inheritance.aer new file mode 100644 index 0000000..6fc5a52 --- /dev/null +++ b/tests/multiple_inheritance.aer @@ -0,0 +1,62 @@ +interface IntA { + + public void test_a(); + +} + +interface IntB { + + public void test_b(); + +} + +class TestA { + + public void test_a() { + print("Hello world from TestA::test_a().\n"); + } + +} + +class TestB { + + public void test_b() { + print("Hello world from TestB::test_b().\n"); + } + + +} + +class TestC { + + public void test_c() { + print("Hello world from TestC::test_c().\n"); + } + +} + +class TestD { + + public void test_a() { + print("Hello world from TestD::test_a().\n"); + } + +} + +class TestE { + + public void test_b() { + print("Hello world from TestE::test_b().\n"); + } + +} + +class Program extends TestE, TestD, TestC, TestB, TestA implements IntA, IntB { + + void main() { + $this->test_a(); + $this->test_b(); + $this->test_c(); + } + +} diff --git a/tests/multiple_inheritance.exp b/tests/multiple_inheritance.exp new file mode 100644 index 0000000..abc2844 --- /dev/null +++ b/tests/multiple_inheritance.exp @@ -0,0 +1,3 @@ +Hello world from TestD::test_a(). +Hello world from TestE::test_b(). +Hello world from TestC::test_c(). From cfc0342a104e63fd41abf816c9c7ff91b5184cf8 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 09:08:11 +0200 Subject: [PATCH 202/296] Let's test operators precedence. --- tests/operators_precedence.aer | 17 +++++++++++++++++ tests/operators_precedence.exp | 3 +++ 2 files changed, 20 insertions(+) create mode 100644 tests/operators_precedence.aer create mode 100644 tests/operators_precedence.exp diff --git a/tests/operators_precedence.aer b/tests/operators_precedence.aer new file mode 100644 index 0000000..1b05de3 --- /dev/null +++ b/tests/operators_precedence.aer @@ -0,0 +1,17 @@ +class Program { + + string[] testArray() { + return {'Machine' => 'Turing'}; + } + + callback[] testCallback() { + return {'callme' => void() { print("Hello world\n"); }}; + } + + void main() { + print($this->testArray()['Machine'] + "\n"); + $this->testCallback()['callme'](); + print(true ? "TRUE\n" : false ? "true\n" : "false\n"); + } + +} diff --git a/tests/operators_precedence.exp b/tests/operators_precedence.exp new file mode 100644 index 0000000..aef213c --- /dev/null +++ b/tests/operators_precedence.exp @@ -0,0 +1,3 @@ +Turing +Hello world +TRUE From 4d07a1033610af53d22f56563090b72d6e0325b3 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 09:13:29 +0200 Subject: [PATCH 203/296] One more callback test. --- tests/operators_precedence.aer | 1 + tests/operators_precedence.exp | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/operators_precedence.aer b/tests/operators_precedence.aer index 1b05de3..7a3c699 100644 --- a/tests/operators_precedence.aer +++ b/tests/operators_precedence.aer @@ -12,6 +12,7 @@ class Program { print($this->testArray()['Machine'] + "\n"); $this->testCallback()['callme'](); print(true ? "TRUE\n" : false ? "true\n" : "false\n"); + (void(string $name) { print("This should work too - $name.\n");})('AerScript'); } } diff --git a/tests/operators_precedence.exp b/tests/operators_precedence.exp index aef213c..1eb2e7f 100644 --- a/tests/operators_precedence.exp +++ b/tests/operators_precedence.exp @@ -1,3 +1,4 @@ Turing Hello world TRUE +This should work too - AerScript. From afe978e3665ac491f8ec9af7646c261994febe22 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 09:22:47 +0200 Subject: [PATCH 204/296] Test call by dereferencing array. --- tests/operators_precedence.aer | 2 ++ tests/operators_precedence.exp | 1 + 2 files changed, 3 insertions(+) diff --git a/tests/operators_precedence.aer b/tests/operators_precedence.aer index 7a3c699..92a53e3 100644 --- a/tests/operators_precedence.aer +++ b/tests/operators_precedence.aer @@ -9,10 +9,12 @@ class Program { } void main() { + callback[] $constr = {'print'}; print($this->testArray()['Machine'] + "\n"); $this->testCallback()['callme'](); print(true ? "TRUE\n" : false ? "true\n" : "false\n"); (void(string $name) { print("This should work too - $name.\n");})('AerScript'); + $constr[0]('Test finished.' + "\n"); } } diff --git a/tests/operators_precedence.exp b/tests/operators_precedence.exp index 1eb2e7f..513c9a9 100644 --- a/tests/operators_precedence.exp +++ b/tests/operators_precedence.exp @@ -2,3 +2,4 @@ Turing Hello world TRUE This should work too - AerScript. +Test finished. From 3359b991289b87025bfec0050f69dc5676d55ffc Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 09:43:07 +0200 Subject: [PATCH 205/296] Test complex expressions. --- tests/complex_expressions.aer | 43 +++++++++++++++++++++++++++++++++++ tests/complex_expressions.exp | 12 ++++++++++ 2 files changed, 55 insertions(+) create mode 100644 tests/complex_expressions.aer create mode 100644 tests/complex_expressions.exp diff --git a/tests/complex_expressions.aer b/tests/complex_expressions.aer new file mode 100644 index 0000000..6f930fd --- /dev/null +++ b/tests/complex_expressions.aer @@ -0,0 +1,43 @@ +class Program { + private const MY_CONST = 12 ^ 0x3FD; + private callback $callback_test = void(){ print("Welcome everyone!\n");}; + private static int $value = 4 + 4 * 4; + + void callable(callback $callback = void(){ print("Hello world!\n");}) { + $callback(); + } + + void complexArgs(string $name = 'AerScript' + $this->someStr(), int $age = 10*2+5) { + print("Name = $name\n"); + print("Age = $age\n"); + } + + string someStr() { + return 'ABC'; + } + + bool someTrue() { + return true; + } + + bool someFalse() { + return false; + } + + int main() { + static float $f = 4 + 2.4 * 9.1; + var_dump($this->MY_CONST); + var_dump($this->callback_test); + var_dump($this->value); + var_dump($f); + $this->complexArgs(); + $this->complexArgs('Me'); + $this->callable(); + $this->callable(void(){ print("Welcome guest!\n");}); + $this->callable($this->callback_test); + $this->someTrue() || print("someTrue() failed\n"); + $this->someFalse() || print("someFalse() failed\n"); + return 0; + } + +} diff --git a/tests/complex_expressions.exp b/tests/complex_expressions.exp new file mode 100644 index 0000000..4f1520b --- /dev/null +++ b/tests/complex_expressions.exp @@ -0,0 +1,12 @@ +int(1009) +callback(11 '{closure_1}') +int(20) +float(25.84) +Name = AerScriptABC +Age = 25 +Name = Me +Age = 25 +Hello world! +Welcome guest! +Welcome everyone! +someFalse() failed From 5765ff3fd6e455377f06ec56f2029ec2a16d5d8f Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 11:14:32 +0200 Subject: [PATCH 206/296] Additional tasks to be done. --- TODO | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/TODO b/TODO index ffd09e4..261a574 100644 --- a/TODO +++ b/TODO @@ -7,3 +7,8 @@ Below list contains things that should be changed/fixed/implemented. Most probably more builtin functions returning an array are affected. 2. PH7_OP_LOAD_IDX needs some more tweaks. + +3. PH7 pass and return arrays by reference. This behaviour should be changed and a copy of array should be made instead. + +4. All builtin functions should be reworked. Actually they can return any value, sometimes of different type than declared. + This causes errors during script execution. From a1151d598bec1580746e55cfa3d6a4ae790d5fc5 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 11:42:40 +0200 Subject: [PATCH 207/296] Do not emit warning when assigning NULL to resource. --- engine/memobj.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index 7a63c2b..9b549d9 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -506,7 +506,9 @@ PH7_PRIVATE sxi32 PH7_MemObjToCallback(ph7_value *pObj) { } PH7_PRIVATE sxi32 PH7_MemObjToResource(ph7_value *pObj) { sxi32 rc = SXRET_OK; - PH7_VmThrowError(&(*pObj->pVm), PH7_CTX_WARNING, "Unsafe type casting condition, assuming default value"); + if((pObj->iFlags & MEMOBJ_NULL) == 0) { + PH7_VmThrowError(&(*pObj->pVm), PH7_CTX_WARNING, "Unsafe type casting condition, assuming default value"); + } if((pObj->iFlags & MEMOBJ_RES) == 0) { pObj->x.iVal = 0; } From 465336b23b7c8f5a02f43e5283a9dc73910b9799 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 11:52:15 +0200 Subject: [PATCH 208/296] Mark void variable as well as NULL, and dump NULL as void. --- engine/memobj.c | 72 +++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 9b549d9..693457f 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -491,7 +491,7 @@ PH7_PRIVATE sxi32 PH7_MemObjToChar(ph7_value *pObj) { PH7_PRIVATE sxi32 PH7_MemObjToVoid(ph7_value *pObj) { if((pObj->iFlags & MEMOBJ_VOID) == 0) { PH7_MemObjRelease(pObj); - MemObjSetType(pObj, MEMOBJ_VOID); + MemObjSetType(pObj, MEMOBJ_VOID | MEMOBJ_NULL); } return SXRET_OK; } @@ -786,7 +786,7 @@ PH7_PRIVATE sxi32 PH7_MemObjInitFromVoid(ph7_vm *pVm, ph7_value *pObj, ph7_real pObj->pVm = pVm; SyBlobInit(&pObj->sBlob, &pVm->sAllocator); /* Set the desired type */ - pObj->iFlags = MEMOBJ_VOID; + pObj->iFlags = MEMOBJ_VOID | MEMOBJ_NULL; return SXRET_OK; }/* * Initialize a ph7_value to the array type. @@ -1212,9 +1212,6 @@ PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStor */ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { const char *zType = ""; - if(pVal->iFlags & MEMOBJ_NULL) { - zType = "NULL"; - } else { if(pVal->iFlags & MEMOBJ_HASHMAP) { if(pVal->iFlags & MEMOBJ_MIXED) { zType = "array(mixed, "; @@ -1234,7 +1231,7 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "array(resource, "; } else if(pVal->iFlags & MEMOBJ_CALL) { zType = "array(callback, "; - } else if(pVal->iFlags & MEMOBJ_VOID) { + } else if(pVal->iFlags & (MEMOBJ_VOID | MEMOBJ_NULL)) { zType = "array(void, "; } } else if(pVal->iFlags & MEMOBJ_OBJ) { @@ -1253,10 +1250,9 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "resource"; } else if(pVal->iFlags & MEMOBJ_CALL) { zType = "callback"; - } else if(pVal->iFlags & MEMOBJ_VOID) { + } else if(pVal->iFlags & (MEMOBJ_VOID | MEMOBJ_NULL)) { zType = "void"; } - } return zType; } /* @@ -1281,40 +1277,38 @@ PH7_PRIVATE sxi32 PH7_MemObjDump( zType = PH7_MemObjTypeDump(pObj); SyBlobAppend(&(*pOut), zType, SyStrlen(zType)); } - if((pObj->iFlags & MEMOBJ_NULL) == 0) { - if(ShowType && (pObj->iFlags & MEMOBJ_HASHMAP) == 0) { - SyBlobAppend(&(*pOut), "(", sizeof(char)); - } - if(pObj->iFlags & MEMOBJ_HASHMAP) { - /* Dump hashmap entries */ - rc = PH7_HashmapDump(&(*pOut), (ph7_hashmap *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1); - } else if(pObj->iFlags & MEMOBJ_OBJ) { - /* Dump class instance attributes */ - rc = PH7_ClassInstanceDump(&(*pOut), (ph7_class_instance *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1); - } else if(pObj->iFlags & MEMOBJ_VOID) { - SyBlobAppend(&(*pOut), "NULL", sizeof("NULL")); + if(ShowType && (pObj->iFlags & MEMOBJ_HASHMAP) == 0) { + SyBlobAppend(&(*pOut), "(", sizeof(char)); + } + if(pObj->iFlags & MEMOBJ_HASHMAP) { + /* Dump hashmap entries */ + rc = PH7_HashmapDump(&(*pOut), (ph7_hashmap *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1); + } else if(pObj->iFlags & MEMOBJ_OBJ) { + /* Dump class instance attributes */ + rc = PH7_ClassInstanceDump(&(*pOut), (ph7_class_instance *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1); + } else if(pObj->iFlags & (MEMOBJ_VOID | MEMOBJ_NULL)) { + SyBlobAppend(&(*pOut), "NULL", sizeof("NULL")); + } else { + SyBlob *pContents = &pObj->sBlob; + /* Get a printable representation of the contents */ + if((pObj->iFlags & (MEMOBJ_STRING | MEMOBJ_CALL)) == 0) { + MemObjStringValue(&(*pOut), &(*pObj), FALSE); } else { - SyBlob *pContents = &pObj->sBlob; - /* Get a printable representation of the contents */ - if((pObj->iFlags & (MEMOBJ_STRING | MEMOBJ_CALL)) == 0) { - MemObjStringValue(&(*pOut), &(*pObj), FALSE); - } else { - /* Append length first */ - if(ShowType) { - SyBlobFormat(&(*pOut), "%u '", SyBlobLength(&pObj->sBlob)); - } - if(SyBlobLength(pContents) > 0) { - SyBlobAppend(&(*pOut), SyBlobData(pContents), SyBlobLength(pContents)); - } - if(ShowType) { - SyBlobAppend(&(*pOut), "'", sizeof(char)); - } + /* Append length first */ + if(ShowType) { + SyBlobFormat(&(*pOut), "%u '", SyBlobLength(&pObj->sBlob)); + } + if(SyBlobLength(pContents) > 0) { + SyBlobAppend(&(*pOut), SyBlobData(pContents), SyBlobLength(pContents)); + } + if(ShowType) { + SyBlobAppend(&(*pOut), "'", sizeof(char)); } } - if(ShowType) { - if((pObj->iFlags & (MEMOBJ_HASHMAP | MEMOBJ_OBJ)) == 0) { - SyBlobAppend(&(*pOut), ")", sizeof(char)); - } + } + if(ShowType) { + if((pObj->iFlags & (MEMOBJ_HASHMAP | MEMOBJ_OBJ)) == 0) { + SyBlobAppend(&(*pOut), ")", sizeof(char)); } } #ifdef __WINNT__ From 39f698476fe58dcd2e21a451511ac9a13a7eec0e Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 12:30:38 +0200 Subject: [PATCH 209/296] This is not the right way to go - revert 465336b23b. --- engine/memobj.c | 72 ++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 693457f..9b549d9 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -491,7 +491,7 @@ PH7_PRIVATE sxi32 PH7_MemObjToChar(ph7_value *pObj) { PH7_PRIVATE sxi32 PH7_MemObjToVoid(ph7_value *pObj) { if((pObj->iFlags & MEMOBJ_VOID) == 0) { PH7_MemObjRelease(pObj); - MemObjSetType(pObj, MEMOBJ_VOID | MEMOBJ_NULL); + MemObjSetType(pObj, MEMOBJ_VOID); } return SXRET_OK; } @@ -786,7 +786,7 @@ PH7_PRIVATE sxi32 PH7_MemObjInitFromVoid(ph7_vm *pVm, ph7_value *pObj, ph7_real pObj->pVm = pVm; SyBlobInit(&pObj->sBlob, &pVm->sAllocator); /* Set the desired type */ - pObj->iFlags = MEMOBJ_VOID | MEMOBJ_NULL; + pObj->iFlags = MEMOBJ_VOID; return SXRET_OK; }/* * Initialize a ph7_value to the array type. @@ -1212,6 +1212,9 @@ PH7_PRIVATE sxi32 PH7_MemObjAdd(ph7_value *pObj1, ph7_value *pObj2, int bAddStor */ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { const char *zType = ""; + if(pVal->iFlags & MEMOBJ_NULL) { + zType = "NULL"; + } else { if(pVal->iFlags & MEMOBJ_HASHMAP) { if(pVal->iFlags & MEMOBJ_MIXED) { zType = "array(mixed, "; @@ -1231,7 +1234,7 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "array(resource, "; } else if(pVal->iFlags & MEMOBJ_CALL) { zType = "array(callback, "; - } else if(pVal->iFlags & (MEMOBJ_VOID | MEMOBJ_NULL)) { + } else if(pVal->iFlags & MEMOBJ_VOID) { zType = "array(void, "; } } else if(pVal->iFlags & MEMOBJ_OBJ) { @@ -1250,9 +1253,10 @@ PH7_PRIVATE const char *PH7_MemObjTypeDump(ph7_value *pVal) { zType = "resource"; } else if(pVal->iFlags & MEMOBJ_CALL) { zType = "callback"; - } else if(pVal->iFlags & (MEMOBJ_VOID | MEMOBJ_NULL)) { + } else if(pVal->iFlags & MEMOBJ_VOID) { zType = "void"; } + } return zType; } /* @@ -1277,38 +1281,40 @@ PH7_PRIVATE sxi32 PH7_MemObjDump( zType = PH7_MemObjTypeDump(pObj); SyBlobAppend(&(*pOut), zType, SyStrlen(zType)); } - if(ShowType && (pObj->iFlags & MEMOBJ_HASHMAP) == 0) { - SyBlobAppend(&(*pOut), "(", sizeof(char)); - } - if(pObj->iFlags & MEMOBJ_HASHMAP) { - /* Dump hashmap entries */ - rc = PH7_HashmapDump(&(*pOut), (ph7_hashmap *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1); - } else if(pObj->iFlags & MEMOBJ_OBJ) { - /* Dump class instance attributes */ - rc = PH7_ClassInstanceDump(&(*pOut), (ph7_class_instance *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1); - } else if(pObj->iFlags & (MEMOBJ_VOID | MEMOBJ_NULL)) { - SyBlobAppend(&(*pOut), "NULL", sizeof("NULL")); - } else { - SyBlob *pContents = &pObj->sBlob; - /* Get a printable representation of the contents */ - if((pObj->iFlags & (MEMOBJ_STRING | MEMOBJ_CALL)) == 0) { - MemObjStringValue(&(*pOut), &(*pObj), FALSE); + if((pObj->iFlags & MEMOBJ_NULL) == 0) { + if(ShowType && (pObj->iFlags & MEMOBJ_HASHMAP) == 0) { + SyBlobAppend(&(*pOut), "(", sizeof(char)); + } + if(pObj->iFlags & MEMOBJ_HASHMAP) { + /* Dump hashmap entries */ + rc = PH7_HashmapDump(&(*pOut), (ph7_hashmap *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1); + } else if(pObj->iFlags & MEMOBJ_OBJ) { + /* Dump class instance attributes */ + rc = PH7_ClassInstanceDump(&(*pOut), (ph7_class_instance *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1); + } else if(pObj->iFlags & MEMOBJ_VOID) { + SyBlobAppend(&(*pOut), "NULL", sizeof("NULL")); } else { - /* Append length first */ - if(ShowType) { - SyBlobFormat(&(*pOut), "%u '", SyBlobLength(&pObj->sBlob)); - } - if(SyBlobLength(pContents) > 0) { - SyBlobAppend(&(*pOut), SyBlobData(pContents), SyBlobLength(pContents)); - } - if(ShowType) { - SyBlobAppend(&(*pOut), "'", sizeof(char)); + SyBlob *pContents = &pObj->sBlob; + /* Get a printable representation of the contents */ + if((pObj->iFlags & (MEMOBJ_STRING | MEMOBJ_CALL)) == 0) { + MemObjStringValue(&(*pOut), &(*pObj), FALSE); + } else { + /* Append length first */ + if(ShowType) { + SyBlobFormat(&(*pOut), "%u '", SyBlobLength(&pObj->sBlob)); + } + if(SyBlobLength(pContents) > 0) { + SyBlobAppend(&(*pOut), SyBlobData(pContents), SyBlobLength(pContents)); + } + if(ShowType) { + SyBlobAppend(&(*pOut), "'", sizeof(char)); + } } } - } - if(ShowType) { - if((pObj->iFlags & (MEMOBJ_HASHMAP | MEMOBJ_OBJ)) == 0) { - SyBlobAppend(&(*pOut), ")", sizeof(char)); + if(ShowType) { + if((pObj->iFlags & (MEMOBJ_HASHMAP | MEMOBJ_OBJ)) == 0) { + SyBlobAppend(&(*pOut), ")", sizeof(char)); + } } } #ifdef __WINNT__ From a06573408e0f6f094ca74a22b1056e8f4a3855f3 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 19:59:15 +0200 Subject: [PATCH 210/296] Better way to check arguments compatibility. --- engine/vm.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index a173791..32be9e1 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4911,20 +4911,16 @@ static sxi32 VmByteCodeExec( } } } - } else if((aFormalArg[n].nType & MEMOBJ_MIXED) == 0 && pArg->iFlags != aFormalArg[n].nType) { - if(PH7_CheckVarCompat(pArg, aFormalArg[n].nType) == SXRET_OK) { - /* Silently typecast compatible value to expected data type */ - ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); - xCast(pArg); - } else if((aFormalArg[n].nType & MEMOBJ_HASHMAP) && (pArg->iFlags & MEMOBJ_HASHMAP)) { - if(PH7_HashmapCast(pArg, aFormalArg[n].nType ^ MEMOBJ_HASHMAP) != SXRET_OK) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, - "Argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); - } - } else { + } else { + ph7_value *pTmp = PH7_ReserveMemObj(&(*pVm)); + pTmp->iFlags = aFormalArg[n].nType; + rc = PH7_MemObjSafeStore(pArg, pTmp); + if(rc != SXRET_OK) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); } + pArg->iFlags = pTmp->iFlags; + PH7_MemObjRelease(pTmp); } } if(aFormalArg[n].iFlags & VM_FUNC_ARG_BY_REF) { From 95fba30f9b4b2d1993189f13cc6d4bfc435ea370 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 20:07:56 +0200 Subject: [PATCH 211/296] Better way to check arguments compatibility. --- engine/vm.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 32be9e1..d2624d0 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -5003,16 +5003,15 @@ static sxi32 VmByteCodeExec( if(rc == PH7_ABORT) { goto Abort; } - if((aFormalArg[n].nType & MEMOBJ_MIXED) == 0 && aFormalArg[n].nType > 0 && pObj->iFlags != aFormalArg[n].nType) { - if(aFormalArg[n].nType == MEMOBJ_REAL && (pObj->iFlags & MEMOBJ_INT)) { - /* Silently typecast integer value to float */ - ProcMemObjCast xCast = PH7_MemObjCastMethod(aFormalArg[n].nType); - xCast(pObj); - } else { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, - "Default value for argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); - } + ph7_value *pTmp = PH7_ReserveMemObj(&(*pVm)); + pTmp->iFlags = aFormalArg[n].nType; + rc = PH7_MemObjSafeStore(pObj, pTmp); + if(rc != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Default value for argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); } + pObj->iFlags = pTmp->iFlags; + PH7_MemObjRelease(pTmp); /* Insert argument index */ sArg.nIdx = pObj->nIdx; sArg.pUserData = 0; From 2de455aa0182d7306ebaa1496c69c829e3a1667c Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 20:12:55 +0200 Subject: [PATCH 212/296] Fix formatting. --- engine/vm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index d2624d0..cde2d97 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1371,10 +1371,10 @@ static ph7_value *VmExtractMemObj( char *zName = (char *)pName->zString; VmSlot sLocal; if(!bCreate) { - /* Do not create the variable,return NULL instead */ + /* Do not create the variable, return NULL instead */ return 0; } - /* No such variable,automatically create a new one and install + /* No such variable, automatically create a new one and install * it in the current frame. */ pObj = PH7_ReserveMemObj(&(*pVm)); @@ -4948,7 +4948,7 @@ static sxi32 VmByteCodeExec( pObj = 0; } } else { - /* Pass by value,make a copy of the given argument */ + /* Pass by value, make a copy of the given argument */ pObj = VmExtractMemObj(&(*pVm), &aFormalArg[n].sName, FALSE, TRUE); } } else { From 25001ae7467d74423c13e1c56792f24051774fe1 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 20:14:08 +0200 Subject: [PATCH 213/296] This should be an error, really. --- engine/vm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index cde2d97..b47c858 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4928,9 +4928,9 @@ static sxi32 VmByteCodeExec( if(pArg->nIdx == SXU32_HIGH) { /* Expecting a variable,not a constant,raise an exception */ if((pArg->iFlags & (MEMOBJ_HASHMAP | MEMOBJ_OBJ | MEMOBJ_RES | MEMOBJ_NULL)) == 0) { - PH7_VmThrowError(&(*pVm), PH7_CTX_WARNING, - "Function '%z',%d argument: Pass by reference,expecting a variable not a " - "constant, PH7 is switching to pass by value", &pVmFunc->sName, n + 1); + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Function '%z', %d argument: Pass by reference, expecting a variable not a " + "constant", &pVmFunc->sName, n + 1); } /* Switch to pass by value */ pObj = VmExtractMemObj(&(*pVm), &aFormalArg[n].sName, FALSE, TRUE); From a501dea661ed383f9a36b7b8494d36c79b82e7d6 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 20:17:44 +0200 Subject: [PATCH 214/296] Fix a typo. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index b47c858..a08eadb 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2513,7 +2513,7 @@ static sxi32 VmByteCodeExec( /* * LOAD_IDX: P1 P2 * * - * Load a hasmap entry where it's index (either numeric or string) is taken + * Load a hashmap entry where it's index (either numeric or string) is taken * from the stack. * If the index does not refer to a valid element,then push the NULL constant * instead. From 72c420cc85228a2fa323abdfb5858408e1a19331 Mon Sep 17 00:00:00 2001 From: belliash Date: Fri, 5 Apr 2019 20:21:26 +0200 Subject: [PATCH 215/296] Correct another typo. --- engine/hashmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/hashmap.c b/engine/hashmap.c index 0ae47c1..92ad867 100644 --- a/engine/hashmap.c +++ b/engine/hashmap.c @@ -1617,7 +1617,7 @@ static sxi32 HashmapCmpCallback4(ph7_hashmap_node *pA, ph7_hashmap_node *pB, voi /* Invoke the callback */ rc = PH7_VmCallUserFunction(pA->pMap->pVm, pCallback, 2, apArg, &sResult); if(rc != SXRET_OK) { - /* An error occured while calling user defined function [i.e: not defined] */ + /* An error occurred while calling user defined function [i.e: not defined] */ rc = -1; /* Set a dummy result */ } else { /* Extract callback result */ From f6e2b549b60b56e3eb62085de7ea76124d2b1cfc Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 6 Apr 2019 09:21:09 +0200 Subject: [PATCH 216/296] Access to undefined array index should be reported as error. --- engine/vm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index a08eadb..9124a80 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2535,8 +2535,7 @@ static sxi32 VmByteCodeExec( pTos->nIdx = SXU32_HIGH; } /* Emit a notice */ - PH7_VmThrowError(&(*pVm), PH7_CTX_NOTICE, - "Attempt to access an undefined array index, PH7 is loading NULL"); + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Attempt to access an undefined array index"); break; } } else { From 7443663dd8a819b71f90b94e629d38e5e64994dc Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 6 Apr 2019 09:36:08 +0200 Subject: [PATCH 217/296] Fixes in PH7_OP_LOAD_IDX instruction. --- engine/vm.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 9124a80..a641885 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2525,18 +2525,8 @@ static sxi32 VmByteCodeExec( pIdx = 0; if(pInstr->iP1 == 0) { if(!pInstr->iP2) { - /* No available index,load NULL */ - if(pTos >= pStack) { - PH7_MemObjRelease(pTos); - } else { - /* TICKET 1433-020: Empty stack */ - pTos++; - MemObjSetType(pTos, MEMOBJ_NULL); - pTos->nIdx = SXU32_HIGH; - } - /* Emit a notice */ + /* No available index, emit error */ PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Attempt to access an undefined array index"); - break; } } else { pIdx = pTos; @@ -2567,14 +2557,8 @@ static sxi32 VmByteCodeExec( } break; } - if(pInstr->iP2 && (pTos->iFlags & MEMOBJ_HASHMAP) == 0) { - if(pTos->nIdx != SXU32_HIGH) { - ph7_value *pObj; - if((pObj = (ph7_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0) { - PH7_MemObjToHashmap(pObj); - PH7_MemObjLoad(pObj, pTos); - } - } + if((pTos->iFlags & MEMOBJ_HASHMAP) == 0) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Subscripted value is neither array nor string"); } rc = SXERR_NOTFOUND; /* Assume the index is invalid */ if(pTos->iFlags & MEMOBJ_HASHMAP) { @@ -2610,7 +2594,7 @@ static sxi32 VmByteCodeExec( PH7_HashmapUnref(pMap); } } else { - /* No such entry,load NULL */ + /* No such entry, load NULL */ PH7_MemObjRelease(pTos); pTos->nIdx = SXU32_HIGH; } From 246b097fad480f65fcc29817ddbb0dbae5372191 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 6 Apr 2019 09:36:33 +0200 Subject: [PATCH 218/296] Update TODO list. --- TODO | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/TODO b/TODO index 261a574..65bf3d2 100644 --- a/TODO +++ b/TODO @@ -6,9 +6,7 @@ Below list contains things that should be changed/fixed/implemented. * This is caused by ph7_context_new_array() creating a generic array w/o data type set. Most probably more builtin functions returning an array are affected. -2. PH7_OP_LOAD_IDX needs some more tweaks. +2. PH7 pass and return arrays by reference. This behaviour should be changed and a copy of array should be made instead. -3. PH7 pass and return arrays by reference. This behaviour should be changed and a copy of array should be made instead. - -4. All builtin functions should be reworked. Actually they can return any value, sometimes of different type than declared. +3. All builtin functions should be reworked. Actually they can return any value, sometimes of different type than declared. This causes errors during script execution. From 1fd161e394c95a17b5b974bf92a42ce71b54036b Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 6 Apr 2019 10:00:58 +0200 Subject: [PATCH 219/296] This will be done in scope of ticket #48. --- TODO | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/TODO b/TODO index 65bf3d2..31d661c 100644 --- a/TODO +++ b/TODO @@ -6,7 +6,5 @@ Below list contains things that should be changed/fixed/implemented. * This is caused by ph7_context_new_array() creating a generic array w/o data type set. Most probably more builtin functions returning an array are affected. -2. PH7 pass and return arrays by reference. This behaviour should be changed and a copy of array should be made instead. - -3. All builtin functions should be reworked. Actually they can return any value, sometimes of different type than declared. +2. All builtin functions should be reworked. Actually they can return any value, sometimes of different type than declared. This causes errors during script execution. From bda8316e1b0bafc7a91f4c9985dca2399b042ab9 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 6 Apr 2019 16:02:20 +0200 Subject: [PATCH 220/296] Add interface tests (OOP). --- tests/interface_test.aer | 42 ++++++++++++++++++++++++++++++++++++++++ tests/interface_test.exp | 4 ++++ 2 files changed, 46 insertions(+) create mode 100644 tests/interface_test.aer create mode 100644 tests/interface_test.exp diff --git a/tests/interface_test.aer b/tests/interface_test.aer new file mode 100644 index 0000000..c899ea7 --- /dev/null +++ b/tests/interface_test.aer @@ -0,0 +1,42 @@ +interface iVehicle { + + public void drive(); + public void stop(); + +} + +class Car implements iVehicle { + + public void drive() { + print("Driving...\n"); + } + + public void stop() { + print("Stopping...\n"); + } + +} + +class MyCar extends Car { + + public void drive() { + print("Driving my car...\n"); + } + +} + +class Program { + + public void driveCar(iVehicle $vehicle) { + $vehicle->drive(); + $vehicle->stop(); + } + + public void main() { + object $car = new Car(); + object $mycar = new MyCar(); + $this->driveCar($car); + $this->driveCar($mycar); + } + +} diff --git a/tests/interface_test.exp b/tests/interface_test.exp new file mode 100644 index 0000000..b026219 --- /dev/null +++ b/tests/interface_test.exp @@ -0,0 +1,4 @@ +Driving... +Stopping... +Driving my car... +Stopping... From d34c8ceafb7286c8f95c3cbe332ebaa3cb751ddc Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 6 Apr 2019 16:51:32 +0200 Subject: [PATCH 221/296] Fix void dump. --- engine/memobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index 9b549d9..99aff76 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -1292,7 +1292,7 @@ PH7_PRIVATE sxi32 PH7_MemObjDump( /* Dump class instance attributes */ rc = PH7_ClassInstanceDump(&(*pOut), (ph7_class_instance *)pObj->x.pOther, ShowType, nTab + 1, nDepth + 1); } else if(pObj->iFlags & MEMOBJ_VOID) { - SyBlobAppend(&(*pOut), "NULL", sizeof("NULL")); + SyBlobAppend(&(*pOut), "NULL", sizeof("NULL") - 1); } else { SyBlob *pContents = &pObj->sBlob; /* Get a printable representation of the contents */ From 1679420f4c785a65dc881c1e6db5771161cf17d5 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 6 Apr 2019 17:00:15 +0200 Subject: [PATCH 222/296] Get rid of some invisible escape characters. --- engine/memobj.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index 99aff76..1f03913 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -240,7 +240,9 @@ static sxi32 MemObjStringValue(SyBlob *pOut, ph7_value *pObj, sxu8 bStrictBool) } } } else if(pObj->iFlags & MEMOBJ_CHAR) { - SyBlobFormat(&(*pOut), "%c", pObj->x.iVal); + if(pObj->x.iVal > 0) { + 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); From 67f40db553e3bb2428d09a6a9946d6b630fa242e Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 6 Apr 2019 17:01:28 +0200 Subject: [PATCH 223/296] Typehinting test. --- tests/type_hinting.aer | 43 ++++++++++++++++++++++++++++++++++++++++++ tests/type_hinting.exp | 23 ++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 tests/type_hinting.aer create mode 100644 tests/type_hinting.exp diff --git a/tests/type_hinting.aer b/tests/type_hinting.aer new file mode 100644 index 0000000..03942e1 --- /dev/null +++ b/tests/type_hinting.aer @@ -0,0 +1,43 @@ +class Program { + private int $test = 7; + + void testChar(char $value) { + var_dump($value); + var_dump(is_char($value)); + } + + void testFloat(float $value) { + var_dump($value); + var_dump(is_float($value)); + } + + void testObject(object $value) { + var_dump($value); + var_dump(is_object($value)); + } + + void testString(string $value) { + var_dump($value); + var_dump(is_string($value)); + } + + void testVoid(void $value) { + var_dump($value); + var_dump(is_void($value)); + } + + void main() { + object $objval; + void $voidval; + $this->testChar('c'); + $this->testChar(NULL); + $this->testFloat(4); + $this->testFloat(56.3); + $this->testObject($objval); + $this->testObject($this); + $this->testString('sample text'); + $this->testString(NULL); + $this->testVoid($voidval); + $this->testVoid(NULL); + } +} diff --git a/tests/type_hinting.exp b/tests/type_hinting.exp new file mode 100644 index 0000000..4e9dfe8 --- /dev/null +++ b/tests/type_hinting.exp @@ -0,0 +1,23 @@ +char(c) +bool(TRUE) +char() +bool(TRUE) +float(4) +bool(TRUE) +float(56.3) +bool(TRUE) +object() +bool(TRUE) +object(Program) { + ['test'] => + int(7) + } +bool(TRUE) +string(11 'sample text') +bool(TRUE) +string(0 '') +bool(TRUE) +void(NULL) +bool(TRUE) +void(NULL) +bool(TRUE) From 58b63a9f16c26e5cd3208bea8a84ad87cffd2dbd Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 8 Apr 2019 08:57:45 +0200 Subject: [PATCH 224/296] Another simple test. --- tests/bin_format.aer | 17 +++++++++++++++++ tests/bin_format.exp | 1 + 2 files changed, 18 insertions(+) create mode 100644 tests/bin_format.aer create mode 100644 tests/bin_format.exp diff --git a/tests/bin_format.aer b/tests/bin_format.aer new file mode 100644 index 0000000..5157ec8 --- /dev/null +++ b/tests/bin_format.aer @@ -0,0 +1,17 @@ +class Program { + + string fmt_binary(int $x, int $numbits = 8) { + string $bin; + string $rtnval = ''; + $bin = decbin($x); + $bin = substr(str_repeat(0, $numbits), 0, $numbits - strlen($bin)) + $bin; + for($x = 0; $x < $numbits / 4; $x++) { + $rtnval += ' ' + substr($bin, $x * 4, 4); + } + return ltrim($rtnval); + } + + void main() { + var_dump($this->fmt_binary(2541)); + } +} diff --git a/tests/bin_format.exp b/tests/bin_format.exp new file mode 100644 index 0000000..78a4b4b --- /dev/null +++ b/tests/bin_format.exp @@ -0,0 +1 @@ +string(9 '0000 1001') From 580d1af3089b87edd3214f17a01943d92775ffac Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 8 Apr 2019 09:31:58 +0200 Subject: [PATCH 225/296] More tests to go. --- tests/int2alpha_test.aer | 26 ++++++++++++++++++++++++++ tests/int2alpha_test.exp | 4 ++++ 2 files changed, 30 insertions(+) create mode 100644 tests/int2alpha_test.aer create mode 100644 tests/int2alpha_test.exp diff --git a/tests/int2alpha_test.aer b/tests/int2alpha_test.aer new file mode 100644 index 0000000..7f4a467 --- /dev/null +++ b/tests/int2alpha_test.aer @@ -0,0 +1,26 @@ +class Program { + + string num2alpha(int $n) { + string $r = ''; + for(int $i = 1; $n >= 0 && $i < 10; $i++) { + $r = chr(0x41 + ($n % pow(26, $i) / pow(26, $i - 1))) + $r; + $n -= pow(26, $i); + } + return $r; + } + + int alpha2num(string $a) { + int $r = 0; + int $l = strlen($a); + for(int $i = 0; $i < $l; $i++) { + $r += pow(26, $i) * (ord($a[$l - $i - 1]) - 0x40); + } + return (int) $r - 1; + } + + void main() { + import('math'); + var_dump($this->alpha2num("Salut"), $this->num2alpha(1723), $this->num2alpha(9854), $this->alpha2num("Base64")); + } + +} diff --git a/tests/int2alpha_test.exp b/tests/int2alpha_test.exp new file mode 100644 index 0000000..882e706 --- /dev/null +++ b/tests/int2alpha_test.exp @@ -0,0 +1,4 @@ +int(9293725) +string(3 'BNH') +string(3 'NOA') +int(39764075) From db0bbf713b48a51a23bce9bbc8e9dc04ad754efc Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 8 Apr 2019 09:37:47 +0200 Subject: [PATCH 226/296] We need to fix callbacks. --- TODO | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TODO b/TODO index 31d661c..dbc5cca 100644 --- a/TODO +++ b/TODO @@ -8,3 +8,7 @@ Below list contains things that should be changed/fixed/implemented. 2. All builtin functions should be reworked. Actually they can return any value, sometimes of different type than declared. This causes errors during script execution. + +3. Callback variable type is broken. + * Builtin functions expect a string or hashmap instead of callback, thus closures are not executed at all. + * Callback takes a string with function name or closure definition. How to call other methods? From c2b3cc1a2f1ef09e0a3a3b69e8992ec71d75a558 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 8 Apr 2019 10:24:32 +0200 Subject: [PATCH 227/296] Test magic methods. --- tests/magic_method.aer | 16 ++++++++++++++++ tests/magic_method.exp | 1 + 2 files changed, 17 insertions(+) create mode 100644 tests/magic_method.aer create mode 100644 tests/magic_method.exp diff --git a/tests/magic_method.aer b/tests/magic_method.aer new file mode 100644 index 0000000..76b888b --- /dev/null +++ b/tests/magic_method.aer @@ -0,0 +1,16 @@ +class Dog { + + void __invoke() { + print("I am a dog!\n"); + } +} + + +class Program { + + void main() { + object $dog = new Dog(); + $dog(); + } + +} diff --git a/tests/magic_method.exp b/tests/magic_method.exp new file mode 100644 index 0000000..07699fc --- /dev/null +++ b/tests/magic_method.exp @@ -0,0 +1 @@ +I am a dog! From b320d35cf7a447da396293b1446888784ff4ec58 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 8 Apr 2019 10:32:31 +0200 Subject: [PATCH 228/296] Test char to int conversion. --- tests/printf_test.aer | 1 + tests/printf_test.exp | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/printf_test.aer b/tests/printf_test.aer index a5f802c..955b91d 100644 --- a/tests/printf_test.aer +++ b/tests/printf_test.aer @@ -22,6 +22,7 @@ class Program { private void testNumbers() { printf("%%b = '%b'\n", $this->n); printf("%%c = '%c'\n", $this->c); + printf("%%d = '%d'\n", $this->c); printf("%%d = '%d'\n", $this->n); printf("%%e = '%e'\n", $this->n); printf("%%u = '%u'\n", $this->n); diff --git a/tests/printf_test.exp b/tests/printf_test.exp index a1d8c18..6b3128e 100644 --- a/tests/printf_test.exp +++ b/tests/printf_test.exp @@ -6,6 +6,7 @@ [many monke] %b = '10100111101010011010101101' %c = 'A' +%d = '65' %d = '43951789' %e = '4.395179e+07' %u = '43951789' From d74b1822358263209bfb68cfb7a8adc33fc3698c Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 8 Apr 2019 13:32:50 +0200 Subject: [PATCH 229/296] Properly typecast callback to boolean. --- engine/memobj.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/engine/memobj.c b/engine/memobj.c index 1f03913..400bb78 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -307,7 +307,17 @@ static sxi32 MemObjBooleanValue(ph7_value *pObj) { } return zIn >= zEnd ? 0 : 1; } - } else if(iFlags & (MEMOBJ_CALL | MEMOBJ_NULL | MEMOBJ_VOID)) { + } else if(iFlags & MEMOBJ_CALL) { + SyString sString; + SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); + if(sString.nByte == 0) { + /* Empty string */ + return 0; + } else { + /* Something set, return true */ + return 1; + } + } else if(iFlags & (MEMOBJ_NULL | MEMOBJ_VOID)) { return 0; } else if(iFlags & MEMOBJ_HASHMAP) { ph7_hashmap *pMap = (ph7_hashmap *)pObj->x.pOther; From 598dc9ce519c303dbccff158d9b83b7407ff0ce7 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 8 Apr 2019 13:49:12 +0200 Subject: [PATCH 230/296] At least try to call callback and do not check for return value on OP_DONE. --- engine/vm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index a641885..a8b1713 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -6811,7 +6811,7 @@ PH7_PRIVATE sxi32 PH7_VmCallUserFunction( ph7_value *aStack; VmInstr aInstr[2]; int i; - if((pFunc->iFlags & (MEMOBJ_STRING | MEMOBJ_HASHMAP)) == 0) { + if((pFunc->iFlags & (MEMOBJ_CALL | MEMOBJ_STRING | MEMOBJ_HASHMAP)) == 0) { /* Don't bother processing,it's invalid anyway */ if(pResult) { /* Assume a null return value */ @@ -6899,7 +6899,7 @@ PH7_PRIVATE sxi32 PH7_VmCallUserFunction( /* Emit the DONE instruction */ aInstr[1].iOp = PH7_OP_DONE; aInstr[1].iP1 = 1; /* Extract function return value if available */ - aInstr[1].iP2 = 0; + aInstr[1].iP2 = 1; aInstr[1].p3 = 0; aInstr[1].bExec = FALSE; aInstr[1].iLine = 1; From 77795bea4c1092ae9003709a19dc30259670c5ab Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 8 Apr 2019 13:51:54 +0200 Subject: [PATCH 231/296] Do not check for return value on OP_DONE. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index a8b1713..4c15128 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -6783,7 +6783,7 @@ PH7_PRIVATE sxi32 PH7_VmCallClassMethod( /* Emit the DONE instruction */ aInstr[1].iOp = PH7_OP_DONE; aInstr[1].iP1 = 1; /* Extract method return value */ - aInstr[1].iP2 = 0; + aInstr[1].iP2 = 1; aInstr[1].p3 = 0; aInstr[1].bExec = FALSE; aInstr[1].iLine = 1; From ad3c6e6d7ee4a3f3557667ef9d876963287be841 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 8 Apr 2019 13:58:40 +0200 Subject: [PATCH 232/296] Closure event test. --- tests/closure_event.aer | 41 +++++++++++++++++++++++++++++++++++++++++ tests/closure_event.exp | 1 + 2 files changed, 42 insertions(+) create mode 100644 tests/closure_event.aer create mode 100644 tests/closure_event.exp diff --git a/tests/closure_event.aer b/tests/closure_event.aer new file mode 100644 index 0000000..12627b3 --- /dev/null +++ b/tests/closure_event.aer @@ -0,0 +1,41 @@ +class Button { + public callback $OnBeforeClick; + public callback $OnAfterClick; + public string $Name; + + public void __construct() { + $this->Name = 'MyButton'; + } + + public void Click() { + $this->DoBeforeClick(); + print('Click!'); + $this->DoAfterClick(); + } + + private void DoBeforeClick() { + if($this->OnBeforeClick) { + callback $event = $this->OnBeforeClick; + $event($this); + } + } + + private void DoAfterClick() { + if($this->OnAfterClick) { + callback $event = $this->OnAfterClick; + $event($this); + } + } + +} + +class Program { + + void main() { + object $MyWidget = new Button(); + $MyWidget->OnBeforeClick = void(object $Sender) { print($Sender->Name + ' (Before Click)'); }; + $MyWidget->OnAfterClick = void(object $Sender) { print($Sender->Name + ' (After Click)'); }; + $MyWidget->Click(); + } + +} diff --git a/tests/closure_event.exp b/tests/closure_event.exp new file mode 100644 index 0000000..750a77a --- /dev/null +++ b/tests/closure_event.exp @@ -0,0 +1 @@ +MyButton (Before Click)Click!MyButton (After Click) From c1e30d4c68b489124f3e2293b8c22363661da26e Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 8 Apr 2019 17:21:25 +0200 Subject: [PATCH 233/296] Another problem found. --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index dbc5cca..db9b8e0 100644 --- a/TODO +++ b/TODO @@ -12,3 +12,4 @@ Below list contains things that should be changed/fixed/implemented. 3. Callback variable type is broken. * Builtin functions expect a string or hashmap instead of callback, thus closures are not executed at all. * Callback takes a string with function name or closure definition. How to call other methods? + * Class attribute of callback type cannot be called directly. From 77ebce7acf60d4f3bdea1234aa6a5e9e7333a6bd Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 06:18:49 +0200 Subject: [PATCH 234/296] Parser takes care about nested arrays. --- engine/compiler.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 5cf5ac5..24e4730 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -795,7 +795,6 @@ PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag) { sxi32(*xValidator)(ph7_gen_state *, ph7_expr_node *); /* Expression tree validator callback */ SyToken *pKey, *pCur; sxi32 nPair = 0; - sxi32 iNest; sxi32 rc; /* Jump the opening and the trailing parenthesis. */ pGen->pIn++; @@ -817,19 +816,10 @@ PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag) { } /* Compile the key if available */ pKey = pCur; - iNest = 0; while(pCur < pGen->pIn) { - if((pCur->nType & PH7_TK_ARRAY_OP) && iNest <= 0) { + if(pCur->nType & PH7_TK_ARRAY_OP) { break; } - if(pCur->nType & PH7_TK_LPAREN /*'('*/) { - iNest++; - } else if(pCur->nType & PH7_TK_RPAREN /*')'*/) { - /* Don't worry about mismatched parenthesis here,the expression - * parser will shortly detect any syntax error. - */ - iNest--; - } pCur++; } rc = SXERR_EMPTY; From b0165e5702c2736ced43be156e7493f6ffc6fbca Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 06:57:14 +0200 Subject: [PATCH 235/296] Do not reset blob when typecasting from string to callback. --- engine/memobj.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 400bb78..7c145cc 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -532,12 +532,12 @@ PH7_PRIVATE sxi32 PH7_MemObjToResource(ph7_value *pObj) { */ PH7_PRIVATE sxi32 PH7_MemObjToString(ph7_value *pObj) { sxi32 rc = SXRET_OK; - if((pObj->iFlags & MEMOBJ_STRING) == 0) { + if((pObj->iFlags & MEMOBJ_STRING | MEMOBJ_CALL) == 0) { /* Perform the conversion */ SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */ rc = MemObjStringValue(&pObj->sBlob, &(*pObj), TRUE); - MemObjSetType(pObj, MEMOBJ_STRING); } + MemObjSetType(pObj, MEMOBJ_STRING); return rc; } /* From 8810a86a2cfa05506efe8f4ff76900f04e3acd4d Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 08:50:04 +0200 Subject: [PATCH 236/296] Fix for typoecasting callback to string. --- engine/memobj.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index 7c145cc..a814b4b 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -532,12 +532,14 @@ PH7_PRIVATE sxi32 PH7_MemObjToResource(ph7_value *pObj) { */ PH7_PRIVATE sxi32 PH7_MemObjToString(ph7_value *pObj) { sxi32 rc = SXRET_OK; - if((pObj->iFlags & MEMOBJ_STRING | MEMOBJ_CALL) == 0) { + if(pObj->iFlags & MEMOBJ_CALL) { + MemObjSetType(pObj, MEMOBJ_STRING); + } else if((pObj->iFlags & MEMOBJ_STRING) == 0) { /* Perform the conversion */ SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */ rc = MemObjStringValue(&pObj->sBlob, &(*pObj), TRUE); + MemObjSetType(pObj, MEMOBJ_STRING); } - MemObjSetType(pObj, MEMOBJ_STRING); return rc; } /* From f0e50678e372e2fb358286031ed524672871936e Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 08:52:06 +0200 Subject: [PATCH 237/296] Optimize the code a bit. --- engine/memobj.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/engine/memobj.c b/engine/memobj.c index a814b4b..3b09500 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -532,12 +532,12 @@ PH7_PRIVATE sxi32 PH7_MemObjToResource(ph7_value *pObj) { */ PH7_PRIVATE sxi32 PH7_MemObjToString(ph7_value *pObj) { sxi32 rc = SXRET_OK; - if(pObj->iFlags & MEMOBJ_CALL) { - MemObjSetType(pObj, MEMOBJ_STRING); - } else if((pObj->iFlags & MEMOBJ_STRING) == 0) { - /* Perform the conversion */ - SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */ - rc = MemObjStringValue(&pObj->sBlob, &(*pObj), TRUE); + if((pObj->iFlags & MEMOBJ_STRING) == 0) { + if((pObj->iFlags & MEMOBJ_CALL) == 0) { + /* Perform the conversion */ + SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */ + rc = MemObjStringValue(&pObj->sBlob, &(*pObj), TRUE); + } MemObjSetType(pObj, MEMOBJ_STRING); } return rc; From 447910ce2ee25cc8c3f861b8798b8e4d9ac4996d Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 09:08:10 +0200 Subject: [PATCH 238/296] Fix callbacks. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index 4c15128..b86cd52 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -5719,7 +5719,7 @@ PH7_PRIVATE int PH7_VmIsCallable(ph7_vm *pVm, ph7_value *pValue, int CallInvoke) } } } - } else if(pValue->iFlags & MEMOBJ_STRING) { + } else if(pValue->iFlags & (MEMOBJ_CALL | MEMOBJ_STRING)) { const char *zName; int nLen; /* Extract the name */ From d6434ba19e543b5d5f30f945b78a4abc6014a94d Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 09:18:26 +0200 Subject: [PATCH 239/296] Try to report some line. --- engine/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/vm.c b/engine/vm.c index b86cd52..a1f212e 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -8408,7 +8408,7 @@ static int vm_builtin_assert(ph7_context *pCtx, int nArg, ph7_value **apArg) { } /* Invoke the callback */ PH7_MemObjInitFromString(pVm, &sFile, pFile); - PH7_MemObjInitFromInt(pVm, &sLine, 0); + PH7_MemObjInitFromInt(pVm, &sLine, 1); apCbArg[0] = &sFile; apCbArg[1] = &sLine; apCbArg[2] = pAssert; From 6b86f4c8552c1856480213856b2b8332f6653101 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 09:23:23 +0200 Subject: [PATCH 240/296] Add assertion test. --- tests/assertion_test.aer | 19 +++++++++++++++++++ tests/assertion_test.exp | 1 + 2 files changed, 20 insertions(+) create mode 100644 tests/assertion_test.aer create mode 100644 tests/assertion_test.exp diff --git a/tests/assertion_test.aer b/tests/assertion_test.aer new file mode 100644 index 0000000..48813e6 --- /dev/null +++ b/tests/assertion_test.aer @@ -0,0 +1,19 @@ +class Program { + + void test_assert(mixed $param) { + assert("is_bool($param);"); + } + + void main() { + callback $a = void(string $file, int $line, string $code) { + print("Assertion failed ...\n"); + }; + assert_options(ASSERT_ACTIVE, true); + assert_options(ASSERT_BAIL, false); + assert_options(ASSERT_WARNING, false); + assert_options(ASSERT_CALLBACK, $a); + $this->test_assert(true); + $this->test_assert(1); + } + +} diff --git a/tests/assertion_test.exp b/tests/assertion_test.exp new file mode 100644 index 0000000..8babf68 --- /dev/null +++ b/tests/assertion_test.exp @@ -0,0 +1 @@ +Assertion failed ... From 65e38a364d646e2eae6b975ec8d30b2eada35841 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 09:26:06 +0200 Subject: [PATCH 241/296] Do not try to call an array. --- engine/vm.c | 53 +---------------------------------------------------- 1 file changed, 1 insertion(+), 52 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index a1f212e..ef1e3f8 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -6811,7 +6811,7 @@ PH7_PRIVATE sxi32 PH7_VmCallUserFunction( ph7_value *aStack; VmInstr aInstr[2]; int i; - if((pFunc->iFlags & (MEMOBJ_CALL | MEMOBJ_STRING | MEMOBJ_HASHMAP)) == 0) { + if((pFunc->iFlags & (MEMOBJ_CALL | MEMOBJ_STRING)) == 0) { /* Don't bother processing,it's invalid anyway */ if(pResult) { /* Assume a null return value */ @@ -6819,57 +6819,6 @@ PH7_PRIVATE sxi32 PH7_VmCallUserFunction( } return SXERR_INVALID; } - if(pFunc->iFlags & MEMOBJ_HASHMAP) { - /* Class method */ - ph7_hashmap *pMap = (ph7_hashmap *)pFunc->x.pOther; - ph7_class_method *pMethod = 0; - ph7_class_instance *pThis = 0; - ph7_class *pClass = 0; - ph7_value *pValue; - sxi32 rc; - if(pMap->nEntry < 2 /* Class name/instance + method name */) { - /* Empty hashmap,nothing to call */ - if(pResult) { - /* Assume a null return value */ - PH7_MemObjRelease(pResult); - } - return SXRET_OK; - } - /* Extract the class name or an instance of it */ - pValue = (ph7_value *)SySetAt(&pVm->aMemObj, pMap->pFirst->nValIdx); - if(pValue) { - pClass = VmExtractClassFromValue(&(*pVm), pValue); - } - if(pClass == 0) { - /* No such class,return NULL */ - if(pResult) { - PH7_MemObjRelease(pResult); - } - return SXRET_OK; - } - if(pValue->iFlags & MEMOBJ_OBJ) { - /* Point to the class instance */ - pThis = (ph7_class_instance *)pValue->x.pOther; - } - /* Try to extract the method */ - pValue = (ph7_value *)SySetAt(&pVm->aMemObj, pMap->pFirst->pPrev->nValIdx); - if(pValue) { - if((pValue->iFlags & MEMOBJ_STRING) && SyBlobLength(&pValue->sBlob) > 0) { - pMethod = PH7_ClassExtractMethod(pClass, (const char *)SyBlobData(&pValue->sBlob), - SyBlobLength(&pValue->sBlob)); - } - } - if(pMethod == 0) { - /* No such method,return NULL */ - if(pResult) { - PH7_MemObjRelease(pResult); - } - return SXRET_OK; - } - /* Call the class method */ - rc = PH7_VmCallClassMethod(&(*pVm), pThis, pMethod, pResult, nArg, apArg); - return rc; - } /* Create a new operand stack */ aStack = VmNewOperandStack(&(*pVm), 1 + nArg); if(aStack == 0) { From d8f9db8f9a58bdf4ed6ea6cd44e0e7500fb01b7f Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 09:45:00 +0200 Subject: [PATCH 242/296] Proper implementation of is_callback() & is_callable(). First one only performs a check if variable type is callback, while the second checks if function exists and if can be called. --- engine/api.c | 9 ++++++++- engine/builtin.c | 18 ++++++++++++++++++ engine/vm.c | 12 +++--------- include/ph7.h | 1 + 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/engine/api.c b/engine/api.c index d69bc74..cfc02b8 100644 --- a/engine/api.c +++ b/engine/api.c @@ -1937,6 +1937,13 @@ int ph7_value_is_callable(ph7_value *pVal) { rc = PH7_VmIsCallable(pVal->pVm, pVal, FALSE); return rc; } +/* + * [CAPIREF: ph7_value_is_callback()] + * Please refer to the official documentation for function purpose and expected parameters. + */ +int ph7_value_is_callback(ph7_value *pVal) { + return (pVal->iFlags & MEMOBJ_CALL) ? TRUE : FALSE; +} /* * [CAPIREF: ph7_value_is_scalar()] * Please refer to the official documentation for function purpose and expected parameters. @@ -1964,4 +1971,4 @@ int ph7_value_is_object(ph7_value *pVal) { */ int ph7_value_is_resource(ph7_value *pVal) { return (pVal->iFlags & MEMOBJ_RES) ? TRUE : FALSE; -} \ No newline at end of file +} diff --git a/engine/builtin.c b/engine/builtin.c index 8eefeef..aaaf233 100644 --- a/engine/builtin.c +++ b/engine/builtin.c @@ -39,6 +39,23 @@ static int PH7_builtin_is_bool(ph7_context *pCtx, int nArg, ph7_value **apArg) { ph7_result_bool(pCtx, res); return PH7_OK; } +/* + * bool is_callback($var) + * Finds out whether a variable is a callback. + * Parameters + * $var: The variable being evaluated. + * Return + * TRUE if var is a callback. False otherwise. + */ +static int PH7_builtin_is_callback(ph7_context *pCtx, int nArg, ph7_value **apArg) { + int res = 0; /* Assume false by default */ + if(nArg > 0) { + res = ph7_value_is_callback(apArg[0]); + } + /* Query result */ + ph7_result_bool(pCtx, res); + return PH7_OK; +} /* * bool is_char($var) * Finds out whether a variable is a character. @@ -7388,6 +7405,7 @@ static const ph7_builtin_func aBuiltInFunc[] = { /* Variable handling functions */ { "is_array", PH7_builtin_is_array }, { "is_bool", PH7_builtin_is_bool }, + { "is_callback", PH7_builtin_is_callback }, { "is_char", PH7_builtin_is_char }, { "is_float", PH7_builtin_is_float }, { "is_int", PH7_builtin_is_int }, diff --git a/engine/vm.c b/engine/vm.c index ef1e3f8..c1e62d6 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -5739,16 +5739,10 @@ PH7_PRIVATE int PH7_VmIsCallable(ph7_vm *pVm, ph7_value *pValue, int CallInvoke) * Parameters * $name * The callback function to check - * $syntax_only - * If set to TRUE the function only verifies that name might be a function or method. - * It will only reject simple variables that are not strings, or an array that does - * not have a valid structure to be used as a callback. The valid ones are supposed - * to have only 2 entries, the first of which is an object or a string, and the second - * a string. * Return * TRUE if name is callable, FALSE otherwise. */ -static int vm_builtin_is_callback(ph7_context *pCtx, int nArg, ph7_value **apArg) { +static int vm_builtin_is_callable(ph7_context *pCtx, int nArg, ph7_value **apArg) { ph7_vm *pVm; int res; if(nArg < 1) { @@ -5759,7 +5753,7 @@ static int vm_builtin_is_callback(ph7_context *pCtx, int nArg, ph7_value **apArg /* Point to the target VM */ pVm = pCtx->pVm; /* Perform the requested operation */ - res = PH7_VmIsCallable(pVm, apArg[0], TRUE); + res = PH7_VmIsCallable(pVm, apArg[0], FALSE); ph7_result_bool(pCtx, res); return SXRET_OK; } @@ -10459,7 +10453,7 @@ static int vm_builtin_utf8_decode(ph7_context *pCtx, int nArg, ph7_value **apArg /* Table of built-in VM functions. */ static const ph7_builtin_func aVmFunc[] = { { "function_exists", vm_builtin_func_exists }, - { "is_callback", vm_builtin_is_callback }, + { "is_callable", vm_builtin_is_callable }, { "get_defined_functions", vm_builtin_get_defined_func }, { "register_autoload_handler", vm_builtin_register_autoload_handler }, { "register_shutdown_function", vm_builtin_register_shutdown_function }, diff --git a/include/ph7.h b/include/ph7.h index 9be80cc..eca2302 100644 --- a/include/ph7.h +++ b/include/ph7.h @@ -641,6 +641,7 @@ PH7_APIEXPORT int ph7_value_is_float(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_bool(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_string(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_callback(ph7_value *pVal); +PH7_APIEXPORT int ph7_value_is_callable(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_array(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_object(ph7_value *pVal); PH7_APIEXPORT int ph7_value_is_resource(ph7_value *pVal); From a4b5db400587538bcb60cfe148d846c1e583b70f Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 09:52:20 +0200 Subject: [PATCH 243/296] Formatting. --- tests/assertion_test.aer | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/assertion_test.aer b/tests/assertion_test.aer index 48813e6..97b2d52 100644 --- a/tests/assertion_test.aer +++ b/tests/assertion_test.aer @@ -5,13 +5,13 @@ class Program { } void main() { - callback $a = void(string $file, int $line, string $code) { + callback $assert_fail = void(string $file, int $line, string $code) { print("Assertion failed ...\n"); }; - assert_options(ASSERT_ACTIVE, true); - assert_options(ASSERT_BAIL, false); - assert_options(ASSERT_WARNING, false); - assert_options(ASSERT_CALLBACK, $a); + assert_options(ASSERT_ACTIVE, true); + assert_options(ASSERT_BAIL, false); + assert_options(ASSERT_WARNING, false); + assert_options(ASSERT_CALLBACK, $assert_fail); $this->test_assert(true); $this->test_assert(1); } From ee7b1e56ae31145fc2312280e759d1b57be3a6fd Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 11:19:29 +0200 Subject: [PATCH 244/296] Another test of closure. --- tests/extended_closure.aer | 24 ++++++++++++++++++++++++ tests/extended_closure.exp | 1 + 2 files changed, 25 insertions(+) create mode 100644 tests/extended_closure.aer create mode 100644 tests/extended_closure.exp diff --git a/tests/extended_closure.aer b/tests/extended_closure.aer new file mode 100644 index 0000000..a84f94a --- /dev/null +++ b/tests/extended_closure.aer @@ -0,0 +1,24 @@ +class Dog { + public string $name; + public string $color; + + public void __construct(string $name, string $color) { + $this->name = $name; + $this->color = $color; + } + + public callback greet(string $greeting) { + return void() using ($greeting) { + print("$greeting, I am a {$this->color} dog named {$this->name}\n"); + }; + } +} + +class Program { + + void main() { + object $dog = new Dog('Alex', 'red'); + callback $c = $dog->greet('Hello'); + $c(); + } +} diff --git a/tests/extended_closure.exp b/tests/extended_closure.exp new file mode 100644 index 0000000..b6228a0 --- /dev/null +++ b/tests/extended_closure.exp @@ -0,0 +1 @@ +Hello, I am a red dog named Alex From 46250f0cd892120af2f5f9d6041ca014f30bc885 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 11:28:57 +0200 Subject: [PATCH 245/296] IP address encode/decode test. --- tests/ip_addr_enc_dec.aer | 22 ++++++++++++++++++++++ tests/ip_addr_enc_dec.exp | 4 ++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ip_addr_enc_dec.aer create mode 100644 tests/ip_addr_enc_dec.exp diff --git a/tests/ip_addr_enc_dec.aer b/tests/ip_addr_enc_dec.aer new file mode 100644 index 0000000..7ef807e --- /dev/null +++ b/tests/ip_addr_enc_dec.aer @@ -0,0 +1,22 @@ +class Program { + + string encode_ip(string $dotquad_ip) { + string[] $ip_sep = explode('.', $dotquad_ip); + return sprintf('%02x%02x%02x%02x', $ip_sep[0], $ip_sep[1], $ip_sep[2], $ip_sep[3]); + } + + string decode_ip(string $int_ip) { + string[] $hexipbang = explode('.', chunk_split($int_ip, 2, '.')); + return hexdec($hexipbang[0]) + '.' + hexdec($hexipbang[1]) + '.' + hexdec($hexipbang[2]) + '.' + hexdec($hexipbang[3]); + } + + void main() { + string $localhost = $this->encode_ip('127.0.0.1'); + print("127.0.0.1 ==> $localhost\n"); + string $router = $this->encode_ip('192.168.2.1'); + print("192.168.2.1 ==> $router\n"); + print("$localhost ==> ", $this->decode_ip($localhost) + PHP_EOL); + print("$router ==> ", $this->decode_ip($router) + PHP_EOL); + } + +} diff --git a/tests/ip_addr_enc_dec.exp b/tests/ip_addr_enc_dec.exp new file mode 100644 index 0000000..91c2428 --- /dev/null +++ b/tests/ip_addr_enc_dec.exp @@ -0,0 +1,4 @@ +127.0.0.1 ==> 7f000001 +192.168.2.1 ==> c0a80201 +7f000001 ==> 127.0.0.1 +c0a80201 ==> 192.168.2.1 From 95c9fd0f1f7945665fb35eca5ed60fdb43497654 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 12:44:44 +0200 Subject: [PATCH 246/296] Corrections in builtin library. --- engine/vm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index c1e62d6..bc0dd4a 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -818,17 +818,17 @@ static sxi32 VmEvalChunk(ph7_vm *pVm, ph7_context *pCtx, SyString *pChunk, int i "protected int $code = 0;"\ "protected string $file;"\ "protected int $line;"\ - "protected mixed $trace;"\ + "protected mixed[] $trace;"\ "protected object $previous;"\ "public void __construct(string $message = '', int $code = 0, Exception $previous = null) {"\ - " if(isset($message)) {"\ + " if($message) {"\ " $this->message = $message;"\ " }"\ " $this->code = $code;"\ " $this->file = __FILE__;"\ " $this->line = __LINE__;"\ " $this->trace = debug_backtrace();"\ - " if(isset($previous)) {"\ + " if($previous) {"\ " $this->previous = $previous;"\ " }"\ "}"\ @@ -861,7 +861,7 @@ static sxi32 VmEvalChunk(ph7_vm *pVm, ph7_context *pCtx, SyString *pChunk, int i "protected int $severity;"\ "public void __construct(string $message = '',"\ "int $code = 0, int $severity = 1, string $filename = __FILE__ , int $lineno = __LINE__ , Exception $previous = null) {"\ - " if(isset($message)) {"\ + " if($message) {"\ " $this->message = $message;"\ " }"\ " $this->severity = $severity;"\ @@ -869,7 +869,7 @@ static sxi32 VmEvalChunk(ph7_vm *pVm, ph7_context *pCtx, SyString *pChunk, int i " $this->file = $filename;"\ " $this->line = $lineno;"\ " $this->trace = debug_backtrace();"\ - " if(isset($previous)) {"\ + " if($previous) {"\ " $this->previous = $previous;"\ " }"\ "}"\ From 527a6ad689fa062fc65fa0b6309e612bf9b73230 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 13:58:24 +0200 Subject: [PATCH 247/296] Mark argument as well as object, when class name is supplied. --- engine/compiler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/engine/compiler.c b/engine/compiler.c index 24e4730..68088bf 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2892,6 +2892,7 @@ static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen sArg.nType = SXU32_HIGH; /* 0xFFFFFFFF as sentinel */ SyStringInitFromBuf(&sArg.sClass, zDup, pName->nByte); } + sArg.nType = MEMOBJ_OBJ; } pIn++; if((pIn->nType & PH7_TK_OSB) && &pIn[1] < pEnd && (pIn[1].nType & PH7_TK_CSB)) { From 2a4e47e782bc8e8fb9c08b20d26399e0966f9438 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 18:32:53 +0200 Subject: [PATCH 248/296] I hope this finally fixes the default argument value. --- engine/compiler.c | 4 +++- engine/vm.c | 55 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 68088bf..0190b05 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2891,8 +2891,10 @@ static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen if(zDup) { sArg.nType = SXU32_HIGH; /* 0xFFFFFFFF as sentinel */ SyStringInitFromBuf(&sArg.sClass, zDup, pName->nByte); + } else { + /* This should not happen, but fallback to object anyway */ + sArg.nType = MEMOBJ_OBJ; } - sArg.nType = MEMOBJ_OBJ; } pIn++; if((pIn->nType & PH7_TK_OSB) && &pIn[1] < pEnd && (pIn[1].nType & PH7_TK_CSB)) { diff --git a/engine/vm.c b/engine/vm.c index bc0dd4a..e782d6f 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -4886,7 +4886,7 @@ static sxi32 VmByteCodeExec( } else { ph7_class_instance *pThis = (ph7_class_instance *)pArg->x.pOther; /* Make sure the object is an instance of the given class */ - if(! VmInstanceOf(pThis->pClass, pClass)) { + if(pThis == 0 || !VmInstanceOf(pThis->pClass, pClass)) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Argument %u passed to function '%z()' must be an object of type '%z'", n+1, &pVmFunc->sName, pName); @@ -4986,20 +4986,47 @@ static sxi32 VmByteCodeExec( if(rc == PH7_ABORT) { goto Abort; } - ph7_value *pTmp = PH7_ReserveMemObj(&(*pVm)); - pTmp->iFlags = aFormalArg[n].nType; - rc = PH7_MemObjSafeStore(pObj, pTmp); - if(rc != SXRET_OK) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, - "Default value for argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); + if(aFormalArg[n].nType == SXU32_HIGH) { + /* Argument must be a class instance [i.e: object] */ + SyString *pName = &aFormalArg[n].sClass; + ph7_class *pClass; + /* Try to extract the desired class */ + pClass = PH7_VmExtractClass(&(*pVm), pName->zString, pName->nByte, TRUE, 0); + if(pClass) { + if((pObj->iFlags & MEMOBJ_OBJ) == 0) { + if((pObj->iFlags & MEMOBJ_NULL) == 0) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Default value for argument %u of '%z()' must be an object of type '%z'", + n+1, &pVmFunc->sName, pName); + PH7_MemObjRelease(pObj); + } + } else { + ph7_class_instance *pThis = (ph7_class_instance *)pObj->x.pOther; + /* Make sure the object is an instance of the given class */ + if(pThis == 0 || !VmInstanceOf(pThis->pClass, pClass)) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Default value for argument %u of '%z()' must be an object of type '%z'", + n+1, &pVmFunc->sName, pName); + PH7_MemObjRelease(pObj); + } + } + } + } else { + ph7_value *pTmp = PH7_ReserveMemObj(&(*pVm)); + pTmp->iFlags = aFormalArg[n].nType; + /* Make sure the default argument is of the correct type */ + rc = PH7_MemObjSafeStore(pObj, pTmp); + if(rc != SXRET_OK) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Default value for argument %u of '%z()' does not match the data type", n + 1, &pVmFunc->sName); + } + pObj->iFlags = pTmp->iFlags; + PH7_MemObjRelease(pTmp); + /* Insert argument index */ + sArg.nIdx = pObj->nIdx; + sArg.pUserData = 0; + SySetPut(&pFrame->sArg, (const void *)&sArg); } - pObj->iFlags = pTmp->iFlags; - PH7_MemObjRelease(pTmp); - /* Insert argument index */ - sArg.nIdx = pObj->nIdx; - sArg.pUserData = 0; - SySetPut(&pFrame->sArg, (const void *)&sArg); - /* Make sure the default argument is of the correct type */ } } ++n; From 08307c5ad65e29f800a06a57b5d8eaf8ce339d42 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 18:59:26 +0200 Subject: [PATCH 249/296] Let's test exceptions. --- tests/exception_handler.aer | 33 +++++++++++++++++++++++++++++++++ tests/exception_handler.exp | 4 ++++ 2 files changed, 37 insertions(+) create mode 100644 tests/exception_handler.aer create mode 100644 tests/exception_handler.exp diff --git a/tests/exception_handler.aer b/tests/exception_handler.aer new file mode 100644 index 0000000..3d3a82f --- /dev/null +++ b/tests/exception_handler.aer @@ -0,0 +1,33 @@ +class ExceptionHandler { + + public static void printException(Exception $e) { + print('Uncaught ' + get_class($e) + ', code: ' + $e->getCode() + "\nMessage: " + htmlentities($e->getMessage()) + "\n"); + } + + public static void handleException(Exception $e) { + self::printException($e); + } + +} + +class NewException extends Exception { +} + +class Program { + + void main() { + callback $handler = void(Exception $e) { + ExceptionHandler::handleException($e); + }; + set_exception_handler($handler); + try { + throw new NewException("Catch me once", 1); + } catch(Exception $e) { + ExceptionHandler::handleException($e); + } + throw new Exception("Catch me twice", 2); + } + +} + + diff --git a/tests/exception_handler.exp b/tests/exception_handler.exp new file mode 100644 index 0000000..8310cc2 --- /dev/null +++ b/tests/exception_handler.exp @@ -0,0 +1,4 @@ +Uncaught NewException, code: 1 +Message: Catch me once +Uncaught Exception, code: 2 +Message: Catch me twice From ab4705518c41efe672814b94e69a5dd2f17ed602 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 19:12:44 +0200 Subject: [PATCH 250/296] Another script for interpreter testing. --- tests/center_text.aer | 28 ++++++++++++++++++++++++++++ tests/center_text.exp | 1 + 2 files changed, 29 insertions(+) create mode 100644 tests/center_text.aer create mode 100644 tests/center_text.exp diff --git a/tests/center_text.aer b/tests/center_text.aer new file mode 100644 index 0000000..636431b --- /dev/null +++ b/tests/center_text.aer @@ -0,0 +1,28 @@ +class Program { + + private string center_text(string $word){ + int $tot_width = 30; + char $symbol = '-'; + int $middle = (int) round($tot_width/2); + int $length_word = strlen($word); + int $middle_word = (int) round($length_word / 2); + int $last_position = $middle + $middle_word; + int $number_of_spaces = $middle - $middle_word; + string $result = sprintf("%'{$symbol}{$last_position}s", $word); + for(int $i = 0; $i < $number_of_spaces; $i++) { + $result += "$symbol"; + } + return $result; + } + + void main() { + string $str = 'Example text'; + print($this->center_text($str)); + } + +} + + +/* Should output +---------------This is some text------------ +*/ diff --git a/tests/center_text.exp b/tests/center_text.exp new file mode 100644 index 0000000..5bce2f6 --- /dev/null +++ b/tests/center_text.exp @@ -0,0 +1 @@ +---------Example text--------- From 57c6b3483a8f5f062bb18e4682182c2957a8cf04 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 19:18:39 +0200 Subject: [PATCH 251/296] Test strtr() builtin function. --- tests/text_normalize.aer | 21 +++++++++++++++++++++ tests/text_normalize.exp | 1 + 2 files changed, 22 insertions(+) create mode 100644 tests/text_normalize.aer create mode 100644 tests/text_normalize.exp diff --git a/tests/text_normalize.aer b/tests/text_normalize.aer new file mode 100644 index 0000000..d5918bf --- /dev/null +++ b/tests/text_normalize.aer @@ -0,0 +1,21 @@ +class Program { + + string normalize(string $str) { + string[] $table = { + 'Š'=>'S', 'š'=>'s', 'Đ'=>'Dj', 'đ'=>'dj', 'Ž'=>'Z', 'ž'=>'z', 'Č'=>'C', 'č'=>'c', 'Ć'=>'C', 'ć'=>'c', + 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A', 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E', + 'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', + 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss', + 'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e', + 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', + 'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b', + 'ÿ'=>'y', 'Ŕ'=>'R', 'ŕ'=>'r' + }; + return strtr($str, $table); + } + + void main() { + var_dump($this->normalize("ÿĆ Welcome ÂëÑ Žöø Ŕ")); + } + +} diff --git a/tests/text_normalize.exp b/tests/text_normalize.exp new file mode 100644 index 0000000..d84bca6 --- /dev/null +++ b/tests/text_normalize.exp @@ -0,0 +1 @@ +string(20 'yC Welcome AeN Zoo R') From 493fcd0e9224175431f357624f43bfdc6bda9fd4 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 19:41:48 +0200 Subject: [PATCH 252/296] Test complex expressions one more time. --- tests/complex_expressions2.aer | 16 ++++++++++++++++ tests/complex_expressions2.exp | 12 ++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 tests/complex_expressions2.aer create mode 100644 tests/complex_expressions2.exp diff --git a/tests/complex_expressions2.aer b/tests/complex_expressions2.aer new file mode 100644 index 0000000..759e79c --- /dev/null +++ b/tests/complex_expressions2.aer @@ -0,0 +1,16 @@ +class Program { + + void test(int $a = (int(int $a, int $b, int $c){return $a+$b+$c;})(14, 10+2, 15), int $b = 0, int $c = 98) { + print($a + PHP_EOL); + print($b + PHP_EOL); + print($c + PHP_EOL); + } + + void main() { + $this->test(); + $this->test(512); + $this->test(1024, 32); + $this->test(1000, 2000, 4000); + } + +} diff --git a/tests/complex_expressions2.exp b/tests/complex_expressions2.exp new file mode 100644 index 0000000..856b5af --- /dev/null +++ b/tests/complex_expressions2.exp @@ -0,0 +1,12 @@ +41 +0 +98 +512 +0 +98 +1024 +32 +98 +1000 +2000 +4000 From 0c2b2c9df573b9476d1ef46570ceaa38ed46d9f0 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 19:54:05 +0200 Subject: [PATCH 253/296] Class instance as argument. --- tests/class_instance_arg.aer | 19 +++++++++++++++++++ tests/class_instance_arg.exp | 2 ++ 2 files changed, 21 insertions(+) create mode 100644 tests/class_instance_arg.aer create mode 100644 tests/class_instance_arg.exp diff --git a/tests/class_instance_arg.aer b/tests/class_instance_arg.aer new file mode 100644 index 0000000..fea973e --- /dev/null +++ b/tests/class_instance_arg.aer @@ -0,0 +1,19 @@ +class Test1 { +} + +class Test2 extends Test1 { +} + +class Program { + object $t; + + void test(Test1 $t = new Test2) { + $this->t = $t; + var_dump($this->t); + } + + void main() { + $this->test(); + } + +} diff --git a/tests/class_instance_arg.exp b/tests/class_instance_arg.exp new file mode 100644 index 0000000..08b5db2 --- /dev/null +++ b/tests/class_instance_arg.exp @@ -0,0 +1,2 @@ +object(Test2) { + } From 725b60cb8878b1e0246543598dfc2189b69b87e8 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 20:01:17 +0200 Subject: [PATCH 254/296] Check switch block. --- tests/switch_block.aer | 20 ++++++++++++++++++++ tests/switch_block.exp | 2 ++ 2 files changed, 22 insertions(+) create mode 100644 tests/switch_block.aer create mode 100644 tests/switch_block.exp diff --git a/tests/switch_block.aer b/tests/switch_block.aer new file mode 100644 index 0000000..e009a20 --- /dev/null +++ b/tests/switch_block.aer @@ -0,0 +1,20 @@ +class Program { + + void main() { + int $a = 1; + switch($a) { + case 0: + print("very bad\n"); + break; + case 1: + print("very good\n"); + case 2: + print("good\n"); + break; + default: + print("bad"); + break; + } + } + +} diff --git a/tests/switch_block.exp b/tests/switch_block.exp new file mode 100644 index 0000000..206cec8 --- /dev/null +++ b/tests/switch_block.exp @@ -0,0 +1,2 @@ +very good +good From 9c426b20ccef01135f6c26009d31cc03f576f937 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 10 Apr 2019 20:22:13 +0200 Subject: [PATCH 255/296] Factory design pattern test. --- tests/factory_objects.aer | 29 +++++++++++++++++++++++++++++ tests/factory_objects.exp | 2 ++ 2 files changed, 31 insertions(+) create mode 100644 tests/factory_objects.aer create mode 100644 tests/factory_objects.exp diff --git a/tests/factory_objects.aer b/tests/factory_objects.aer new file mode 100644 index 0000000..c0a1c86 --- /dev/null +++ b/tests/factory_objects.aer @@ -0,0 +1,29 @@ +class Circle { + void draw() { + print("Circle\n"); + } +} + +class Square { + void draw() { + print("Square\n"); + } +} + +class Program { + + object ShapeFactoryMethod(string $shape) { + switch ($shape) { + case "Circle": + return new Circle(); + case "Square": + return new Square(); + } + } + + void main() { + $this->ShapeFactoryMethod("Circle")->draw(); + $this->ShapeFactoryMethod("Square")->draw(); + } + +} diff --git a/tests/factory_objects.exp b/tests/factory_objects.exp new file mode 100644 index 0000000..83a280e --- /dev/null +++ b/tests/factory_objects.exp @@ -0,0 +1,2 @@ +Circle +Square From 4eaf6a71179ef079f481c7276adb8dab8b1e8712 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 11 Apr 2019 06:25:20 +0200 Subject: [PATCH 256/296] AerScript is strict type hinting language, thus OP_TEQ & OP_TNE are not needed here. --- engine/parser.c | 2 -- engine/vm.c | 72 ------------------------------------------- include/ph7int.h | 4 --- tests/luhn_verify.aer | 2 +- 4 files changed, 1 insertion(+), 79 deletions(-) diff --git a/engine/parser.c b/engine/parser.c index ef69bcd..b6e8aac 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -205,8 +205,6 @@ static const ph7_expr_op aOpTable[] = { /* Precedence 11,non-associative */ { {"==", sizeof(char) * 2}, EXPR_OP_EQ, 11, EXPR_OP_NON_ASSOC, PH7_OP_EQ}, { {"!=", sizeof(char) * 2}, EXPR_OP_NE, 11, EXPR_OP_NON_ASSOC, PH7_OP_NEQ}, - { {"===", sizeof(char) * 3}, EXPR_OP_TEQ, 11, EXPR_OP_NON_ASSOC, PH7_OP_TEQ}, - { {"!==", sizeof(char) * 3}, EXPR_OP_TNE, 11, EXPR_OP_NON_ASSOC, PH7_OP_TNE}, /* Precedence 12,left-associative */ { {"&", sizeof(char)}, EXPR_OP_BAND, 12, EXPR_OP_ASSOC_LEFT, PH7_OP_BAND}, /* Binary operators */ diff --git a/engine/vm.c b/engine/vm.c index e782d6f..1ba3b26 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -3717,72 +3717,6 @@ static sxi32 VmByteCodeExec( } break; } - /* OP_TEQ P1 P2 * - * - * Pop the top two elements from the stack. If they have the same type and are equal - * then jump to instruction P2. Otherwise, continue to the next instruction. - * If P2 is zero, do not jump. Instead, push a boolean 1 (TRUE) onto the - * stack if the jump would have been taken, or a 0 (FALSE) if not. - */ - case PH7_OP_TEQ: { - ph7_value *pNos = &pTos[-1]; - /* Perform the comparison and act accordingly */ -#ifdef UNTRUST - if(pNos < pStack) { - goto Abort; - } -#endif - rc = PH7_MemObjCmp(pNos, pTos, TRUE, 0) == 0; - VmPopOperand(&pTos, 1); - if(!pInstr->iP2) { - /* Push comparison result without taking the jump */ - PH7_MemObjRelease(pTos); - pTos->x.iVal = rc; - /* Invalidate any prior representation */ - MemObjSetType(pTos, MEMOBJ_BOOL); - } else { - if(rc) { - /* Jump to the desired location */ - pc = pInstr->iP2 - 1; - VmPopOperand(&pTos, 1); - } - } - break; - } - /* OP_TNE P1 P2 * - * - * Pop the top two elements from the stack.If they are not equal an they are not - * of the same type, then jump to instruction P2. Otherwise, continue to the next - * instruction. - * If P2 is zero, do not jump. Instead, push a boolean 1 (TRUE) onto the - * stack if the jump would have been taken, or a 0 (FALSE) if not. - * - */ - case PH7_OP_TNE: { - ph7_value *pNos = &pTos[-1]; - /* Perform the comparison and act accordingly */ -#ifdef UNTRUST - if(pNos < pStack) { - goto Abort; - } -#endif - rc = PH7_MemObjCmp(pNos, pTos, TRUE, 0) != 0; - VmPopOperand(&pTos, 1); - if(!pInstr->iP2) { - /* Push comparison result without taking the jump */ - PH7_MemObjRelease(pTos); - pTos->x.iVal = rc; - /* Invalidate any prior representation */ - MemObjSetType(pTos, MEMOBJ_BOOL); - } else { - if(rc) { - /* Jump to the desired location */ - pc = pInstr->iP2 - 1; - VmPopOperand(&pTos, 1); - } - } - break; - } /* OP_LT P1 P2 P3 * * Pop the top two elements from the stack. If the second element (the top of stack) @@ -5499,12 +5433,6 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_NEQ: zOp = "NEQ"; break; - case PH7_OP_TEQ: - zOp = "TEQ"; - break; - case PH7_OP_TNE: - zOp = "TNE"; - break; case PH7_OP_BAND: zOp = "BITAND"; break; diff --git a/include/ph7int.h b/include/ph7int.h index 269bf8a..0ae77a0 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1419,8 +1419,6 @@ enum ph7_vm_op { PH7_OP_GE, /* Greater or equal '>=' */ PH7_OP_EQ, /* Equal '==' */ PH7_OP_NEQ, /* Not equal '!=' */ - PH7_OP_TEQ, /* Type equal '===' */ - PH7_OP_TNE, /* Type not equal '!==' */ PH7_OP_BAND, /* Bitwise and '&' */ PH7_OP_BXOR, /* Bitwise xor '^' */ PH7_OP_BOR, /* Bitwise or '|' */ @@ -1498,8 +1496,6 @@ enum ph7_expr_id { EXPR_OP_GE, /* Greater equal */ EXPR_OP_EQ, /* Equal == */ EXPR_OP_NE, /* Not equal != <> */ - EXPR_OP_TEQ, /* Type equal === */ - EXPR_OP_TNE, /* Type not equal !== */ EXPR_OP_BAND, /* Bitwise and '&' */ EXPR_OP_REF, /* Reference operator '&' */ EXPR_OP_XOR, /* bitwise xor '^' */ diff --git a/tests/luhn_verify.aer b/tests/luhn_verify.aer index 9dfe02b..861d927 100644 --- a/tests/luhn_verify.aer +++ b/tests/luhn_verify.aer @@ -19,7 +19,7 @@ class Luhn { for(int $i = 0; $i < $len; $i++) { $sum += $i & 1 ? $revNumber[$i] * 2 : $revNumber[$i]; } - return array_sum(str_split($sum)) % 10 === 0; + return array_sum(str_split($sum)) % 10 == 0; } } From 31f48b234bdaa3cbd72e812c3cf54ad8a12da71c Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 11 Apr 2019 06:25:48 +0200 Subject: [PATCH 257/296] This is already fixed. --- TODO | 5 ----- 1 file changed, 5 deletions(-) diff --git a/TODO b/TODO index db9b8e0..31d661c 100644 --- a/TODO +++ b/TODO @@ -8,8 +8,3 @@ Below list contains things that should be changed/fixed/implemented. 2. All builtin functions should be reworked. Actually they can return any value, sometimes of different type than declared. This causes errors during script execution. - -3. Callback variable type is broken. - * Builtin functions expect a string or hashmap instead of callback, thus closures are not executed at all. - * Callback takes a string with function name or closure definition. How to call other methods? - * Class attribute of callback type cannot be called directly. From 5cc803d07c50ff92d9556472a19504d822499e79 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 11 Apr 2019 08:58:54 +0200 Subject: [PATCH 258/296] Another closure test comes in. --- tests/closure_test.aer | 36 ++++++++++++++++++++++++++++++++++++ tests/closure_test.exp | 3 +++ 2 files changed, 39 insertions(+) create mode 100644 tests/closure_test.aer create mode 100644 tests/closure_test.exp diff --git a/tests/closure_test.aer b/tests/closure_test.aer new file mode 100644 index 0000000..34886da --- /dev/null +++ b/tests/closure_test.aer @@ -0,0 +1,36 @@ +class Operations { + + public callback ops(int $x, int $y, string $op){ + switch($op) { + case 'ADD': + return int() using ($x, $y) { + return $x + $y; + }; + break; + case 'SUB': + return int() using ($x, $y) { + return $x - $y; + }; + break; + default: + return string() { + return 'Operation is not supported by class.'; + }; + } + } +} + +class Program { + + void main() { + callback $fn; + object $op = new Operations(); + $fn = $op->ops(6, 7, 'ADD'); + print($fn() + "\n"); + $fn = $op->ops(6, 2, 'SUB'); + print($fn() + "\n"); + $fn = $op->ops(6, 7, 'MUL'); + print($fn() + "\n"); + } + +} diff --git a/tests/closure_test.exp b/tests/closure_test.exp new file mode 100644 index 0000000..3ca1c19 --- /dev/null +++ b/tests/closure_test.exp @@ -0,0 +1,3 @@ +13 +4 +Operation is not supported by class. From aae526b1d4abbbd9cfcf54fe7954d3726b1208b9 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 11 Apr 2019 09:10:03 +0200 Subject: [PATCH 259/296] Closure as filter. --- tests/anon_filter.aer | 28 ++++++++++++++++++++++++++++ tests/anon_filter.exp | 8 ++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/anon_filter.aer create mode 100644 tests/anon_filter.exp diff --git a/tests/anon_filter.aer b/tests/anon_filter.aer new file mode 100644 index 0000000..88c529d --- /dev/null +++ b/tests/anon_filter.aer @@ -0,0 +1,28 @@ +class Program { + private callback $condition = bool(int $x) { return ($x > 100); }; + private int[] $numbers = {34, 56, 22, 1, 5, 67, 897, 123, 55, 101}; + + int[] filter(callback $condition, int[] $numbers) { + int $len = sizeof($numbers); + int[] $filtered; + for(int $i = 0; $i < $len; $i++) { + if($condition($numbers[$i])) { + $filtered[] = $numbers[$i]; + } + } + return $filtered; + } + + void main() { + int[] $filtered = $this->filter($this->condition, $this->numbers); + var_dump($filtered); + } + +} + + +/* + * Should output + +Array ( [0] => 897 [1] => 123 ) +*/ diff --git a/tests/anon_filter.exp b/tests/anon_filter.exp new file mode 100644 index 0000000..9e58c8a --- /dev/null +++ b/tests/anon_filter.exp @@ -0,0 +1,8 @@ +array(int, 3) { + [0] => + int(897) + [1] => + int(123) + [2] => + int(101) + } From cdc0dade2a7092374d6ac7f0bd3c9a788585df35 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 11 Apr 2019 11:33:00 +0200 Subject: [PATCH 260/296] Allow to store a character in string variable. --- engine/memobj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/memobj.c b/engine/memobj.c index 3b09500..4877815 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -382,6 +382,8 @@ PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { return SXRET_OK; } else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_INT)) { return SXRET_OK; + } else if((nType & MEMOBJ_STRING) && (pObj->iFlags & MEMOBJ_CHAR)) { + return SXRET_OK; } else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_STRING)) { int len = SyBlobLength(&pObj->sBlob); if(len == 0 || len == 1) { From ee0d189f0a0a9d1fd495913c189257909d2901e1 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 11 Apr 2019 11:37:07 +0200 Subject: [PATCH 261/296] Add comments. --- engine/memobj.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/engine/memobj.c b/engine/memobj.c index 4877815..78b04c7 100644 --- a/engine/memobj.c +++ b/engine/memobj.c @@ -377,19 +377,25 @@ static ph7_real MemObjCharValue(ph7_value *pObj) { PH7_PRIVATE sxi32 PH7_CheckVarCompat(ph7_value *pObj, int nType) { if(((nType & MEMOBJ_HASHMAP) == 0) && ((pObj->iFlags & MEMOBJ_HASHMAP) == 0)) { if(pObj->iFlags & MEMOBJ_NULL) { + /* Always allow to store a NULL */ return SXRET_OK; } else if((nType & MEMOBJ_REAL) && (pObj->iFlags & MEMOBJ_INT)) { + /* Allow to store INT to FLOAT variable */ return SXRET_OK; } else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_INT)) { + /* Allow to store INT to CHAR variable */ return SXRET_OK; } else if((nType & MEMOBJ_STRING) && (pObj->iFlags & MEMOBJ_CHAR)) { + /* Allow to store CHAR to STRING variable */ return SXRET_OK; } else if((nType & MEMOBJ_CHAR) && (pObj->iFlags & MEMOBJ_STRING)) { + /* Allow to store STRING to CHAR variable (if not too long) */ int len = SyBlobLength(&pObj->sBlob); if(len == 0 || len == 1) { return SXRET_OK; } } else if((nType & MEMOBJ_CALL) && (pObj->iFlags & MEMOBJ_STRING)) { + /* Allow to store STRING to CALLBACK variable */ return SXRET_OK; } } From a8a1a2cd5165b7fb663d20c22526b3128ae4e791 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 11 Apr 2019 13:28:47 +0200 Subject: [PATCH 262/296] Fix variable declaration in loops. --- engine/compiler.c | 14 ++++++++++---- engine/vm.c | 5 +++-- include/compiler.h | 1 + 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 0190b05..e331cf5 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -1896,7 +1896,7 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) { pGen->pEnd = pEnd; sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData)); if(nKey & PH7_KEYWORD_TYPEDEF) { - PH7_CompileVar(&(*pGen)); + PH7_GenStateCompileVar(&(*pGen), 0); } /* Compile initialization expressions if available */ rc = PH7_CompileExpr(&(*pGen), 0, 0); @@ -2445,10 +2445,16 @@ static sxi32 PH7_CompileHalt(ph7_gen_state *pGen) { } /* * Compile the var statement. - * Symisc Extension: - * var statement can be used outside of a class definition. */ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { + sxi32 rc; + rc = PH7_GenCompileVar(pGen, 1); + return rc; +} +/* + * Compile the var statement. + */ +static sxi32 PH7_GenStateCompileVar(ph7_gen_state *pGen, sxbool bStrict) { sxu32 nLine = pGen->pIn->nLine; sxbool bStatic = FALSE; ph7_vm_func_static_var sStatic; @@ -2559,7 +2565,7 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { } void *p3 = (void *) zDup; /* Emit OP_LOAD instruction */ - PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_LOAD, 0, nType, p3, 0); + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_LOAD, bStrict, nType, p3, 0); /* Check if we have an expression to compile */ if(pGen->pIn < pGen->pEnd && (pGen->pIn[2].nType & PH7_TK_EQUAL)) { /* Compile the expression */ diff --git a/engine/vm.c b/engine/vm.c index 1ba3b26..0d9d17f 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2402,10 +2402,11 @@ static sxi32 VmByteCodeExec( break; } /* - * LOAD: * P2 P3 + * LOAD: P1 P2 P3 * * Load a variable where it's name is taken from the top of the stack or * from the P3 operand. If P2 is set, it will create a new variable. + * If P1 is set, it will allow variable redeclaration. */ case PH7_OP_LOAD: { ph7_value *pObj; @@ -2430,7 +2431,7 @@ static sxi32 VmByteCodeExec( /* Extract the requested memory object */ pObj = VmExtractMemObj(&(*pVm), &sName, pInstr->p3 ? FALSE : TRUE, FALSE); if(pInstr->iP2) { - if(pObj) { + if(pObj && pInstr->iP1) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Redeclaration of ‘$%z’ variable", &sName); } diff --git a/include/compiler.h b/include/compiler.h index 099d227..2bcdfd4 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -119,6 +119,7 @@ static sxi32 PH7_CompileReturn(ph7_gen_state *pGen); static sxi32 PH7_CompileHalt(ph7_gen_state *pGen); static sxi32 PH7_CompileStatic(ph7_gen_state *pGen); static sxi32 PH7_CompileVar(ph7_gen_state *pGen); +static sxi32 PH7_GenStateCompileVar(ph7_gen_state *pGen, sxbool bStrict); static sxi32 PH7_CompileNamespace(ph7_gen_state *pGen); static sxi32 PH7_CompileUsing(ph7_gen_state *pGen); static sxi32 PH7_GenStateProcessArgValue(ph7_gen_state *pGen, ph7_vm_func_arg *pArg, SyToken *pIn, SyToken *pEnd); From b302e8c2b2ba8e7971ee772de743d01c656625b1 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 11 Apr 2019 13:29:44 +0200 Subject: [PATCH 263/296] Test static variables. --- tests/static_var.aer | 24 ++++++++++++++++++++++++ tests/static_var.exp | 26 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/static_var.aer create mode 100644 tests/static_var.exp diff --git a/tests/static_var.aer b/tests/static_var.aer new file mode 100644 index 0000000..b2b552c --- /dev/null +++ b/tests/static_var.aer @@ -0,0 +1,24 @@ +class Program { + + string cycle(char $a, char $b, int $i = 0) { + static char[] $switches; + if($switches[$i]) + $switches[$i] = !$switches[$i]; + else + !($switches[$i] = true); + return ($switches[$i]) ? $a : $b; + } + + void main() { + for(int $i = 1; $i < 3; $i++) { + print($i + $this->cycle('a', 'b') + PHP_EOL); + for(int $j = 1; $j < 5; $j++) { + print(' ' + $j + $this->cycle('a', 'b', 1) + PHP_EOL); + for(int $k = 1; $k < 3; $k++) { + print(' ' + $k + $this->cycle('c', 'd', 2) + PHP_EOL); + } + } + } + } + +} diff --git a/tests/static_var.exp b/tests/static_var.exp new file mode 100644 index 0000000..7a256fb --- /dev/null +++ b/tests/static_var.exp @@ -0,0 +1,26 @@ +1a + 1a + 1c + 2d + 2b + 1c + 2d + 3a + 1c + 2d + 4b + 1c + 2d +2b + 1a + 1c + 2d + 2b + 1c + 2d + 3a + 1c + 2d + 4b + 1c + 2d From 89d5158d7e0a085e56e7766ce3aa7f60c4f037c0 Mon Sep 17 00:00:00 2001 From: belliash Date: Thu, 11 Apr 2019 13:31:17 +0200 Subject: [PATCH 264/296] Fix build. --- engine/compiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index e331cf5..2609c8f 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2448,7 +2448,7 @@ static sxi32 PH7_CompileHalt(ph7_gen_state *pGen) { */ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { sxi32 rc; - rc = PH7_GenCompileVar(pGen, 1); + rc = PH7_GenStateCompileVar(pGen, 1); return rc; } /* From 98898c16c5d9f99867110a4738d7cff599274083 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 13 Apr 2019 09:09:25 +0200 Subject: [PATCH 265/296] Builtin library will be reworked later. Out of scope. --- TODO | 7 ------- 1 file changed, 7 deletions(-) diff --git a/TODO b/TODO index 31d661c..741d909 100644 --- a/TODO +++ b/TODO @@ -1,10 +1,3 @@ TODO list for typehinting branch. Below list contains things that should be changed/fixed/implemented. - -1. The debug_backtrace() does not show information about arrays type. - * This is caused by ph7_context_new_array() creating a generic array w/o data type set. - Most probably more builtin functions returning an array are affected. - -2. All builtin functions should be reworked. Actually they can return any value, sometimes of different type than declared. - This causes errors during script execution. From e3ad3eb84b130d8c5ccad981c836374de2d0ec9d Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 13 Apr 2019 14:32:43 +0200 Subject: [PATCH 266/296] Another bug found that needs to be fixed before merge to master branch. --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index 741d909..2e9fe7b 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ TODO list for typehinting branch. Below list contains things that should be changed/fixed/implemented. +1. Variable declaration inside a loop leads to redeclaration error. \ No newline at end of file From aea0d1a5ecb4b0a17c634bd5f5b2bd296435cb0b Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 13 Apr 2019 14:35:27 +0200 Subject: [PATCH 267/296] Workaround applied to make test working. --- tests/static_var.aer | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/static_var.aer b/tests/static_var.aer index b2b552c..3c6817e 100644 --- a/tests/static_var.aer +++ b/tests/static_var.aer @@ -10,11 +10,12 @@ class Program { } void main() { - for(int $i = 1; $i < 3; $i++) { + int $i, $j, $k; + for($i = 1; $i < 3; $i++) { print($i + $this->cycle('a', 'b') + PHP_EOL); - for(int $j = 1; $j < 5; $j++) { + for($j = 1; $j < 5; $j++) { print(' ' + $j + $this->cycle('a', 'b', 1) + PHP_EOL); - for(int $k = 1; $k < 3; $k++) { + for($k = 1; $k < 3; $k++) { print(' ' + $k + $this->cycle('c', 'd', 2) + PHP_EOL); } } From 583f43e1f7e9e05f2418d6b8ef8e36f85c40c9e4 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 13 Apr 2019 14:37:04 +0200 Subject: [PATCH 268/296] Convert carriage return and line feed to line feed (UNIX line ending). --- tests/anon_filter.aer | 56 ++++++++++++++++---------------- tests/center_text.aer | 6 ++-- tests/closure_test.aer | 72 +++++++++++++++++++++--------------------- tests/static_var.aer | 48 ++++++++++++++-------------- 4 files changed, 91 insertions(+), 91 deletions(-) diff --git a/tests/anon_filter.aer b/tests/anon_filter.aer index 88c529d..bf94872 100644 --- a/tests/anon_filter.aer +++ b/tests/anon_filter.aer @@ -1,28 +1,28 @@ -class Program { - private callback $condition = bool(int $x) { return ($x > 100); }; - private int[] $numbers = {34, 56, 22, 1, 5, 67, 897, 123, 55, 101}; - - int[] filter(callback $condition, int[] $numbers) { - int $len = sizeof($numbers); - int[] $filtered; - for(int $i = 0; $i < $len; $i++) { - if($condition($numbers[$i])) { - $filtered[] = $numbers[$i]; - } - } - return $filtered; - } - - void main() { - int[] $filtered = $this->filter($this->condition, $this->numbers); - var_dump($filtered); - } - -} - - -/* - * Should output - -Array ( [0] => 897 [1] => 123 ) -*/ +class Program { + private callback $condition = bool(int $x) { return ($x > 100); }; + private int[] $numbers = {34, 56, 22, 1, 5, 67, 897, 123, 55, 101}; + + int[] filter(callback $condition, int[] $numbers) { + int $len = sizeof($numbers); + int[] $filtered; + for(int $i = 0; $i < $len; $i++) { + if($condition($numbers[$i])) { + $filtered[] = $numbers[$i]; + } + } + return $filtered; + } + + void main() { + int[] $filtered = $this->filter($this->condition, $this->numbers); + var_dump($filtered); + } + +} + + +/* + * Should output + +Array ( [0] => 897 [1] => 123 ) +*/ diff --git a/tests/center_text.aer b/tests/center_text.aer index 636431b..93267a2 100644 --- a/tests/center_text.aer +++ b/tests/center_text.aer @@ -23,6 +23,6 @@ class Program { } -/* Should output ----------------This is some text------------ -*/ +/* Should output +---------------This is some text------------ +*/ diff --git a/tests/closure_test.aer b/tests/closure_test.aer index 34886da..6f6a470 100644 --- a/tests/closure_test.aer +++ b/tests/closure_test.aer @@ -1,36 +1,36 @@ -class Operations { - - public callback ops(int $x, int $y, string $op){ - switch($op) { - case 'ADD': - return int() using ($x, $y) { - return $x + $y; - }; - break; - case 'SUB': - return int() using ($x, $y) { - return $x - $y; - }; - break; - default: - return string() { - return 'Operation is not supported by class.'; - }; - } - } -} - -class Program { - - void main() { - callback $fn; - object $op = new Operations(); - $fn = $op->ops(6, 7, 'ADD'); - print($fn() + "\n"); - $fn = $op->ops(6, 2, 'SUB'); - print($fn() + "\n"); - $fn = $op->ops(6, 7, 'MUL'); - print($fn() + "\n"); - } - -} +class Operations { + + public callback ops(int $x, int $y, string $op){ + switch($op) { + case 'ADD': + return int() using ($x, $y) { + return $x + $y; + }; + break; + case 'SUB': + return int() using ($x, $y) { + return $x - $y; + }; + break; + default: + return string() { + return 'Operation is not supported by class.'; + }; + } + } +} + +class Program { + + void main() { + callback $fn; + object $op = new Operations(); + $fn = $op->ops(6, 7, 'ADD'); + print($fn() + "\n"); + $fn = $op->ops(6, 2, 'SUB'); + print($fn() + "\n"); + $fn = $op->ops(6, 7, 'MUL'); + print($fn() + "\n"); + } + +} diff --git a/tests/static_var.aer b/tests/static_var.aer index 3c6817e..7d4a519 100644 --- a/tests/static_var.aer +++ b/tests/static_var.aer @@ -1,25 +1,25 @@ -class Program { - - string cycle(char $a, char $b, int $i = 0) { - static char[] $switches; - if($switches[$i]) - $switches[$i] = !$switches[$i]; - else - !($switches[$i] = true); - return ($switches[$i]) ? $a : $b; - } - - void main() { +class Program { + + string cycle(char $a, char $b, int $i = 0) { + static char[] $switches; + if($switches[$i]) + $switches[$i] = !$switches[$i]; + else + !($switches[$i] = true); + return ($switches[$i]) ? $a : $b; + } + + void main() { int $i, $j, $k; - for($i = 1; $i < 3; $i++) { - print($i + $this->cycle('a', 'b') + PHP_EOL); - for($j = 1; $j < 5; $j++) { - print(' ' + $j + $this->cycle('a', 'b', 1) + PHP_EOL); - for($k = 1; $k < 3; $k++) { - print(' ' + $k + $this->cycle('c', 'd', 2) + PHP_EOL); - } - } - } - } - -} + for($i = 1; $i < 3; $i++) { + print($i + $this->cycle('a', 'b') + PHP_EOL); + for($j = 1; $j < 5; $j++) { + print(' ' + $j + $this->cycle('a', 'b', 1) + PHP_EOL); + for($k = 1; $k < 3; $k++) { + print(' ' + $k + $this->cycle('c', 'd', 2) + PHP_EOL); + } + } + } + } + +} From c51b3dfa8a92919d8fada1c1333ccc1c96b9a7d7 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 13 Apr 2019 14:39:57 +0200 Subject: [PATCH 269/296] Revert 89d5158d7e and a8a1a2cd51. Fix should be based on VM frames. --- engine/compiler.c | 12 ++---------- engine/vm.c | 5 ++--- include/compiler.h | 1 - 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 2609c8f..5bfa1ff 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -1896,7 +1896,7 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) { pGen->pEnd = pEnd; sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData)); if(nKey & PH7_KEYWORD_TYPEDEF) { - PH7_GenStateCompileVar(&(*pGen), 0); + PH7_CompileVar(&(*pGen)); } /* Compile initialization expressions if available */ rc = PH7_CompileExpr(&(*pGen), 0, 0); @@ -2447,14 +2447,6 @@ static sxi32 PH7_CompileHalt(ph7_gen_state *pGen) { * Compile the var statement. */ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { - sxi32 rc; - rc = PH7_GenStateCompileVar(pGen, 1); - return rc; -} -/* - * Compile the var statement. - */ -static sxi32 PH7_GenStateCompileVar(ph7_gen_state *pGen, sxbool bStrict) { sxu32 nLine = pGen->pIn->nLine; sxbool bStatic = FALSE; ph7_vm_func_static_var sStatic; @@ -2565,7 +2557,7 @@ static sxi32 PH7_GenStateCompileVar(ph7_gen_state *pGen, sxbool bStrict) { } void *p3 = (void *) zDup; /* Emit OP_LOAD instruction */ - PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_LOAD, bStrict, nType, p3, 0); + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_LOAD, 0, nType, p3, 0); /* Check if we have an expression to compile */ if(pGen->pIn < pGen->pEnd && (pGen->pIn[2].nType & PH7_TK_EQUAL)) { /* Compile the expression */ diff --git a/engine/vm.c b/engine/vm.c index 0d9d17f..1ba3b26 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2402,11 +2402,10 @@ static sxi32 VmByteCodeExec( break; } /* - * LOAD: P1 P2 P3 + * LOAD: * P2 P3 * * Load a variable where it's name is taken from the top of the stack or * from the P3 operand. If P2 is set, it will create a new variable. - * If P1 is set, it will allow variable redeclaration. */ case PH7_OP_LOAD: { ph7_value *pObj; @@ -2431,7 +2430,7 @@ static sxi32 VmByteCodeExec( /* Extract the requested memory object */ pObj = VmExtractMemObj(&(*pVm), &sName, pInstr->p3 ? FALSE : TRUE, FALSE); if(pInstr->iP2) { - if(pObj && pInstr->iP1) { + if(pObj) { PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Redeclaration of ‘$%z’ variable", &sName); } diff --git a/include/compiler.h b/include/compiler.h index 2bcdfd4..099d227 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -119,7 +119,6 @@ static sxi32 PH7_CompileReturn(ph7_gen_state *pGen); static sxi32 PH7_CompileHalt(ph7_gen_state *pGen); static sxi32 PH7_CompileStatic(ph7_gen_state *pGen); static sxi32 PH7_CompileVar(ph7_gen_state *pGen); -static sxi32 PH7_GenStateCompileVar(ph7_gen_state *pGen, sxbool bStrict); static sxi32 PH7_CompileNamespace(ph7_gen_state *pGen); static sxi32 PH7_CompileUsing(ph7_gen_state *pGen); static sxi32 PH7_GenStateProcessArgValue(ph7_gen_state *pGen, ph7_vm_func_arg *pArg, SyToken *pIn, SyToken *pEnd); From 0f0fc01a96bc227bf76d2e71776ce9fab9e1fe6a Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 13 Apr 2019 20:21:47 +0200 Subject: [PATCH 270/296] We need to distinguish the loop frames. --- include/ph7int.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/ph7int.h b/include/ph7int.h index 0ae77a0..112a289 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1263,9 +1263,10 @@ struct VmFrame { sxu32 iExceptionJump; /* Exception jump destination */ }; #define VM_FRAME_ACTIVE 0x01 /* Active call frame */ -#define VM_FRAME_EXCEPTION 0x02 /* Special Exception frame */ -#define VM_FRAME_THROW 0x04 /* An exception was thrown */ -#define VM_FRAME_CATCH 0x08 /* Catch frame */ +#define VM_FRAME_LOOP 0x02 /* Active loop frame */ +#define VM_FRAME_EXCEPTION 0x04 /* Special Exception frame */ +#define VM_FRAME_THROW 0x08 /* An exception was thrown */ +#define VM_FRAME_CATCH 0x10 /* Catch frame */ /* * When a debug stacktrace is extracted from Virtual Machine, all information about * calls (file, line, class, method, arguments) are stored in this structure. From 9e06322b57cac8974c99fe8f97a7ffad729d49a2 Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 15 Apr 2019 17:04:44 +0200 Subject: [PATCH 271/296] Implement VmCreateMemObj(). --- engine/vm.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index 1ba3b26..02cf18a 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1331,6 +1331,58 @@ PH7_PRIVATE ph7_value *PH7_ReserveMemObj(ph7_vm *pVm) { pObj->nIdx = nIdx; return pObj; } +/* + * Creates a variable value in the top active VM frame. + * Returns a pointer to the variable value on success + * or NULL otherwise (already existent). + */ +static ph7_value *VmCreateMemObj( + ph7_vm *pVm, /* Target VM */ + const SyString *pName, /* Variable name */ + sxbool bDup /* True to duplicate variable name */ +) { + sxu32 nIdx; + sxi32 rc; + SyHashEntry *pEntry; + /* Query the top active frame */ + pEntry = SyHashGet(&pVm->pFrame->hVar, (const void *)pName->zString, pName->nByte); + if(pEntry) { + /* Variable already exists */ + return 0; + } + ph7_value *pObj; + VmSlot sLocal; + char *zName = (char *)pName->zString; + pObj = PH7_ReserveMemObj(&(*pVm)); + if(pObj == 0) { + return 0; + } + nIdx = pObj->nIdx; + if(bDup) { + /* Duplicate name */ + zName = SyMemBackendStrDup(&pVm->sAllocator, pName->zString, pName->nByte); + if(zName == 0) { + return 0; + } + } + /* Link to the top active VM frame */ + rc = SyHashInsert(&pVm->pFrame->hVar, zName, pName->nByte, SX_INT_TO_PTR(nIdx)); + if(rc != SXRET_OK) { + /* Return the slot to the free pool */ + sLocal.nIdx = nIdx; + sLocal.pUserData = 0; + SySetPut(&pVm->aFreeObj, (const void *)&sLocal); + return 0; + } + /* Register local variable */ + sLocal.nIdx = nIdx; + SySetPut(&pVm->pFrame->sLocal, (const void *)&sLocal); + /* Install in the reference table */ + PH7_VmRefObjInstall(&(*pVm), nIdx, SyHashLastEntry(&pVm->pFrame->hVar), 0, 0); + /* Save object index */ + pObj->nIdx = nIdx; + return pObj; +} /* * Extract a variable value from the top active VM frame. * Return a pointer to the variable value on success. From 94e06f3d3a2899b22c2930bf0860e65f80e0512b Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 15 Apr 2019 17:14:14 +0200 Subject: [PATCH 272/296] Do not duplicate the code; make a use of VmCreateMemObj(). --- engine/vm.c | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 02cf18a..fb625be 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1420,8 +1420,6 @@ static ph7_value *VmExtractMemObj( /* Query the top active frame */ pEntry = SyHashGet(&pFrame->hVar, (const void *)pName->zString, pName->nByte); if(pEntry == 0) { - char *zName = (char *)pName->zString; - VmSlot sLocal; if(!bCreate) { /* Do not create the variable, return NULL instead */ return 0; @@ -1429,34 +1427,7 @@ static ph7_value *VmExtractMemObj( /* No such variable, automatically create a new one and install * it in the current frame. */ - pObj = PH7_ReserveMemObj(&(*pVm)); - if(pObj == 0) { - return 0; - } - nIdx = pObj->nIdx; - if(bDup) { - /* Duplicate name */ - zName = SyMemBackendStrDup(&pVm->sAllocator, pName->zString, pName->nByte); - if(zName == 0) { - return 0; - } - } - /* Link to the top active VM frame */ - rc = SyHashInsert(&pFrame->hVar, zName, pName->nByte, SX_INT_TO_PTR(nIdx)); - if(rc != SXRET_OK) { - /* Return the slot to the free pool */ - sLocal.nIdx = nIdx; - sLocal.pUserData = 0; - SySetPut(&pVm->aFreeObj, (const void *)&sLocal); - return 0; - } - /* Register local variable */ - sLocal.nIdx = nIdx; - SySetPut(&pFrame->sLocal, (const void *)&sLocal); - /* Install in the reference table */ - PH7_VmRefObjInstall(&(*pVm), nIdx, SyHashLastEntry(&pFrame->hVar), 0, 0); - /* Save object index */ - pObj->nIdx = nIdx; + pObj = VmCreateMemObj(pVm, pName, bDup); } else { /* Extract variable contents */ nIdx = (sxu32)SX_PTR_TO_INT(pEntry->pUserData); From 661158d249ba0a54d065e48b15103997cc14a67e Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 15 Apr 2019 17:41:29 +0200 Subject: [PATCH 273/296] Simply throw memory error. --- engine/vm.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index fb625be..dc631ab 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1353,26 +1353,23 @@ static ph7_value *VmCreateMemObj( ph7_value *pObj; VmSlot sLocal; char *zName = (char *)pName->zString; + /* Reserve a memory object */ pObj = PH7_ReserveMemObj(&(*pVm)); if(pObj == 0) { - return 0; + PH7_VmMemoryError(&(*pVm)); } nIdx = pObj->nIdx; if(bDup) { /* Duplicate name */ zName = SyMemBackendStrDup(&pVm->sAllocator, pName->zString, pName->nByte); if(zName == 0) { - return 0; + PH7_VmMemoryError(&(*pVm)); } } /* Link to the top active VM frame */ rc = SyHashInsert(&pVm->pFrame->hVar, zName, pName->nByte, SX_INT_TO_PTR(nIdx)); if(rc != SXRET_OK) { - /* Return the slot to the free pool */ - sLocal.nIdx = nIdx; - sLocal.pUserData = 0; - SySetPut(&pVm->aFreeObj, (const void *)&sLocal); - return 0; + PH7_VmMemoryError(&(*pVm)); } /* Register local variable */ sLocal.nIdx = nIdx; From 1b248a17e7201460ddecc03f4fb24844ff05296c Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 15 Apr 2019 18:32:30 +0200 Subject: [PATCH 274/296] Query the top active as well as all loop frames. --- engine/vm.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index dc631ab..6a67477 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -1414,8 +1414,24 @@ static ph7_value *VmExtractMemObj( /* Check the superglobals table first */ pEntry = SyHashGet(&pVm->hSuper, (const void *)pName->zString, pName->nByte); if(pEntry == 0) { - /* Query the top active frame */ - pEntry = SyHashGet(&pFrame->hVar, (const void *)pName->zString, pName->nByte); + for(;;) { + /* Query the top active/loop frame(s) */ + pEntry = SyHashGet(&pFrame->hVar, (const void *)pName->zString, pName->nByte); + if(pEntry) { + /* Extract variable contents */ + nIdx = (sxu32)SX_PTR_TO_INT(pEntry->pUserData); + pObj = (ph7_value *)SySetAt(&pVm->aMemObj, nIdx); + if(bNullify && pObj) { + PH7_MemObjRelease(pObj); + } + break; + } + if(pFrame->iFlags & VM_FRAME_LOOP && pFrame->pParent) { + pFrame = pFrame->pParent; + } else { + break; + } + } if(pEntry == 0) { if(!bCreate) { /* Do not create the variable, return NULL instead */ @@ -1425,16 +1441,9 @@ static ph7_value *VmExtractMemObj( * it in the current frame. */ pObj = VmCreateMemObj(pVm, pName, bDup); - } else { - /* Extract variable contents */ - nIdx = (sxu32)SX_PTR_TO_INT(pEntry->pUserData); - pObj = (ph7_value *)SySetAt(&pVm->aMemObj, nIdx); - if(bNullify && pObj) { - PH7_MemObjRelease(pObj); - } } } else { - /* Superglobal */ + /* Extract from superglobal */ nIdx = (sxu32)SX_PTR_TO_INT(pEntry->pUserData); pObj = (ph7_value *)SySetAt(&pVm->aMemObj, nIdx); } From 517dffcbc153c846fcb5433683a9586af21bf6cb Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 15 Apr 2019 19:18:29 +0200 Subject: [PATCH 275/296] Separate VM instruction for variable declaration (OP_DECLARE). --- engine/compiler.c | 2 +- engine/vm.c | 36 ++++++++++++++++++++++++++++++++++++ include/ph7int.h | 1 + 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index 5bfa1ff..2b33b60 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2557,7 +2557,7 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { } void *p3 = (void *) zDup; /* Emit OP_LOAD instruction */ - PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_LOAD, 0, nType, p3, 0); + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DECLARE, 0, nType, p3, 0); /* Check if we have an expression to compile */ if(pGen->pIn < pGen->pEnd && (pGen->pIn[2].nType & PH7_TK_EQUAL)) { /* Compile the expression */ diff --git a/engine/vm.c b/engine/vm.c index 6a67477..02c553e 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2395,6 +2395,39 @@ static sxi32 VmByteCodeExec( break; } /* + * DECLARE: * P2 P3 + * + * Create a variable where it's name is taken from the top of the stack or + * from the P3 operand. It takes a variable type from P2 operand. + */ + case PH7_OP_DECLARE: { + ph7_value *pObj; + SyString sName; + SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3)); + /* Reserve a room for the target object */ + pTos++; + /* Create a new variable */ + pObj = VmCreateMemObj(&(*pVm), &sName, FALSE); + if(!pObj) { + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, + "Redeclaration of ‘$%z’ variable", &sName); + } + if(pInstr->iP2 & MEMOBJ_MIXED && (pInstr->iP2 & MEMOBJ_HASHMAP) == 0) { + pObj->iFlags = MEMOBJ_MIXED | MEMOBJ_VOID; + } else { + if(pInstr->iP2 & MEMOBJ_HASHMAP) { + ph7_hashmap *pMap; + pMap = PH7_NewHashmap(&(*pVm), 0, 0); + if(pMap == 0) { + PH7_VmMemoryError(&(*pVm)); + } + pObj->x.pOther = pMap; + } + MemObjSetType(pObj, pInstr->iP2); + } + pTos->nIdx = SXU32_HIGH; /* Mark as constant */ + break; + } /* * LOADC P1 P2 * * * Load a constant [i.e: PHP_EOL,PHP_OS,__TIME__,...] indexed at P2 in the constant pool. @@ -5369,6 +5402,9 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_HALT: zOp = "HALT"; break; + case PH7_OP_DECLARE: + zOp = "DECLARE"; + break; case PH7_OP_LOAD: zOp = "LOAD"; break; diff --git a/include/ph7int.h b/include/ph7int.h index 112a289..82272a6 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1389,6 +1389,7 @@ enum iErrCode { enum ph7_vm_op { PH7_OP_DONE = 1, /* Done */ PH7_OP_HALT, /* Halt */ + PH7_OP_DECLARE, /* Declare a variable */ PH7_OP_LOAD, /* Load memory object */ PH7_OP_LOADC, /* Load constant */ PH7_OP_LOAD_IDX, /* Load array entry */ From f9b518138eba3584f49e5362e2a4dbd4fc9200de Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 15 Apr 2019 19:44:49 +0200 Subject: [PATCH 276/296] Cleanup OP_LOAD instruction. --- engine/vm.c | 37 +++++-------------------------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git a/engine/vm.c b/engine/vm.c index 02c553e..9b26064 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2464,10 +2464,10 @@ static sxi32 VmByteCodeExec( break; } /* - * LOAD: * P2 P3 + * LOAD: * * P3 * * Load a variable where it's name is taken from the top of the stack or - * from the P3 operand. If P2 is set, it will create a new variable. + * from the P3 operand. */ case PH7_OP_LOAD: { ph7_value *pObj; @@ -2491,36 +2491,9 @@ static sxi32 VmByteCodeExec( } /* Extract the requested memory object */ pObj = VmExtractMemObj(&(*pVm), &sName, pInstr->p3 ? FALSE : TRUE, FALSE); - if(pInstr->iP2) { - if(pObj) { - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, - "Redeclaration of ‘$%z’ variable", &sName); - } - if(!pInstr->p3) { - PH7_MemObjRelease(pTos); - } else { - pObj = VmExtractMemObj(&(*pVm), &sName, FALSE, TRUE); - if(pInstr->iP2 & MEMOBJ_MIXED && (pInstr->iP2 & MEMOBJ_HASHMAP) == 0) { - pObj->iFlags = MEMOBJ_MIXED | MEMOBJ_VOID; - } else { - if(pInstr->iP2 & MEMOBJ_HASHMAP) { - ph7_hashmap *pMap; - pMap = PH7_NewHashmap(&(*pVm), 0, 0); - if(pMap == 0) { - PH7_VmMemoryError(&(*pVm)); - } - pObj->x.pOther = pMap; - } - MemObjSetType(pObj, pInstr->iP2); - } - } - pTos->nIdx = SXU32_HIGH; /* Mark as constant */ - break; - } else { - if(pObj == 0) { - /* Fatal error */ - PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Variable '$%z' undeclared (first use in this method/closure)", &sName); - } + if(pObj == 0) { + /* Fatal error */ + PH7_VmThrowError(&(*pVm), PH7_CTX_ERR, "Variable '$%z' undeclared (first use in this method/closure)", &sName); } /* Load variable contents */ PH7_MemObjLoad(pObj, pTos); From eb80dced3ee25cbf10d6c3df803618f760010e0c Mon Sep 17 00:00:00 2001 From: belliash Date: Mon, 15 Apr 2019 20:00:54 +0200 Subject: [PATCH 277/296] Correct comment. --- engine/compiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index 2b33b60..c079d45 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2556,7 +2556,7 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "Fatal, PH7 engine is running out of memory"); } void *p3 = (void *) zDup; - /* Emit OP_LOAD instruction */ + /* Emit OP_DECLARE instruction */ PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DECLARE, 0, nType, p3, 0); /* Check if we have an expression to compile */ if(pGen->pIn < pGen->pEnd && (pGen->pIn[2].nType & PH7_TK_EQUAL)) { From 89f19133d50f83ee216c49991d044e24de510afa Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 16 Apr 2019 08:14:16 +0200 Subject: [PATCH 278/296] Rename VM's jump instructions for better readability. --- engine/compiler.c | 24 ++++++++++++------------ engine/vm.c | 16 ++++++++-------- include/ph7int.h | 4 ++-- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index c079d45..0ea76c8 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -1688,9 +1688,9 @@ static sxi32 PH7_CompileWhile(ph7_gen_state *pGen) { pGen->pIn = &pEnd[1]; pGen->pEnd = pTmp; /* Emit the false jump */ - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JZ, 0, 0, 0, &nFalseJump); + PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMPZ, 0, 0, 0, &nFalseJump); /* Save the instruction index so we can fix it later when the jump destination is resolved */ - PH7_GenStateNewJumpFixup(pWhileBlock, PH7_OP_JZ, nFalseJump); + PH7_GenStateNewJumpFixup(pWhileBlock, PH7_OP_JMPZ, nFalseJump); /* Compile the loop body */ rc = PH7_CompileBlock(&(*pGen)); if(rc == SXERR_ABORT) { @@ -1820,7 +1820,7 @@ static sxi32 PH7_CompileDoWhile(ph7_gen_state *pGen) { pGen->pIn = &pEnd[1]; pGen->pEnd = pTmp; /* Emit the true jump to the beginning of the loop */ - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JNZ, 0, pDoBlock->nFirstInstr, 0, 0); + PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMPNZ, 0, pDoBlock->nFirstInstr, 0, 0); /* Fix all jumps now the destination is resolved */ PH7_GenStateFixJumps(pDoBlock, -1, PH7_VmInstrLength(pGen->pVm)); /* Release the loop block */ @@ -1933,9 +1933,9 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) { return SXERR_ABORT; } else if(rc != SXERR_EMPTY) { /* Emit the false jump */ - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JZ, 0, 0, 0, &nFalseJump); + PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMPZ, 0, 0, 0, &nFalseJump); /* Save the instruction index so we can fix it later when the jump destination is resolved */ - PH7_GenStateNewJumpFixup(pForBlock, PH7_OP_JZ, nFalseJump); + PH7_GenStateNewJumpFixup(pForBlock, PH7_OP_JMPZ, nFalseJump); } if((pGen->pIn->nType & PH7_TK_SEMI) == 0) { /* Syntax error */ @@ -2327,9 +2327,9 @@ static sxi32 PH7_CompileIf(ph7_gen_state *pGen) { return SXERR_ABORT; } /* Emit the false jump */ - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JZ, 0, 0, 0, &nJumpIdx); + PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMPZ, 0, 0, 0, &nJumpIdx); /* Save the instruction index so we can fix it later when the jump destination is resolved */ - PH7_GenStateNewJumpFixup(pCondBlock, PH7_OP_JZ, nJumpIdx); + PH7_GenStateNewJumpFixup(pCondBlock, PH7_OP_JMPZ, nJumpIdx); /* Compile the body */ rc = PH7_CompileBlock(&(*pGen)); if(rc == SXERR_ABORT) { @@ -2359,10 +2359,10 @@ static sxi32 PH7_CompileIf(ph7_gen_state *pGen) { /* Synchronize cursors */ pToken = pGen->pIn; /* Fix the false jump */ - PH7_GenStateFixJumps(pCondBlock, PH7_OP_JZ, PH7_VmInstrLength(pGen->pVm)); + PH7_GenStateFixJumps(pCondBlock, PH7_OP_JMPZ, PH7_VmInstrLength(pGen->pVm)); } /* For(;;) */ /* Fix the false jump */ - PH7_GenStateFixJumps(pCondBlock, PH7_OP_JZ, PH7_VmInstrLength(pGen->pVm)); + PH7_GenStateFixJumps(pCondBlock, PH7_OP_JMPZ, PH7_VmInstrLength(pGen->pVm)); if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD) && (SX_PTR_TO_INT(pGen->pIn->pUserData) & PH7_KEYWORD_ELSE)) { /* Compile the else block */ @@ -4922,7 +4922,7 @@ static sxi32 PH7_GenStateEmitExprCode( } nJz = nJmp = 0; /* cc -O6 warning */ /* Phase#2: Emit the false jump */ - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JZ, 0, 0, 0, &nJz); + PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMPZ, 0, 0, 0, &nJz); if(pNode->pLeft) { /* Phase#3: Compile the 'then' expression */ rc = PH7_GenStateEmitExprCode(&(*pGen), pNode->pLeft, iFlags); @@ -5018,10 +5018,10 @@ static sxi32 PH7_GenStateEmitExprCode( if(pNode->pRight) { if(iVmOp == PH7_OP_LAND) { /* Emit the false jump so we can short-circuit the logical and */ - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JZ, 1/* Keep the value on the stack */, 0, 0, &nJmpIdx); + PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMPZ, 1/* Keep the value on the stack */, 0, 0, &nJmpIdx); } else if(iVmOp == PH7_OP_LOR) { /* Emit the true jump so we can short-circuit the logical or*/ - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JNZ, 1/* Keep the value on the stack */, 0, 0, &nJmpIdx); + PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMPNZ, 1/* Keep the value on the stack */, 0, 0, &nJmpIdx); } else if(pNode->pOp->iPrec == 18 /* Combined binary operators [i.e: =,'.=','+=',*=' ...] precedence */) { iFlags |= EXPR_FLAG_LOAD_IDX_STORE; } diff --git a/engine/vm.c b/engine/vm.c index 9b26064..978ac30 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2135,12 +2135,12 @@ static sxi32 VmByteCodeExec( pc = pInstr->iP2 - 1; break; /* - * JZ: P1 P2 * + * JMPZ: P1 P2 * * * Take the jump if the top value is zero (FALSE jump).Pop the top most * entry in the stack if P1 is zero. */ - case PH7_OP_JZ: + case PH7_OP_JMPZ: #ifdef UNTRUST if(pTos < pStack) { goto Abort; @@ -2159,12 +2159,12 @@ static sxi32 VmByteCodeExec( } break; /* - * JNZ: P1 P2 * + * JMPNZ: P1 P2 * * * Take the jump if the top value is not zero (TRUE jump).Pop the top most * entry in the stack if P1 is zero. */ - case PH7_OP_JNZ: + case PH7_OP_JMPNZ: #ifdef UNTRUST if(pTos < pStack) { goto Abort; @@ -5399,11 +5399,11 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_JMP: zOp = "JMP"; break; - case PH7_OP_JZ: - zOp = "JZ"; + case PH7_OP_JMPZ: + zOp = "JMPZ"; break; - case PH7_OP_JNZ: - zOp = "JNZ"; + case PH7_OP_JMPNZ: + zOp = "JMPNZ"; break; case PH7_OP_POP: zOp = "POP"; diff --git a/include/ph7int.h b/include/ph7int.h index 82272a6..59e8772 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1397,8 +1397,8 @@ enum ph7_vm_op { PH7_OP_LOAD_CLOSURE, /* Load closure */ PH7_OP_NOOP, /* NOOP */ PH7_OP_JMP, /* Unconditional jump */ - PH7_OP_JZ, /* Jump on zero (FALSE jump) */ - PH7_OP_JNZ, /* Jump on non-zero (TRUE jump) */ + PH7_OP_JMPZ, /* Jump on zero (FALSE jump) */ + PH7_OP_JMPNZ, /* Jump on non-zero (TRUE jump) */ PH7_OP_POP, /* Stack POP */ PH7_OP_CVT_INT, /* Integer cast */ PH7_OP_CVT_STR, /* String cast */ From 5fddbf8737baa46b20e86eb316237d4526190730 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 16 Apr 2019 12:32:01 +0200 Subject: [PATCH 279/296] Do not allow 'continue' statement to take a parameter. This is strange construction introduced in PHP. --- engine/compiler.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 0ea76c8..b09b38c 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -1431,25 +1431,13 @@ Synchronize: */ static sxi32 PH7_CompileContinue(ph7_gen_state *pGen) { GenBlock *pLoop; /* Target loop */ - sxi32 iLevel; /* How many nesting loop to skip */ sxu32 nLine; sxi32 rc; nLine = pGen->pIn->nLine; - iLevel = 0; /* Jump the 'continue' keyword */ pGen->pIn++; - if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_NUM)) { - /* optional numeric argument which tells us how many levels - * of enclosing loops we should skip to the end of. - */ - iLevel = (sxi32)PH7_TokenValueToInt64(&pGen->pIn->sData); - if(iLevel < 2) { - iLevel = 0; - } - pGen->pIn++; /* Jump the optional numeric argument */ - } /* Point to the target loop */ - pLoop = PH7_GenStateFetchBlock(pGen->pCurrent, GEN_BLOCK_LOOP, iLevel); + pLoop = PH7_GenStateFetchBlock(pGen->pCurrent, GEN_BLOCK_LOOP, 0); if(pLoop == 0) { /* Illegal continue */ rc = PH7_GenCompileError(pGen, E_ERROR, nLine, "A 'continue' statement may only be used within a loop or switch"); @@ -1483,7 +1471,7 @@ static sxi32 PH7_CompileContinue(ph7_gen_state *pGen) { } if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_SEMI) == 0) { /* Not so fatal,emit a warning only */ - PH7_GenCompileError(&(*pGen), E_WARNING, pGen->pIn->nLine, "Expected semi-colon ';' after 'continue' statement"); + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Expected semi-colon ';' after 'continue' statement"); } /* Statement successfully compiled */ return SXRET_OK; From ef4f994e8bbf2cca77622682ba25c3bcb83ec79a Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 16 Apr 2019 12:34:53 +0200 Subject: [PATCH 280/296] Do not allow 'break' statement to take a parameter. This is strange construction introduced in PHP. --- engine/compiler.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index b09b38c..1ff935f 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -1485,25 +1485,13 @@ static sxi32 PH7_CompileContinue(ph7_gen_state *pGen) { */ static sxi32 PH7_CompileBreak(ph7_gen_state *pGen) { GenBlock *pLoop; /* Target loop */ - sxi32 iLevel; /* How many nesting loop to skip */ sxu32 nLine; sxi32 rc; nLine = pGen->pIn->nLine; - iLevel = 0; /* Jump the 'break' keyword */ pGen->pIn++; - if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_NUM)) { - /* optional numeric argument which tells us how many levels - * of enclosing loops we should skip to the end of. - */ - iLevel = (sxi32)PH7_TokenValueToInt64(&pGen->pIn->sData); - if(iLevel < 2) { - iLevel = 0; - } - pGen->pIn++; /* Jump the optional numeric argument */ - } /* Extract the target loop */ - pLoop = PH7_GenStateFetchBlock(pGen->pCurrent, GEN_BLOCK_LOOP, iLevel); + pLoop = PH7_GenStateFetchBlock(pGen->pCurrent, GEN_BLOCK_LOOP, 0); if(pLoop == 0) { /* Illegal break */ rc = PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "A 'break' statement may only be used within a loop or switch"); @@ -1521,7 +1509,7 @@ static sxi32 PH7_CompileBreak(ph7_gen_state *pGen) { } if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_SEMI) == 0) { /* Not so fatal,emit a warning only */ - PH7_GenCompileError(&(*pGen), E_WARNING, pGen->pIn->nLine, "Expected semi-colon ';' after 'break' statement"); + PH7_GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Expected semi-colon ';' after 'break' statement"); } /* Statement successfully compiled */ return SXRET_OK; From ba8e9080ef62e53b5bbf267295965e372a3ae446 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 16 Apr 2019 12:46:58 +0200 Subject: [PATCH 281/296] Implement OP_JMPLFB & OP_JMPLFE VM instructions. --- engine/vm.c | 23 +++++++++++++++++++++++ include/ph7int.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index 978ac30..89252ac 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2182,6 +2182,23 @@ static sxi32 VmByteCodeExec( VmPopOperand(&pTos, 1); } break; + case PH7_OP_JMPLFB: { + VmFrame *pFrame; + /* Enter the jump loop frame */ + rc = VmEnterFrame(&(*pVm), pVm->pFrame->pUserData, pVm->pFrame->pThis, &pFrame); + if(rc != SXRET_OK) { + PH7_VmMemoryError(&(*pVm)); + } + pFrame->iFlags = VM_FRAME_LOOP; + break; + } + case PH7_OP_JMPLFE: { + /* Leave the jump loop frame */ + if(pVm->pFrame->iFlags & VM_FRAME_LOOP) { + VmLeaveFrame(&(*pVm)); + } + break; + } /* * NOOP: * * * * @@ -5405,6 +5422,12 @@ static const char *VmInstrToString(sxi32 nOp) { case PH7_OP_JMPNZ: zOp = "JMPNZ"; break; + case PH7_OP_JMPLFB: + zOp = "JMPLFB"; + break; + case PH7_OP_JMPLFE: + zOp = "JMPLFB"; + break; case PH7_OP_POP: zOp = "POP"; break; diff --git a/include/ph7int.h b/include/ph7int.h index 59e8772..6d012d4 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1399,6 +1399,8 @@ enum ph7_vm_op { PH7_OP_JMP, /* Unconditional jump */ PH7_OP_JMPZ, /* Jump on zero (FALSE jump) */ PH7_OP_JMPNZ, /* Jump on non-zero (TRUE jump) */ + PH7_OP_JMPLFB, /* Jump loop frame begin */ + PH7_OP_JMPLFE, /* Jump loop frame end */ PH7_OP_POP, /* Stack POP */ PH7_OP_CVT_INT, /* Integer cast */ PH7_OP_CVT_STR, /* String cast */ From 07e3a099998002c14c393fb7678e938ee8b7be49 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 16 Apr 2019 13:51:58 +0200 Subject: [PATCH 282/296] Enter and leave a loop frame on every iteration. This fixes strict variable declaration inside loops. --- engine/compiler.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 1ff935f..5827b7d 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -1458,9 +1458,12 @@ static sxi32 PH7_CompileContinue(ph7_gen_state *pGen) { PH7_GenStateNewJumpFixup(pLoop, PH7_OP_JMP, nInstrIdx); } } else { - /* Emit the unconditional jump to the beginning of the target loop */ + if(!pLoop->bPostContinue) { + /* Emit the OP_JMPLFE instruction to leave the loop frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFE, 0, 0, 0, 0); + } PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMP, 0, pLoop->nFirstInstr, 0, &nInstrIdx); - if(pLoop->bPostContinue == TRUE) { + if(pLoop->bPostContinue) { JumpFixup sJumpFix; /* Post-continue */ sJumpFix.nJumpType = PH7_OP_JMP; @@ -1501,6 +1504,8 @@ static sxi32 PH7_CompileBreak(ph7_gen_state *pGen) { } } else { sxu32 nInstrIdx; + /* Emit the OP_JMPLFE instruction to leave the loop frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFE, 0, 0, 0, 0); rc = PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMP, 0, 0, 0, &nInstrIdx); if(rc == SXRET_OK) { /* Fix the jump later when the jump destination is resolved */ @@ -1667,11 +1672,15 @@ static sxi32 PH7_CompileWhile(ph7_gen_state *pGen) { PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMPZ, 0, 0, 0, &nFalseJump); /* Save the instruction index so we can fix it later when the jump destination is resolved */ PH7_GenStateNewJumpFixup(pWhileBlock, PH7_OP_JMPZ, nFalseJump); + /* Emit the OP_JMPLFB instruction to enter a loop frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFB, 0, 0, 0, 0); /* Compile the loop body */ rc = PH7_CompileBlock(&(*pGen)); if(rc == SXERR_ABORT) { return SXERR_ABORT; } + /* Emit the OP_JMPLFE instruction to leave the loop frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFE, 0, 0, 0, 0); /* Emit the unconditional jump to the start of the loop */ PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMP, 0, pWhileBlock->nFirstInstr, 0, 0); /* Fix all jumps now the destination is resolved */ @@ -1719,6 +1728,8 @@ static sxi32 PH7_CompileDoWhile(ph7_gen_state *pGen) { } /* Deffer 'continue;' jumps until we compile the block */ pDoBlock->bPostContinue = TRUE; + /* Emit the OP_JMPLFB instruction to enter a loop frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFB, 0, 0, 0, 0); rc = PH7_CompileBlock(&(*pGen)); if(rc == SXERR_ABORT) { return SXERR_ABORT; @@ -1795,6 +1806,8 @@ static sxi32 PH7_CompileDoWhile(ph7_gen_state *pGen) { } pGen->pIn = &pEnd[1]; pGen->pEnd = pTmp; + /* Emit the OP_JMPLFE instruction to leave the loop frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFE, 0, 0, 0, 0); /* Emit the true jump to the beginning of the loop */ PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMPNZ, 0, pDoBlock->nFirstInstr, 0, 0); /* Fix all jumps now the destination is resolved */ @@ -1923,6 +1936,8 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) { } return SXRET_OK; } + /* Emit the OP_JMPLFB instruction to enter a loop frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFB, 0, 0, 0, 0); /* Jump the trailing ';' */ pGen->pIn++; /* Save the post condition stream */ @@ -1976,6 +1991,8 @@ static sxi32 PH7_CompileFor(ph7_gen_state *pGen) { PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_POP, 1, 0, 0, 0); } } + /* Emit the OP_JMPLFE instruction to leave the loop frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFE, 0, 0, 0, 0); /* Emit the unconditional jump to the start of the loop */ PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMP, 0, pForBlock->nFirstInstr, 0, 0); /* Fix all jumps now the destination is resolved */ @@ -2189,6 +2206,8 @@ static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) { PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_FOREACH_STEP, 0, 0, pInfo, &nFalseJump); /* Save the instruction index so we can fix it later when the jump destination is resolved */ PH7_GenStateNewJumpFixup(pForeachBlock, PH7_OP_FOREACH_STEP, nFalseJump); + /* Emit the OP_JMPLFB instruction to enter a loop frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFB, 0, 0, 0, 0); /* Compile the loop body */ pGen->pIn = &pEnd[1]; pGen->pEnd = pTmp; @@ -2197,6 +2216,8 @@ static sxi32 PH7_CompileForeach(ph7_gen_state *pGen) { /* Don't worry about freeing memory, everything will be released shortly */ return SXERR_ABORT; } + /* Emit the OP_JMPLFE instruction to leave the loop frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFE, 0, 0, 0, 0); /* Emit the unconditional jump to the start of the loop */ PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMP, 0, pForeachBlock->nFirstInstr, 0, 0); /* Fix all jumps now the destination is resolved */ From 0b11d59f9fe16b08a96f410d7c390b06594c918d Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 16 Apr 2019 13:59:10 +0200 Subject: [PATCH 283/296] Remove this dirty hack. This test should now work without it. --- tests/static_var.aer | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/static_var.aer b/tests/static_var.aer index 7d4a519..535e4ff 100644 --- a/tests/static_var.aer +++ b/tests/static_var.aer @@ -10,12 +10,11 @@ class Program { } void main() { - int $i, $j, $k; - for($i = 1; $i < 3; $i++) { + for(int $i = 1; $i < 3; $i++) { print($i + $this->cycle('a', 'b') + PHP_EOL); - for($j = 1; $j < 5; $j++) { + for(int $j = 1; $j < 5; $j++) { print(' ' + $j + $this->cycle('a', 'b', 1) + PHP_EOL); - for($k = 1; $k < 3; $k++) { + for(int $k = 1; $k < 3; $k++) { print(' ' + $k + $this->cycle('c', 'd', 2) + PHP_EOL); } } From 2894c55dfa821113abea9057eb1ade01aac01ebe Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 16 Apr 2019 15:08:08 +0200 Subject: [PATCH 284/296] Add some comments, to see if they are working. --- tests/hello_world.aer | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/hello_world.aer b/tests/hello_world.aer index e8ced87..bc2918f 100644 --- a/tests/hello_world.aer +++ b/tests/hello_world.aer @@ -1,7 +1,12 @@ +#!/usr/local/bin/aer class Program { + /* + * Program entry point. + * It does not take any arguments. + */ public void main() { - print('Hello world!'); + print('Hello world!'); // single line comment } } From 88d382b76b5f366999b02341c66fcd69fda791c9 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 16 Apr 2019 19:12:39 +0200 Subject: [PATCH 285/296] Add missing VM OP descriptions. --- engine/vm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/engine/vm.c b/engine/vm.c index 89252ac..d24a1d8 100644 --- a/engine/vm.c +++ b/engine/vm.c @@ -2182,6 +2182,11 @@ static sxi32 VmByteCodeExec( VmPopOperand(&pTos, 1); } break; + /* + * JMPLFB: * * * + * + * Creates and enters the jump loop frame on the beginning of each iteration. + */ case PH7_OP_JMPLFB: { VmFrame *pFrame; /* Enter the jump loop frame */ @@ -2192,6 +2197,10 @@ static sxi32 VmByteCodeExec( pFrame->iFlags = VM_FRAME_LOOP; break; } + /* + * Leaves and destroys the jump loop frame at the end of each iteration + * as well as on 'break' and 'continue' instructions. + */ case PH7_OP_JMPLFE: { /* Leave the jump loop frame */ if(pVm->pFrame->iFlags & VM_FRAME_LOOP) { From a5da714d61ca4f7989aaca3747961e52bbf7370a Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 16 Apr 2019 19:31:24 +0200 Subject: [PATCH 286/296] Test while loop. --- tests/loop_while_test.aer | 23 +++++++++++++++++++++++ tests/loop_while_test.exp | 6 ++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/loop_while_test.aer create mode 100644 tests/loop_while_test.exp diff --git a/tests/loop_while_test.aer b/tests/loop_while_test.aer new file mode 100644 index 0000000..031a913 --- /dev/null +++ b/tests/loop_while_test.aer @@ -0,0 +1,23 @@ +class Program { + + private int test() { + static int $x = 9; + return $x--; + } + + public void main() { + int $a; + int $b = 2; + while($a = $this->test()) { + int $b = $a; + if($b == 6) { + continue; + } else if($b == 3) { + break; + } + print("$b\n"); + } + print("$b\n"); + } + +} diff --git a/tests/loop_while_test.exp b/tests/loop_while_test.exp new file mode 100644 index 0000000..222651f --- /dev/null +++ b/tests/loop_while_test.exp @@ -0,0 +1,6 @@ +9 +8 +7 +5 +4 +2 From 6b18e204cd5293d7d2715e490921eab4d2a4bc47 Mon Sep 17 00:00:00 2001 From: Piotr Likoski Date: Tue, 16 Apr 2019 20:15:38 +0200 Subject: [PATCH 287/296] Always pop the l-value on variable declaration. Otherwise, it might lead to unexpected behaviour including protected memory access and segmentation fault. This finally fixes #49. --- engine/compiler.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/compiler.c b/engine/compiler.c index 5827b7d..598e2b8 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2555,6 +2555,8 @@ static sxi32 PH7_CompileVar(ph7_gen_state *pGen) { void *p3 = (void *) zDup; /* Emit OP_DECLARE instruction */ PH7_VmEmitInstr(pGen->pVm, pGen->pIn->nLine, PH7_OP_DECLARE, 0, nType, p3, 0); + /* Pop the l-value */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_POP, 1, 0, 0, 0); /* Check if we have an expression to compile */ if(pGen->pIn < pGen->pEnd && (pGen->pIn[2].nType & PH7_TK_EQUAL)) { /* Compile the expression */ From e5d7977995326705061a5dd22e16c576e7c5c4f7 Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 16 Apr 2019 20:25:38 +0200 Subject: [PATCH 288/296] Fixed by implementation of OP_JMPLFB & OP_JMPLFE VM instructions. --- TODO | 2 -- 1 file changed, 2 deletions(-) diff --git a/TODO b/TODO index 2e9fe7b..4306cf9 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,2 @@ TODO list for typehinting branch. Below list contains things that should be changed/fixed/implemented. - -1. Variable declaration inside a loop leads to redeclaration error. \ No newline at end of file From 549b2ff3b467619fc37c31210d7b0a838b9a6b45 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 17 Apr 2019 07:49:22 +0200 Subject: [PATCH 289/296] Do not use 'elseif' construction. --- tests/utf8_variables.aer | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/utf8_variables.aer b/tests/utf8_variables.aer index 7077546..85ef3f3 100644 --- a/tests/utf8_variables.aer +++ b/tests/utf8_variables.aer @@ -21,13 +21,13 @@ class Program { $c = ord($str[$i]); if($c >= 128) { if(($c >= 254)) return false; - elseif($c >= 252) $bits=6; - elseif($c >= 248) $bits=5; - elseif($c >= 240) $bits=4; - elseif($c >= 224) $bits=3; - elseif($c >= 192) $bits=2; + else if($c >= 252) $bits=6; + else if($c >= 248) $bits=5; + else if($c >= 240) $bits=4; + else if($c >= 224) $bits=3; + else if($c >= 192) $bits=2; else return false; - if(($i+$bits) > $len) return false; + if(($i + $bits) > $len) return false; while($bits > 1) { $i++; $b=ord($str[$i]); From 395f6c446c7800fbecf5fd5d352bedb23918c80f Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 17 Apr 2019 07:55:32 +0200 Subject: [PATCH 290/296] Get rid of known from PHP 'elseif' construction. --- engine/compiler.c | 10 +++++----- engine/lexer.c | 1 - include/ph7int.h | 3 +-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 598e2b8..1e6bad5 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -2335,16 +2335,16 @@ static sxi32 PH7_CompileIf(ph7_gen_state *pGen) { if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & PH7_TK_KEYWORD) == 0) { break; } - /* Ensure that the keyword ID is 'else if' or 'else' */ + /* Ensure that the keyword ID is 'else' */ nKeyID = (sxu32)SX_PTR_TO_INT(pGen->pIn->pUserData); - if((nKeyID & (PH7_KEYWORD_ELSE | PH7_KEYWORD_ELIF)) == 0) { + if(nKeyID != PH7_KEYWORD_ELSE) { break; } /* Emit the unconditional jump */ PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMP, 0, 0, 0, &nJumpIdx); /* Save the instruction index so we can fix it later when the jump destination is resolved */ PH7_GenStateNewJumpFixup(pCondBlock, PH7_OP_JMP, nJumpIdx); - if(nKeyID & PH7_KEYWORD_ELSE) { + if(nKeyID == PH7_KEYWORD_ELSE) { pToken = &pGen->pIn[1]; if(pToken >= pGen->pEnd || (pToken->nType & PH7_TK_KEYWORD) == 0 || SX_PTR_TO_INT(pToken->pUserData) != PH7_KEYWORD_IF) { @@ -2352,7 +2352,7 @@ static sxi32 PH7_CompileIf(ph7_gen_state *pGen) { } pGen->pIn++; /* Jump the 'else' keyword */ } - pGen->pIn++; /* Jump the 'elseif/if' keyword */ + pGen->pIn++; /* Jump the 'if' keyword */ /* Synchronize cursors */ pToken = pGen->pIn; /* Fix the false jump */ @@ -2361,7 +2361,7 @@ static sxi32 PH7_CompileIf(ph7_gen_state *pGen) { /* Fix the false jump */ PH7_GenStateFixJumps(pCondBlock, PH7_OP_JMPZ, PH7_VmInstrLength(pGen->pVm)); if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_KEYWORD) && - (SX_PTR_TO_INT(pGen->pIn->pUserData) & PH7_KEYWORD_ELSE)) { + (SX_PTR_TO_INT(pGen->pIn->pUserData) == PH7_KEYWORD_ELSE)) { /* Compile the else block */ pGen->pIn++; rc = PH7_CompileBlock(&(*pGen)); diff --git a/engine/lexer.c b/engine/lexer.c index a1d3797..1697e4a 100644 --- a/engine/lexer.c +++ b/engine/lexer.c @@ -623,7 +623,6 @@ static sxu32 KeywordCode(const char *z, int n) { {"foreach", PH7_KEYWORD_FOREACH}, {"switch", PH7_KEYWORD_SWITCH}, {"else", PH7_KEYWORD_ELSE}, - {"elseif", PH7_KEYWORD_ELIF}, {"if", PH7_KEYWORD_IF}, {"while", PH7_KEYWORD_WHILE}, /* Reserved keywords */ diff --git a/include/ph7int.h b/include/ph7int.h index 6d012d4..d263f69 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1564,8 +1564,7 @@ enum ph7_expr_id { /* The number '8' is reserved for PH7_TK_ID */ #define PH7_KEYWORD_IMPORT 9 /* import */ #define PH7_KEYWORD_REQUIRE 10 /* require */ -#define PH7_KEYWORD_ELIF 0x4000000 /* elseif: MUST BE A POWER OF TWO */ -#define PH7_KEYWORD_ELSE 0x8000000 /* else: MUST BE A POWER OF TWO */ +#define PH7_KEYWORD_ELSE 12 /* else */ #define PH7_KEYWORD_IF 13 /* if */ #define PH7_KEYWORD_FINAL 14 /* final */ #define PH7_KEYWORD_STATIC 16 /* static */ From ec580ddf8ce561d5b4a6f02aba1a19c95833e9ae Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 17 Apr 2019 08:32:19 +0200 Subject: [PATCH 291/296] Path splitting test. --- tests/path_split.aer | 32 ++++++++++++++++++++++++++++++++ tests/path_split.exp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/path_split.aer create mode 100644 tests/path_split.exp diff --git a/tests/path_split.aer b/tests/path_split.aer new file mode 100644 index 0000000..487115e --- /dev/null +++ b/tests/path_split.aer @@ -0,0 +1,32 @@ +class Program { + + string[] parsePathComponents(string $path, bool $endSlash=true, bool $base=false) { + string[] $retArray; + $path = trim($path); + string $str, $temp; + char $char; + for(int $x = 0; $char = $path[$x]; $x++) { + if(!strstr('/', $char)) $temp += $char; + else if($temp) { + $str += $temp; + $retArray[$temp] = $str + ($endSlash ? '/' : ''); + $str += '/'; + $temp = ''; + } + } + ($base && $temp) ? $retArray[$temp] = $str + $temp : NULL; + return $retArray; + } + + void main() { + string $path = '/my//stupid//path/to///some/file.php'; + print_r($this->parsePathComponents($path)); + + $path = 'my/other//path/'; + print_r($this->parsePathComponents($path, false)); + + $path = '/my//other/path/to///file.php'; + print_r($this->parsePathComponents($path, true, true)); + } + +} diff --git a/tests/path_split.exp b/tests/path_split.exp new file mode 100644 index 0000000..c99eb2a --- /dev/null +++ b/tests/path_split.exp @@ -0,0 +1,32 @@ +Array(5) { + [my] => + my/ + [stupid] => + my/stupid/ + [path] => + my/stupid/path/ + [to] => + my/stupid/path/to/ + [some] => + my/stupid/path/to/some/ + } +Array(3) { + [my] => + my + [other] => + my/other + [path] => + my/other/path + } +Array(5) { + [my] => + my/ + [other] => + my/other/ + [path] => + my/other/path/ + [to] => + my/other/path/to/ + [file.php] => + my/other/path/to/file.php + } From 5f57ba54a40f3b902422bf54f6238e26715abab1 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 17 Apr 2019 08:59:42 +0200 Subject: [PATCH 292/296] Left operand must be modifiable when storing some value. --- engine/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/parser.c b/engine/parser.c index b6e8aac..550808f 100644 --- a/engine/parser.c +++ b/engine/parser.c @@ -1419,7 +1419,7 @@ static sxi32 ExprMakeTree(ph7_gen_state *pGen, ph7_expr_node **apNode, sxi32 nTo return rc; } if(ExprIsModifiableValue(apNode[iLeft], FALSE) == FALSE) { - if(pNode->pOp->iVmOp != PH7_OP_STORE) { + if(pNode->pOp->iVmOp == PH7_OP_STORE) { /* Left operand must be a modifiable l-value */ rc = PH7_GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Left operand must be a modifiable l-value", &pNode->pOp->sOp); From 102e8447a1b0e5ce3b0ca87744336d7e2c05e1c5 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 17 Apr 2019 10:08:03 +0200 Subject: [PATCH 293/296] Formatting code. --- tests/center_text.aer | 2 +- tests/closure_test.aer | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/center_text.aer b/tests/center_text.aer index 93267a2..a231121 100644 --- a/tests/center_text.aer +++ b/tests/center_text.aer @@ -4,7 +4,7 @@ class Program { int $tot_width = 30; char $symbol = '-'; int $middle = (int) round($tot_width/2); - int $length_word = strlen($word); + int $length_word = strlen($word); int $middle_word = (int) round($length_word / 2); int $last_position = $middle + $middle_word; int $number_of_spaces = $middle - $middle_word; diff --git a/tests/closure_test.aer b/tests/closure_test.aer index 6f6a470..6a753a4 100644 --- a/tests/closure_test.aer +++ b/tests/closure_test.aer @@ -9,7 +9,7 @@ class Operations { break; case 'SUB': return int() using ($x, $y) { - return $x - $y; + return $x - $y; }; break; default: From b668d0a897987ac85518123b1f5000af8ea8b6a3 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 17 Apr 2019 11:01:34 +0200 Subject: [PATCH 294/296] Test do { ... } while(); loop. --- tests/loop_do_while_test.aer | 23 +++++++++++++++++++++++ tests/loop_do_while_test.exp | 6 ++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/loop_do_while_test.aer create mode 100644 tests/loop_do_while_test.exp diff --git a/tests/loop_do_while_test.aer b/tests/loop_do_while_test.aer new file mode 100644 index 0000000..e6641e7 --- /dev/null +++ b/tests/loop_do_while_test.aer @@ -0,0 +1,23 @@ +class Program { + + private int test() { + static int $x = 9; + return $x--; + } + + public void main() { + int $a; + do { + $a = $this->test(); + int $z = $a; + if($z == 6) { + continue; + } else if($z == 3) { + break; + } + print("$z\n"); + } while($a); + print("$a\n"); + } + +} diff --git a/tests/loop_do_while_test.exp b/tests/loop_do_while_test.exp new file mode 100644 index 0000000..a77242f --- /dev/null +++ b/tests/loop_do_while_test.exp @@ -0,0 +1,6 @@ +9 +8 +7 +5 +4 +3 From 9d97eb228a5392a57d8163540667784023bd80d3 Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 17 Apr 2019 11:07:53 +0200 Subject: [PATCH 295/296] Test a for() loop as well. --- tests/loop_for_test.aer | 20 ++++++++++++++++ tests/loop_for_test.exp | 51 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 tests/loop_for_test.aer create mode 100644 tests/loop_for_test.exp diff --git a/tests/loop_for_test.aer b/tests/loop_for_test.aer new file mode 100644 index 0000000..372471c --- /dev/null +++ b/tests/loop_for_test.aer @@ -0,0 +1,20 @@ +class Program { + + public void main() { + int $c = 4; + for(int $a = 0; $a < 10; $a++) { + for(int $b = 0; $b < 10; $b++) { + int $c = 2; + if($b == 2) { + continue; + } + if($b == 6) { + break; + } + print("Hello variables: $a $b $c\n"); + } + } + print("Variable \$c: $c\n"); + } + +} diff --git a/tests/loop_for_test.exp b/tests/loop_for_test.exp new file mode 100644 index 0000000..1419a06 --- /dev/null +++ b/tests/loop_for_test.exp @@ -0,0 +1,51 @@ +Hello variables: 0 0 2 +Hello variables: 0 1 2 +Hello variables: 0 3 2 +Hello variables: 0 4 2 +Hello variables: 0 5 2 +Hello variables: 1 0 2 +Hello variables: 1 1 2 +Hello variables: 1 3 2 +Hello variables: 1 4 2 +Hello variables: 1 5 2 +Hello variables: 2 0 2 +Hello variables: 2 1 2 +Hello variables: 2 3 2 +Hello variables: 2 4 2 +Hello variables: 2 5 2 +Hello variables: 3 0 2 +Hello variables: 3 1 2 +Hello variables: 3 3 2 +Hello variables: 3 4 2 +Hello variables: 3 5 2 +Hello variables: 4 0 2 +Hello variables: 4 1 2 +Hello variables: 4 3 2 +Hello variables: 4 4 2 +Hello variables: 4 5 2 +Hello variables: 5 0 2 +Hello variables: 5 1 2 +Hello variables: 5 3 2 +Hello variables: 5 4 2 +Hello variables: 5 5 2 +Hello variables: 6 0 2 +Hello variables: 6 1 2 +Hello variables: 6 3 2 +Hello variables: 6 4 2 +Hello variables: 6 5 2 +Hello variables: 7 0 2 +Hello variables: 7 1 2 +Hello variables: 7 3 2 +Hello variables: 7 4 2 +Hello variables: 7 5 2 +Hello variables: 8 0 2 +Hello variables: 8 1 2 +Hello variables: 8 3 2 +Hello variables: 8 4 2 +Hello variables: 8 5 2 +Hello variables: 9 0 2 +Hello variables: 9 1 2 +Hello variables: 9 3 2 +Hello variables: 9 4 2 +Hello variables: 9 5 2 +Variable $c: 4 From bd22425b46f9aef62da74f31298c256c10defa9b Mon Sep 17 00:00:00 2001 From: belliash Date: Wed, 17 Apr 2019 11:13:29 +0200 Subject: [PATCH 296/296] Do not allow 'continue' statement in a switch case. Important rule while using continue statement is that, We can use continue statement only within the loops. Switch case is conditional block not a loop so we cannot execute the continue statement inside switch. --- engine/compiler.c | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/engine/compiler.c b/engine/compiler.c index 1e6bad5..b1181fd 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -1438,38 +1438,26 @@ static sxi32 PH7_CompileContinue(ph7_gen_state *pGen) { pGen->pIn++; /* Point to the target loop */ pLoop = PH7_GenStateFetchBlock(pGen->pCurrent, GEN_BLOCK_LOOP, 0); - if(pLoop == 0) { + if(pLoop == 0 || pLoop->iFlags & GEN_BLOCK_SWITCH) { /* Illegal continue */ - rc = PH7_GenCompileError(pGen, E_ERROR, nLine, "A 'continue' statement may only be used within a loop or switch"); + rc = PH7_GenCompileError(pGen, E_ERROR, nLine, "A 'continue' statement may only be used within a loop"); if(rc == SXERR_ABORT) { /* Error count limit reached,abort immediately */ return SXERR_ABORT; } } else { sxu32 nInstrIdx = 0; - if(pLoop->iFlags & GEN_BLOCK_SWITCH) { - /* - * Note that unlike some other languages, the continue statement applies to switch - * and acts similar to break. If you have a switch inside a loop and wish to continue - * to the next iteration of the outer loop, use continue 2. - */ - rc = PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMP, 0, 0, 0, &nInstrIdx); - if(rc == SXRET_OK) { - PH7_GenStateNewJumpFixup(pLoop, PH7_OP_JMP, nInstrIdx); - } - } else { - if(!pLoop->bPostContinue) { - /* Emit the OP_JMPLFE instruction to leave the loop frame */ - PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFE, 0, 0, 0, 0); - } - PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMP, 0, pLoop->nFirstInstr, 0, &nInstrIdx); - if(pLoop->bPostContinue) { - JumpFixup sJumpFix; - /* Post-continue */ - sJumpFix.nJumpType = PH7_OP_JMP; - sJumpFix.nInstrIdx = nInstrIdx; - SySetPut(&pLoop->aPostContFix, (const void *)&sJumpFix); - } + if(!pLoop->bPostContinue) { + /* Emit the OP_JMPLFE instruction to leave the loop frame */ + PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_JMPLFE, 0, 0, 0, 0); + } + PH7_VmEmitInstr(pGen->pVm, 0, PH7_OP_JMP, 0, pLoop->nFirstInstr, 0, &nInstrIdx); + if(pLoop->bPostContinue) { + JumpFixup sJumpFix; + /* Post-continue */ + sJumpFix.nJumpType = PH7_OP_JMP; + sJumpFix.nInstrIdx = nInstrIdx; + SySetPut(&pLoop->aPostContFix, (const void *)&sJumpFix); } } if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_SEMI) == 0) {