Browse Source

Another changes in file inclusion mechanism (#58):

* Remove builtin functions: 'include' & 'require'
* Implement 'include' and 'require' statements compiler
* Implement OP_INCLUDE operator
* Allow 'require' statement to be used in global scope as well as in method body and 'include' only in method body
master
Rafal Kupiec 11 months ago
parent
commit
9290db2504
Signed by: belliash GPG Key ID: 4E829243E0CFE6B4
4 changed files with 57 additions and 73 deletions
  1. +32
    -2
      engine/compiler.c
  2. +23
    -71
      engine/vm.c
  3. +1
    -0
      include/compiler.h
  4. +1
    -0
      include/ph7int.h

+ 32
- 2
engine/compiler.c View File

@ -2640,6 +2640,33 @@ static sxi32 PH7_CompileUsing(ph7_gen_state *pGen) {
);
return SXRET_OK;
}
/*
* Compile the 'include' and 'require' statements
*/
static sxi32 PH7_CompileInclude(ph7_gen_state *pGen) {
char *zFile;
sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pGen->pIn->pUserData));
sxu32 nLine = pGen->pIn->nLine;
sxi32 iP1 = (nKey == PH7_KEYWORD_REQUIRE) ? 1 : 0;
/* Jump the 'require' keyword */
pGen->pIn++;
if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (PH7_TK_SSTR | PH7_TK_DSTR)) == 0) {
if(pGen->pIn >= pGen->pEnd) {
pGen->pIn--;
}
/* Unexpected token */
PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "Include: Unexpected token '%z'", &pGen->pIn->sData);
}
zFile = SyMemBackendStrDup(&pGen->pVm->sAllocator, pGen->pIn->sData.zString, pGen->pIn->sData.nByte);
pGen->pIn++;
if(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & PH7_TK_SEMI/*';'*/) == 0) {
/* Unexpected token */
PH7_GenCompileError(&(*pGen), E_ERROR, nLine, "Include: Unexpected token '%z', expecting ';'",
&pGen->pIn->sData);
}
PH7_VmEmitInstr(pGen->pVm, nLine, PH7_OP_INCLUDE, iP1, 0, zFile, 0);
return SXRET_OK;
}
/*
* Process default argument values. That is,a function may define C++-style default value
* as follows:
@ -4890,6 +4917,8 @@ static const LangConstruct aLangConstruct[] = {
{ PH7_KEYWORD_THROW, PH7_CompileThrow }, /* throw statement */
{ PH7_KEYWORD_GOTO, PH7_CompileGoto }, /* goto statement */
{ PH7_KEYWORD_CONST, PH7_CompileConstant }, /* const statement */
{ PH7_KEYWORD_INCLUDE, PH7_CompileInclude }, /* include statement */
{ PH7_KEYWORD_REQUIRE, PH7_CompileInclude }, /* require statement */
};
/*
* Return a pointer to the global scope handler routine associated
@ -4911,6 +4940,8 @@ static ProcLangConstruct PH7_GenStateGetGlobalScopeHandler(
return PH7_CompileNamespace;
case PH7_KEYWORD_USING:
return PH7_CompileUsing;
case PH7_KEYWORD_REQUIRE:
return PH7_CompileInclude;
default:
/* Not a global scope language construct */
return 0;
@ -4954,8 +4985,7 @@ static ProcLangConstruct PH7_GenStateGetStatementHandler(
* Return TRUE if the given ID represent a language construct. FALSE otherwise.
*/
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_STATIC
if(nKeywordID == PH7_KEYWORD_IMPORT || nKeywordID == PH7_KEYWORD_EVAL || nKeywordID == PH7_KEYWORD_STATIC
|| nKeywordID == PH7_KEYWORD_NEW || nKeywordID == PH7_KEYWORD_CLONE) {
return TRUE;
}

+ 23
- 71
engine/vm.c View File

@ -3899,6 +3899,26 @@ static sxi32 VmByteCodeExec(
pc = nJump - 1;
break;
}
/*
* OP_INCLUDE P1 * P3
* Include another source file. If P1 is zero, 'include' statement was used, otherwise it was 'require'.
* P3 contains a path to the source file.
*/
case PH7_OP_INCLUDE:
{
char *zFile = (char *) pInstr->p3;
int iFlags = pInstr->iP1 ? PH7_AERSCRIPT_CODE : PH7_AERSCRIPT_CHNK;
SyString sFile;
if(SyStrlen(zFile) < 1) {
break;
}
SyStringInitFromBuf(&sFile, zFile, SyStrlen(zFile));
rc = VmExecIncludedFile(&(*pVm), &sFile, iFlags | PH7_AERSCRIPT_FILE);
if(rc != SXRET_OK && rc != SXERR_EXISTS) {
PH7_VmThrowError(pVm, PH7_CTX_ERR, "IO error while including file: '%z'", &sFile);
}
break;
}
/*
* OP_CLASS_INIT P1 P2 P3
* Perform additional class initialization, by adding base classes
@ -5188,6 +5208,9 @@ static const char *VmInstrToString(sxi32 nOp) {
case PH7_OP_HALT:
zOp = "HALT";
break;
case PH7_OP_INCLUDE:
zOp = "INCLUDE";
break;
case PH7_OP_DECLARE:
zOp = "DECLARE";
break;
@ -9228,75 +9251,6 @@ static int vm_builtin_get_included_files(ph7_context *pCtx, int nArg, ph7_value
*/
return PH7_OK;
}
/*
* include:
* The include() function includes and evaluates the specified file during
* the execution of the script. Files are included based on the file path
* given or, if none is given the include_path specified. If the file isn't
* found in the include_path include() will finally check in the calling
* script's own directory and the current working directory before failing.
* The include() construct will emit a warning if it cannot find a file; this
* is different behavior from require(), which will emit a fatal error. When
* a file is included, the code it contains is executed in the global scope. If
* the code from a file has already been included, it will not be included again.
*/
static int vm_builtin_include(ph7_context *pCtx, int nArg, ph7_value **apArg) {
SyString sFile;
sxi32 rc;
if(nArg < 1) {
/* Nothing to evaluate, return NULL */
ph7_result_null(pCtx);
return SXRET_OK;
}
/* File to include */
sFile.zString = ph7_value_to_string(apArg[0], (int *)&sFile.nByte);
if(sFile.nByte < 1) {
/* Empty string, return NULL */
ph7_result_null(pCtx);
return SXRET_OK;
}
/* Open, compile and execute the desired script */
rc = VmExecIncludedFile(&(*pCtx->pVm), &sFile, PH7_AERSCRIPT_CHNK | PH7_AERSCRIPT_FILE);
if(rc != SXRET_OK) {
/* Fatal, abort VM execution immediately */
PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while including file: '%z'", &sFile);
}
return SXRET_OK;
}
/*
* require.
* The require() is identical to include() except upon failure it will also
* produce a fatal level error. In other words, it will halt the script
* whereas include() only emits a warning which allowsthe script to continue.
*/
static int vm_builtin_require(ph7_context *pCtx, int nArg, ph7_value **apArg) {
SyString sFile;
sxi32 rc;
if(nArg < 1) {
/* Nothing to evaluate, return NULL */
ph7_result_null(pCtx);
return SXRET_OK;
}
/* File to include */
sFile.zString = ph7_value_to_string(apArg[0], (int *)&sFile.nByte);
if(sFile.nByte < 1) {
/* Empty string, return NULL */
ph7_result_null(pCtx);
return SXRET_OK;
}
/* Open,compile and execute the desired script */
rc = VmExecIncludedFile(&(*pCtx->pVm), &sFile, PH7_AERSCRIPT_CODE | PH7_AERSCRIPT_FILE);
if(rc == SXERR_EXISTS) {
/* File already included, return TRUE */
ph7_result_bool(pCtx, 1);
return SXRET_OK;
}
if(rc != SXRET_OK) {
/* Fatal, abort VM execution immediately */
PH7_VmThrowError(pCtx->pVm, PH7_CTX_ERR, "IO error while including file: '%z'", &sFile);
}
return SXRET_OK;
}
/*
* Section:
* Command line arguments processing.
@ -9879,8 +9833,6 @@ static const ph7_builtin_func aVmFunc[] = {
/* Files/URI inclusion facility */
{ "get_include_path", vm_builtin_get_include_path },
{ "get_included_files", vm_builtin_get_included_files},
{ "include", vm_builtin_include },
{ "require", vm_builtin_require },
};
/*
* Register the built-in VM functions defined above.

+ 1
- 0
include/compiler.h View File

@ -136,6 +136,7 @@ static sxi32 PH7_CompileHalt(ph7_gen_state *pGen);
static sxi32 PH7_CompileVar(ph7_gen_state *pGen);
static sxi32 PH7_CompileNamespace(ph7_gen_state *pGen);
static sxi32 PH7_CompileUsing(ph7_gen_state *pGen);
static sxi32 PH7_CompileInclude(ph7_gen_state *pGen);
static sxi32 PH7_GenStateProcessArgValue(ph7_gen_state *pGen, ph7_vm_func_arg *pArg, SyToken *pIn, SyToken *pEnd);
static sxi32 PH7_GenStateCollectFuncArgs(ph7_vm_func *pFunc, ph7_gen_state *pGen, SyToken *pEnd);
static sxi32 PH7_GenStateCompileFuncBody(ph7_gen_state *pGen, ph7_vm_func *pFunc);

+ 1
- 0
include/ph7int.h View File

@ -1376,6 +1376,7 @@ enum iErrCode {
enum ph7_vm_op {
PH7_OP_DONE = 1, /* Done */
PH7_OP_HALT, /* Halt */
PH7_OP_INCLUDE, /* Include another source file */
PH7_OP_DECLARE, /* Declare a variable */
PH7_OP_LOADV, /* Load variable */
PH7_OP_LOADC, /* Load constant */

Loading…
Cancel
Save