DirectExec and C4ControlScript support executing script expressions that access variables and parameters of the parent context (used for watch expressions while debugging)

Martin Plicht 2010-04-26 22:16:45 +02:00
parent 99cbfecdff
commit 4902679b56
5 changed files with 43 additions and 9 deletions

View File

@ -49,6 +49,8 @@
#include <C4AulDebug.h>
#endif
#include <C4AulExec.h>
// *** C4ControlPacket
C4ControlPacket::C4ControlPacket()
: iByClient(::Control.ClientID())
@ -288,7 +290,7 @@ void C4ControlScript::Execute() const
else
// default: Fallback to global context
pScript = &::ScriptEngine;
C4Value rVal(pScript->DirectExec(pObj, szScript, "console script"));
C4Value rVal(pScript->DirectExec(pObj, szScript, "console script", false, C4AulScript::MAXSTRICT, fUseVarsFromCallerContext ? AulExec.GetContext(AulExec.GetContextDepth()-1) : NULL));
#ifndef NOAULDEBUG
C4AulDebug* pDebug;
if (pDebug = ::ScriptEngine.GetDebugger())
@ -324,6 +326,7 @@ void C4ControlScript::CompileFunc(StdCompiler *pComp)
{
pComp->Value(mkNamingAdapt(iTargetObj, "TargetObj", -1));
pComp->Value(mkNamingAdapt(fInternal, "Internal", false));
pComp->Value(mkNamingAdapt(fUseVarsFromCallerContext, "UseVarsFromCallerContext", false));
pComp->Value(mkNamingAdapt(Script, "Script", ""));
C4ControlPacket::CompileFunc(pComp);
}

View File

@ -140,12 +140,13 @@ public:
C4ControlScript()
: iTargetObj(-1), fInternal(true)
{ }
C4ControlScript(const char *szScript, int32_t iTargetObj = SCOPE_Global, bool fInternal = true)
: iTargetObj(iTargetObj), fInternal(fInternal), Script(szScript, true)
C4ControlScript(const char *szScript, int32_t iTargetObj = SCOPE_Global, bool fInternal = true, bool fUseVarsFromCallerContext = false)
: iTargetObj(iTargetObj), fInternal(fInternal), Script(szScript, true), fUseVarsFromCallerContext(fUseVarsFromCallerContext)
{ }
protected:
int32_t iTargetObj;
bool fInternal; // silent execute
bool fUseVarsFromCallerContext;
StdStrBuf Script;
public:
void SetTargetObj(int32_t iObj) { iTargetObj = iObj; }

View File

@ -145,6 +145,9 @@ enum C4AulBCCType
AB_PAR_V,
AB_FUNC, // function
AB_PARN_CONTEXT,
AB_VARN_CONTEXT,
// prefix
AB_Inc1, // ++
AB_Dec1, // --
@ -472,7 +475,7 @@ protected:
void AddBCC(C4AulBCCType eType, intptr_t = 0, const char * SPos = 0); // add byte code chunk and advance
void ClearCode();
bool Preparse(); // preparse script; return if successfull
void ParseFn(C4AulScriptFunc *Fn, bool fExprOnly = false); // parse single script function
void ParseFn(C4AulScriptFunc *Fn, bool fExprOnly = false, C4AulScriptContext* context = NULL); // parse single script function
bool Parse(); // parse preparsed script; return if successfull
void ParseDescs(); // parse function descs
@ -509,7 +512,7 @@ public:
void AddFunc(const char *pIdtf, C4ScriptFnDef* Def); // add def def func to table
public:
C4Value DirectExec(C4Object *pObj, const char *szScript, const char *szContext, bool fPassErrors = false, enum Strict Strict = MAXSTRICT); // directly parse uncompiled script (WARG! CYCLES!)
C4Value DirectExec(C4Object *pObj, const char *szScript, const char *szContext, bool fPassErrors = false, enum Strict Strict = MAXSTRICT, C4AulScriptContext* context = NULL); // directly parse uncompiled script (WARG! CYCLES!)
void ResetProfilerTimes(); // zero all profiler times of owned functions
void CollectProfilerTimes(class C4AulProfiler &rProfiler);

View File

