From b36510943dce3aeb11fe51587cf3d0c74738bc69 Mon Sep 17 00:00:00 2001 From: belliash Date: Sat, 4 May 2019 17:08:09 +0200 Subject: [PATCH] Implement 'define' statement for defining constants globally. --- engine/compiler.c | 65 +++++++++++++++++++++++++++++++++++++++++++++- engine/lexer.c | 1 + include/compiler.h | 2 ++ include/ph7int.h | 1 + 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/engine/compiler.c b/engine/compiler.c index aafc876..94d83ad 100644 --- a/engine/compiler.c +++ b/engine/compiler.c @@ -964,6 +964,67 @@ PH7_PRIVATE sxi32 PH7_CompileClosure(ph7_gen_state *pGen, sxi32 iCompileFlag) { /* Node successfully compiled */ return SXRET_OK; } +/* + * Expression tree validator callback used by the 'define' statement. + */ +static sxi32 GenStateDefineNodeValidator(ph7_gen_state *pGen, ph7_expr_node *pRoot) { + if(pRoot->xCode != PH7_CompileArray && pRoot->xCode != PH7_CompileLiteral && pRoot->xCode != PH7_CompileNumLiteral && + pRoot->xCode != PH7_CompileSimpleString && pRoot->xCode != PH7_CompileString) { + /* Unexpected expression */ + PH7_GenCompileError(&(*pGen), E_ERROR, pRoot->pStart ? pRoot->pStart->nLine : 0, + "Define: Expecting a constant simple value, not expression"); + } + return SXRET_OK; +} +/* + * Compile a global 'define' construct. + * A global constant, defined in global scope can be accessible from any place. + */ +PH7_PRIVATE sxi32 PH7_CompileDefine(ph7_gen_state *pGen, sxi32 iFlags) { + SySet *pConsCode, *pInstrContainer; + SyString *pName; + sxi32 rc; + /* Jump the 'define' keyword */ + pGen->pIn++; + if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (PH7_TK_ID | PH7_TK_KEYWORD)) == 0) { + /* Invalid variable name */ + PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Invalid constant name"); + } + /* Extract constant name */ + pName = &pGen->pIn->sData; + if(PH7_GenStateIsReservedConstant(pName)) { + /* Reserved constant */ + PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "define: Cannot redeclare a reserved constant '%z'", pName); + } + /* Advance the stream cursor */ + pGen->pIn++; + /* Allocate a new constant value container */ + pConsCode = (SySet *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(SySet)); + if(pConsCode == 0) { + PH7_GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "PH7 engine is running out-of-memory"); + } + SySetInit(pConsCode, &pGen->pVm->sAllocator, sizeof(VmInstr)); + /* Swap bytecode container */ + pInstrContainer = PH7_VmGetByteCodeContainer(pGen->pVm); + PH7_VmSetByteCodeContainer(pGen->pVm, pConsCode); + /* Compile constant value */ + rc = PH7_CompileExpr(&(*pGen), 0, GenStateDefineNodeValidator); + /* Emit the done instruction */ + PH7_VmEmitInstr(pGen->pVm, pGen->pIn->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 */ + return SXERR_ABORT; + } + SySetSetUserData(pConsCode, pGen->pVm); + /* Register the global constant */ + rc = PH7_VmRegisterConstant(pGen->pVm, pName, PH7_VmExpandConstantValue, pConsCode, TRUE); + if(rc != SXRET_OK) { + SySetRelease(pConsCode); + SyMemBackendPoolFree(&pGen->pVm->sAllocator, pConsCode); + } + return SXRET_OK; +} /* * Compile a function [i.e: die(),exit(),include(),...] which is a langauge * construct. @@ -4811,7 +4872,9 @@ static ProcLangConstruct PH7_GenStateGetGlobalScopeHandler( SyToken *pLookahead /* Look-ahead token */ ) { if(pLookahead) { - if(nKeywordID == PH7_KEYWORD_INTERFACE) { + if(nKeywordID == PH7_KEYWORD_DEFINE) { + return PH7_CompileDefine; + } else if(nKeywordID == PH7_KEYWORD_INTERFACE) { return PH7_CompileClassInterface; } else if(nKeywordID == PH7_KEYWORD_CLASS) { return PH7_CompileClass; diff --git a/engine/lexer.c b/engine/lexer.c index dffef80..4167afd 100644 --- a/engine/lexer.c +++ b/engine/lexer.c @@ -570,6 +570,7 @@ static sxu32 KeywordCode(const char *z, int n) { {"in", PH7_KEYWORD_IN}, {"while", PH7_KEYWORD_WHILE}, /* Reserved keywords */ + {"define", PH7_KEYWORD_DEFINE}, {"eval", PH7_KEYWORD_EVAL}, {"exit", PH7_KEYWORD_EXIT}, {"import", PH7_KEYWORD_IMPORT}, diff --git a/include/compiler.h b/include/compiler.h index 2ab4894..f633a99 100644 --- a/include/compiler.h +++ b/include/compiler.h @@ -115,6 +115,8 @@ static sxi32 PH7_GenStateArrayNodeValidator(ph7_gen_state *pGen, ph7_expr_node * PH7_PRIVATE sxi32 PH7_CompileArray(ph7_gen_state *pGen, sxi32 iCompileFlag); static sxi32 PH7_GenStateListNodeValidator(ph7_gen_state *pGen, ph7_expr_node *pRoot); static sxi32 PH7_GenStateCompileFunc(ph7_gen_state *pGen, SyString *pName, sxi32 iFlags, int bHandleClosure, ph7_vm_func **ppFunc); +static sxi32 GenStateDefineNodeValidator(ph7_gen_state *pGen, ph7_expr_node *pRoot); +PH7_PRIVATE sxi32 PH7_CompileDefine(ph7_gen_state *pGen, sxi32 iFlags); PH7_PRIVATE sxi32 PH7_CompileLangConstruct(ph7_gen_state *pGen, sxi32 iCompileFlag); PH7_PRIVATE sxi32 PH7_CompileVariable(ph7_gen_state *pGen, sxi32 iCompileFlag); static sxi32 PH7_GenStateLoadLiteral(ph7_gen_state *pGen); diff --git a/include/ph7int.h b/include/ph7int.h index 6b7bfc6..c7a3eca 100644 --- a/include/ph7int.h +++ b/include/ph7int.h @@ -1557,6 +1557,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_DEFINE 11 /* define */ #define PH7_KEYWORD_ELSE 12 /* else */ #define PH7_KEYWORD_IF 13 /* if */ #define PH7_KEYWORD_FINAL 14 /* final */