@ -201,6 +201,14 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
case AB_PARN_V:
PushValue(pCurCtx->Pars[pCPos->Par.i]);
break;
case AB_PARN_CONTEXT:
PushValueRef(AulExec.GetContext(AulExec.GetContextDepth()-2)->Pars[pCPos->Par.i]);
break;
case AB_VARN_CONTEXT:
PushValueRef(AulExec.GetContext(AulExec.GetContextDepth()-2)->Vars[pCPos->Par.i]);
break;
case AB_VARN_R:
PushValueRef(pCurCtx->Vars[pCPos->Par.i]);
@ -1206,7 +1214,7 @@ C4Value C4AulDefFunc::Exec(C4AulContext *pCallerCtx, C4Value pPars[], bool fPass
}
C4Value C4AulScript::DirectExec(C4Object *pObj, const char *szScript, const char *szContext, bool fPassErrors, enum Strict Strict)
C4Value C4AulScript::DirectExec(C4Object *pObj, const char *szScript, const char *szContext, bool fPassErrors, enum Strict Strict, C4AulScriptContext* context)
{
#ifdef DEBUGREC_SCRIPT
AddDbgRec(RCT_DirectExec, szScript, strlen(szScript)+1);
@ -1240,7 +1248,7 @@ C4Value C4AulScript::DirectExec(C4Object *pObj, const char *szScript, const char
// Parse function
try
{
pScript->ParseFn(pFunc, true);
pScript->ParseFn(pFunc, true, context);
}
catch (C4AulError *ex)
{

View File

@ -131,7 +131,8 @@ public:
Type(Type),
fJump(false),
iStack(0),
pLoopStack(NULL)
pLoopStack(NULL),
ContextToExecIn(NULL)
{ }
~C4AulParseState()
{ while (pLoopStack) PopLoop(); ClearToken(); }
@ -142,6 +143,7 @@ public:
long cInt; // current int constant (long for compatibility with x86_64)
bool Done; // done parsing?
enum Type Type; // emitting bytecode?
C4AulScriptContext* ContextToExecIn;
void Parse_Script();
void Parse_FuncHead();
void Parse_Desc();
@ -846,6 +848,9 @@ static const char * GetTTName(C4AulBCCType e)
case AB_PAR_V: return "PAR_V";
case AB_FUNC: return "FUNC"; // function
case AB_PARN_CONTEXT: return "AB_PARN_CONTEXT";
case AB_VARN_CONTEXT: return "AB_VARN_CONTEXT";
// prefix
case AB_Inc1: return "Inc1"; // ++
case AB_Dec1: return "Dec1"; // --
@ -1028,6 +1033,8 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
case AB_LOCALN_V:
case AB_GLOBALN_R:
case AB_GLOBALN_V:
case AB_PARN_CONTEXT:
case AB_VARN_CONTEXT:
iStack++;
break;
@ -1290,7 +1297,7 @@ void C4AulParseState::UnexpectedToken(const char * Expected)
throw new C4AulParseError(this, FormatString("%s expected, but found %s", Expected, GetTokenName(TokenType)).getData());
}
void C4AulScript::ParseFn(C4AulScriptFunc *Fn, bool fExprOnly)
void C4AulScript::ParseFn(C4AulScriptFunc *Fn, bool fExprOnly, C4AulScriptContext* context)
{
// check if fn overloads other fn (all func tables are built now)
// *MUST* check Fn->Owner-list, because it may be the engine (due to linked globals)
@ -1303,6 +1310,7 @@ void C4AulScript::ParseFn(C4AulScriptFunc *Fn, bool fExprOnly)
Fn->Code = (C4AulBCC *) (CPos - Code);
// parse
C4AulParseState state(Fn, this, C4AulParseState::PARSER);
state.ContextToExecIn = context;
// get first token
state.Shift();
if (!fExprOnly)
@ -2299,6 +2307,7 @@ void C4AulParseState::Parse_ForEach()
void C4AulParseState::Parse_Expression(int iParentPrio)
{
int ndx;
switch (TokenType)
{
case ATT_IDTF:
@ -2317,6 +2326,16 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
AddBCC(AB_VARN_R, Fn->VarNamed.GetItemNr(Idtf));
Shift();
}
else if (ContextToExecIn && (ndx = ContextToExecIn->Func->ParNamed.GetItemNr(Idtf)) != -1)
{
AddBCC(AB_PARN_CONTEXT, ndx);
Shift();
}
else if (ContextToExecIn && (ndx = ContextToExecIn->Func->VarNamed.GetItemNr(Idtf)) != -1)
{
AddBCC(AB_VARN_CONTEXT, ndx);
Shift();
}
// check for variable (local)
else if (a->LocalNamed.GetItemNr(Idtf) != -1)
{