forked from Mirrors/openclonk
Modified parser to use setter bytecode in place of references.
Currently kills: * a[...] = ... -> Currently a copy is changed and then discarded, need to rework array semantics. * bla->EffectVar(...) = ... -> Normal EffectVar is rewritten to SetEffectVar - but this won't work for calls. We need a better solution anyway. * All scripts that use references, obviously. Just have a look at the parser warnings.stable-5.1
parent
98c34b4fd3
commit
efb5925129
|
@ -4979,19 +4979,29 @@ static long FnGetEffectCount(C4AulContext *ctx, C4String *psEffectName, C4Object
|
|||
return pEffect->GetCount(szEffect, iMaxPriority);
|
||||
}
|
||||
|
||||
static C4Value FnEffectVar_C4V(C4AulContext *cthr, C4Value *pviVarIndex, C4Value *pvpObj, C4Value *pviEffectNumber)
|
||||
static C4Value FnEffectVar(C4AulContext *cthr, int32_t iVarIndex, C4Object *pObj, int32_t iEffectNumber)
|
||||
{
|
||||
// get parameters
|
||||
C4Object *pObj = pvpObj->getObj();
|
||||
long iVarIndex = pviVarIndex->getInt(), iEffectNumber = pviEffectNumber->getInt();
|
||||
// safety
|
||||
if (iVarIndex<0) return C4Value();
|
||||
// get effect
|
||||
C4Effect *pEffect = pObj ? pObj->pEffects : Game.pGlobalEffects;
|
||||
if (!pEffect) return C4Value();
|
||||
if (!(pEffect = pEffect->Get(iEffectNumber, true))) return C4Value();
|
||||
// return ref to var
|
||||
return pEffect->EffectVars[iVarIndex].GetRef();
|
||||
// return var
|
||||
return pEffect->EffectVars[iVarIndex];
|
||||
}
|
||||
|
||||
static C4Value FnSetEffectVar(C4AulContext *cthr, int32_t iVarIndex, C4Object *pObj, int32_t iEffectNumber, const C4Value &Value)
|
||||
{
|
||||
// safety
|
||||
if (iVarIndex<0) return C4Value();
|
||||
// get effect
|
||||
C4Effect *pEffect = pObj ? pObj->pEffects : Game.pGlobalEffects;
|
||||
if (!pEffect) return C4Value();
|
||||
if (!(pEffect = pEffect->Get(iEffectNumber, true))) return C4Value();
|
||||
// set and return value
|
||||
pEffect->EffectVars[iVarIndex] = Value;
|
||||
return Value;
|
||||
}
|
||||
|
||||
static C4Value FnEffectCall_C4V(C4AulContext *ctx, C4Value *pvpTarget, C4Value *pviNumber, C4Value *pvsCallFn, C4Value *pvVal1, C4Value *pvVal2, C4Value *pvVal3, C4Value *pvVal4, C4Value *pvVal5, C4Value *pvVal6, C4Value *pvVal7)
|
||||
|
@ -6361,6 +6371,8 @@ void InitFunctionMap(C4AulScriptEngine *pEngine)
|
|||
AddFunc(pEngine, "FatalError", FnFatalError, false);
|
||||
AddFunc(pEngine, "ExtractMaterialAmount", FnExtractMaterialAmount);
|
||||
AddFunc(pEngine, "GetEffectCount", FnGetEffectCount);
|
||||
AddFunc(pEngine, "EffectVar", FnEffectVar);
|
||||
AddFunc(pEngine, "SetEffectVar", FnSetEffectVar);
|
||||
AddFunc(pEngine, "PlayVideo", FnPlayVideo);
|
||||
AddFunc(pEngine, "StartCallTrace", FnStartCallTrace);
|
||||
AddFunc(pEngine, "StartScriptProfiler", FnStartScriptProfiler);
|
||||
|
@ -6829,7 +6841,6 @@ C4ScriptFnDef C4ScriptFnMap[]=
|
|||
{ "GetEffect", 1 ,C4V_Any ,{ C4V_String ,C4V_C4Object,C4V_Int ,C4V_Int ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnGetEffect_C4V, 0 },
|
||||
{ "CheckEffect", 1 ,C4V_Int ,{ C4V_String ,C4V_C4Object,C4V_Int ,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnCheckEffect_C4V, 0 },
|
||||
{ "EffectCall", 1 ,C4V_Any ,{ C4V_C4Object,C4V_Int ,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnEffectCall_C4V, 0 },
|
||||
{ "EffectVar", 1 ,C4V_Ref ,{ C4V_Int ,C4V_C4Object,C4V_Int ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,MkFnC4V FnEffectVar_C4V, 0 },
|
||||
|
||||
{ "AttachMesh", 1 ,C4V_Int ,{ C4V_Any ,C4V_String ,C4V_String ,C4V_Array ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any} ,0 , FnAttachMesh },
|
||||
|
||||
|
|
|
@ -130,33 +130,28 @@ struct C4AulParSet
|
|||
// some special script functions defined hard-coded to reduce the exec context
|
||||
enum C4AulBCCType
|
||||
{
|
||||
AB_ARRAYA_R, // array access
|
||||
AB_ARRAYA_V, // not creating a reference
|
||||
AB_ARRAYA, // array or proplist access
|
||||
AB_ARRAYA_SET,
|
||||
AB_ARRAY_SLICE, // array slicing
|
||||
AB_VARN_R, // a named var
|
||||
AB_VARN_V,
|
||||
AB_PARN_R, // a named parameter
|
||||
AB_PARN_V,
|
||||
AB_LOCALN_R, // a named local
|
||||
AB_LOCALN_V,
|
||||
AB_GLOBALN_R, // a named global
|
||||
AB_GLOBALN_V,
|
||||
AB_PAR_R, // Par statement
|
||||
AB_PAR_V,
|
||||
AB_VARN, // a named var
|
||||
AB_VARN_SET,
|
||||
AB_PARN, // a named parameter
|
||||
AB_PARN_SET,
|
||||
AB_LOCALN, // a named local
|
||||
AB_LOCALN_SET,
|
||||
AB_GLOBALN, // a named global
|
||||
AB_GLOBALN_SET,
|
||||
AB_PAR, // Par statement
|
||||
AB_PAR_SET,
|
||||
AB_FUNC, // function
|
||||
|
||||
// prefix
|
||||
AB_Inc1, // ++
|
||||
AB_Dec1, // --
|
||||
AB_Inc, // ++
|
||||
AB_Dec, // --
|
||||
AB_BitNot, // ~
|
||||
AB_Not, // !
|
||||
// +
|
||||
AB_Neg, // -
|
||||
|
||||
// postfix (whithout second statement)
|
||||
AB_Inc1_Postfix, // ++
|
||||
AB_Dec1_Postfix, // --
|
||||
|
||||
// postfix
|
||||
AB_Pow, // **
|
||||
AB_Div, // /
|
||||
|
@ -175,15 +170,6 @@ enum C4AulBCCType
|
|||
AB_BitAnd, // &
|
||||
AB_BitXOr, // ^
|
||||
AB_BitOr, // |
|
||||
AB_MulIt, // *=
|
||||
AB_DivIt, // /=
|
||||
AB_ModIt, // %=
|
||||
AB_Inc, // +=
|
||||
AB_Dec, // -=
|
||||
AB_AndIt, // &=
|
||||
AB_OrIt, // |=
|
||||
AB_XOrIt, // ^=
|
||||
AB_Set, // =
|
||||
|
||||
AB_CALL, // direct object call
|
||||
AB_CALLFS, // failsafe direct call
|
||||
|
@ -194,6 +180,7 @@ enum C4AulBCCType
|
|||
AB_C4ID, // constant: C4ID
|
||||
AB_NIL, // constant: nil
|
||||
AB_ARRAY, // semi-constant: array
|
||||
AB_DUP, // duplicate value from stack
|
||||
AB_PROPLIST, // create a new proplist
|
||||
AB_PROPSET, // set a property of a proplist
|
||||
AB_IVARN, // initialization of named var
|
||||
|
@ -220,7 +207,7 @@ struct C4ScriptOpDef
|
|||
const char* Identifier;
|
||||
C4AulBCCType Code;
|
||||
bool Postfix;
|
||||
bool RightAssociative; // right oder left-associative?
|
||||
bool Changer; // changes first operand to result, rewrite to "a = a (op) b"
|
||||
bool NoSecondStatement; // no second statement expected (++/-- postfix)
|
||||
C4V_Type RetType; // type returned. ignored by C4V
|
||||
C4V_Type Type1;
|
||||
|
@ -470,6 +457,7 @@ protected:
|
|||
C4AulFunc *GetFunc(const char *pIdtf); // get local function by name
|
||||
|
||||
void AddBCC(C4AulBCCType eType, intptr_t = 0, const char * SPos = 0); // add byte code chunk and advance
|
||||
void RemoveLastBCC();
|
||||
void ClearCode();
|
||||
bool Preparse(); // preparse script; return if successfull
|
||||
void ParseFn(C4AulScriptFunc *Fn, bool fExprOnly = false); // parse single script function
|
||||
|
|
|
@ -189,47 +189,50 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
PushValue(C4VNull);
|
||||
break;
|
||||
|
||||
case AB_DUP:
|
||||
PushValue(pCurVal[-pCPos->Par.i+1]);
|
||||
break;
|
||||
|
||||
case AB_EOFN:
|
||||
throw new C4AulExecError(pCurCtx->Obj, "function didn't return");
|
||||
|
||||
case AB_ERR:
|
||||
throw new C4AulExecError(pCurCtx->Obj, "syntax error: see previous parser error for details.");
|
||||
|
||||
case AB_PARN_R:
|
||||
PushValueRef(pCurCtx->Pars[pCPos->Par.i]);
|
||||
break;
|
||||
case AB_PARN_V:
|
||||
case AB_PARN:
|
||||
PushValue(pCurCtx->Pars[pCPos->Par.i]);
|
||||
break;
|
||||
|
||||
case AB_VARN_R:
|
||||
PushValueRef(pCurCtx->Vars[pCPos->Par.i]);
|
||||
case AB_PARN_SET:
|
||||
pCurCtx->Pars[pCPos->Par.i] = pCurVal[0];
|
||||
break;
|
||||
case AB_VARN_V:
|
||||
|
||||
case AB_VARN:
|
||||
PushValue(pCurCtx->Vars[pCPos->Par.i]);
|
||||
break;
|
||||
case AB_LOCALN_R: case AB_LOCALN_V:
|
||||
case AB_VARN_SET:
|
||||
pCurCtx->Vars[pCPos->Par.i] = pCurVal[0];
|
||||
break;
|
||||
|
||||
case AB_LOCALN:
|
||||
if (!pCurCtx->Obj)
|
||||
throw new C4AulExecError(pCurCtx->Obj, "can't access local variables in a definition call!");
|
||||
PushNullVals(1);
|
||||
pCurCtx->Obj->GetPropertyRef(pCPos->Par.s, pCurVal[0]);
|
||||
pCurCtx->Obj->GetPropertyVal(pCPos->Par.s, pCurVal[0]);
|
||||
break;
|
||||
case AB_LOCALN_SET:
|
||||
if (!pCurCtx->Obj)
|
||||
throw new C4AulExecError(pCurCtx->Obj, "can't access local variables in a definition call!");
|
||||
pCurCtx->Obj->SetProperty(pCPos->Par.s, pCurVal[0]);
|
||||
break;
|
||||
|
||||
case AB_GLOBALN_R:
|
||||
PushValueRef(*::ScriptEngine.GlobalNamed.GetItem(pCPos->Par.i));
|
||||
break;
|
||||
case AB_GLOBALN_V:
|
||||
case AB_GLOBALN:
|
||||
PushValue(*::ScriptEngine.GlobalNamed.GetItem(pCPos->Par.i));
|
||||
break;
|
||||
// prefix
|
||||
case AB_Inc1: // ++
|
||||
CheckOpPar2(pCPos->Par.i);
|
||||
++(*pCurVal);
|
||||
break;
|
||||
case AB_Dec1: // --
|
||||
CheckOpPar2(pCPos->Par.i);
|
||||
--(*pCurVal);
|
||||
case AB_GLOBALN_SET:
|
||||
::ScriptEngine.GlobalNamed.GetItem(pCPos->Par.i)->Set(pCurVal[0]);
|
||||
break;
|
||||
|
||||
// prefix
|
||||
case AB_BitNot: // ~
|
||||
CheckOpPar(pCPos->Par.i);
|
||||
pCurVal->SetInt(~pCurVal->_getInt());
|
||||
|
@ -242,14 +245,13 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
CheckOpPar(pCPos->Par.i);
|
||||
pCurVal->SetInt(-pCurVal->_getInt());
|
||||
break;
|
||||
// postfix (whithout second statement)
|
||||
case AB_Inc1_Postfix: // ++
|
||||
CheckOpPar2(pCPos->Par.i);
|
||||
pCurVal->Set((*pCurVal)++);
|
||||
case AB_Inc: // ++
|
||||
CheckOpPar(pCPos->Par.i);
|
||||
(*pCurVal)++;
|
||||
break;
|
||||
case AB_Dec1_Postfix: // --
|
||||
CheckOpPar2(pCPos->Par.i);
|
||||
pCurVal->Set((*pCurVal)--);
|
||||
case AB_Dec: // --
|
||||
CheckOpPar(pCPos->Par.i);
|
||||
(*pCurVal)--;
|
||||
break;
|
||||
// postfix
|
||||
case AB_Pow: // **
|
||||
|
@ -393,130 +395,6 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
PopValue();
|
||||
break;
|
||||
}
|
||||
case AB_MulIt: // *=
|
||||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 *= pPar2 ->_getInt();
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
case AB_DivIt: // /=
|
||||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
if (!pPar2->_getInt())
|
||||
throw new C4AulExecError(pCurCtx->Obj, "Division by zero");
|
||||
*pPar1 /= pPar2->_getInt();
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
case AB_ModIt: // %=
|
||||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
if (!pPar2->_getInt())
|
||||
throw new C4AulExecError(pCurCtx->Obj, "Division by zero");
|
||||
*pPar1 %= pPar2->_getInt();
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
case AB_Inc: // +=
|
||||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 += pPar2 ->_getInt();
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
case AB_Dec: // -=
|
||||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 -= pPar2 ->_getInt();
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
case AB_AndIt: // &=
|
||||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 &= pPar2 ->_getInt();
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
case AB_OrIt: // |=
|
||||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 |= pPar2 ->_getInt();
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
case AB_XOrIt: // ^=
|
||||
{
|
||||
CheckOpPars3(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 ^= pPar2 ->_getInt();
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
case AB_Set: // =
|
||||
{
|
||||
CheckOpPars(pCPos->Par.i);
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
*pPar1 = *pPar2;
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
/* case AB_UNOP:
|
||||
{
|
||||
int iOpID = pCPos->Par.i;
|
||||
|
||||
// Typecheck parameter
|
||||
if(!pCurVal->ConvertTo(C4ScriptOpMap[iOpID].Type1))
|
||||
throw new C4AulExecError(pCurCtx->Obj,
|
||||
FormatString("operator \"%s\": got \"%s\", but expected \"%s\"!",
|
||||
C4ScriptOpMap[iOpID].Identifier, pCurVal->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type1)).getData());
|
||||
|
||||
// Execute operator
|
||||
if(C4ScriptOpMap[iOpID].Function)
|
||||
pCurVal->Set((*C4ScriptOpMap[iOpID].Function)(pCurCtx, pCurVal->_getRaw(), 0), C4ScriptOpMap[iOpID].RetType);
|
||||
else if(C4ScriptOpMap[iOpID].FunctionC4V)
|
||||
pCurVal->Set((*C4ScriptOpMap[iOpID].FunctionC4V)(pCurCtx, pCurVal, NULL));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case AB_BINOP:
|
||||
{
|
||||
int iOpID = pCPos->Par.i;
|
||||
|
||||
// Get parameters
|
||||
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
|
||||
|
||||
// Typecheck parameters
|
||||
if(!pPar1->ConvertTo(C4ScriptOpMap[iOpID].Type1))
|
||||
throw new C4AulExecError(pCurCtx->Obj,
|
||||
FormatString("operator \"%s\" left side: got \"%s\", but expected \"%s\"!",
|
||||
C4ScriptOpMap[iOpID].Identifier, pPar1->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type1)).getData());
|
||||
if(!pPar2->ConvertTo(C4ScriptOpMap[iOpID].Type2))
|
||||
throw new C4AulExecError(pCurCtx->Obj,
|
||||
FormatString("operator \"%s\" right side: got \"%s\", but expected \"%s\"!",
|
||||
C4ScriptOpMap[iOpID].Identifier, pPar2->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type2)).getData());
|
||||
|
||||
// Execute operator
|
||||
if(C4ScriptOpMap[iOpID].Function)
|
||||
pPar1->Set((*C4ScriptOpMap[iOpID].Function)(pCurCtx, pPar1->_getRaw(), pPar2->_getRaw()),C4ScriptOpMap[iOpID].RetType);
|
||||
else if(C4ScriptOpMap[iOpID].FunctionC4V)
|
||||
pPar1->Set((*C4ScriptOpMap[iOpID].FunctionC4V)(pCurCtx, pPar1, pPar2));
|
||||
|
||||
// Pop second parameter
|
||||
PopValue();
|
||||
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case AB_ARRAY:
|
||||
{
|
||||
// Create array
|
||||
|
@ -555,42 +433,47 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
break;
|
||||
}
|
||||
|
||||
case AB_ARRAYA_R: case AB_ARRAYA_V:
|
||||
case AB_ARRAYA:
|
||||
{
|
||||
C4Value &Index = pCurVal[0];
|
||||
C4Value &Array = pCurVal[-1].GetRefVal();
|
||||
// Typcheck
|
||||
if ((!Array.ConvertTo(C4V_Array) && !Array.ConvertTo(C4V_PropList)) || Array.GetType() == C4V_Any)
|
||||
throw new C4AulExecError(pCurCtx->Obj, FormatString("array access: can't access %s as an array!", Array.GetTypeName()).getData());
|
||||
else if (Array.GetType() == C4V_Array)
|
||||
C4Value *pIndex = pCurVal, *pStruct = pCurVal - 1, *pResult = pCurVal - 1;
|
||||
// Typcheck to determine whether it's an array or a proplist
|
||||
if(CheckArrayAccess(pStruct, pIndex) == C4V_Array)
|
||||
{
|
||||
if (!Index.ConvertTo(C4V_Int))
|
||||
throw new C4AulExecError(pCurCtx->Obj, FormatString("array access: index of type %s, int expected!", Index.GetTypeName()).getData());
|
||||
// Set reference to array element
|
||||
Array.GetArrayElement(Index._getInt(), pCurVal[-1], pCurCtx, pCPos->bccType == AB_ARRAYA_V);
|
||||
pStruct->GetArrayElement(pIndex->_getInt(), *pResult, pCurCtx, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Index.ConvertTo(C4V_String))
|
||||
throw new C4AulExecError(pCurCtx->Obj, FormatString("proplist access: index of type %s, string expected!", Index.GetTypeName()).getData());
|
||||
C4PropList *proplist = Array.getPropList();
|
||||
assert(proplist);
|
||||
if (pCPos->bccType == AB_ARRAYA_V)
|
||||
{
|
||||
if (!proplist->GetPropertyVal(Index._getStr(), pCurVal[-1]))
|
||||
{
|
||||
pCurVal[-1].Set0();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
proplist->GetPropertyRef(Index._getStr(), pCurVal[-1]);
|
||||
}
|
||||
C4PropList *pPropList = pStruct->getPropList();
|
||||
assert(pPropList);
|
||||
if (!pPropList->GetPropertyVal(pIndex->_getStr(), *pResult))
|
||||
pResult->Set0();
|
||||
}
|
||||
// Remove index
|
||||
PopValue();
|
||||
break;
|
||||
}
|
||||
case AB_ARRAYA_SET:
|
||||
{
|
||||
C4Value *pValue = pCurVal, *pIndex = pCurVal - 1, *pStruct = pCurVal - 2, *pResult = pCurVal - 2;
|
||||
// Typcheck to determine whether it's an array or a proplist
|
||||
if(CheckArrayAccess(pStruct, pIndex) == C4V_Array)
|
||||
{
|
||||
// TODO: Does not work, because array gets copied here!
|
||||
C4Value Ref;
|
||||
pStruct->GetArrayElement(pIndex->_getInt(), Ref, pCurCtx, false);
|
||||
Ref.getRef()->Set(*pValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
C4PropList *pPropList = pStruct->getPropList();
|
||||
assert(pPropList);
|
||||
pPropList->SetProperty(pIndex->_getStr(), *pValue);
|
||||
}
|
||||
// Set result, remove array and index from stack
|
||||
*pResult = *pValue;
|
||||
PopValues(2);
|
||||
break;
|
||||
}
|
||||
case AB_ARRAY_SLICE:
|
||||
{
|
||||
C4Value &Array = pCurVal[-2];
|
||||
|
@ -731,17 +614,12 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
break;
|
||||
}
|
||||
|
||||
case AB_PAR_R: case AB_PAR_V:
|
||||
case AB_PAR:
|
||||
if (!pCurVal->ConvertTo(C4V_Int))
|
||||
throw new C4AulExecError(pCurCtx->Obj, FormatString("Par: index of type %s, int expected!", pCurVal->GetTypeName()).getData());
|
||||
// Push reference to parameter on the stack
|
||||
if (pCurVal->_getInt() >= 0 && pCurVal->_getInt() < pCurCtx->ParCnt())
|
||||
{
|
||||
if (pCPos->bccType == AB_PAR_R)
|
||||
pCurVal->SetRef(&pCurCtx->Pars[pCurVal->_getInt()]);
|
||||
else
|
||||
pCurVal->Set(pCurCtx->Pars[pCurVal->_getInt()]);
|
||||
}
|
||||
pCurVal->Set(pCurCtx->Pars[pCurVal->_getInt()]);
|
||||
else
|
||||
pCurVal->Set0();
|
||||
break;
|
||||
|
|
|
@ -141,18 +141,6 @@ private:
|
|||
FormatString("operator \"%s\" right side: got \"%s\", but expected \"%s\"!",
|
||||
C4ScriptOpMap[iOpID].Identifier, pPar2->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type2)).getData());
|
||||
}
|
||||
void CheckOpPars3(int iOpID)
|
||||
{
|
||||
CheckOpPars(iOpID);
|
||||
// Get parameters
|
||||
C4Value *pPar1 = pCurVal - 1;
|
||||
|
||||
// check that the the first parameter references an int, not something else
|
||||
if (!pPar1->GetRefVal().ConvertTo(C4V_Int))
|
||||
throw new C4AulExecError(pCurCtx->Obj,
|
||||
FormatString("operator \"%s\" left side: got reference to \"%s\", but expected reference to \"%s\"!",
|
||||
C4ScriptOpMap[iOpID].Identifier, pPar1->GetRefVal().GetTypeInfo(), GetC4VName(C4V_Int)).getData());
|
||||
}
|
||||
void CheckOpPar(int iOpID)
|
||||
{
|
||||
// Typecheck parameter
|
||||
|
@ -161,16 +149,23 @@ private:
|
|||
FormatString("operator \"%s\": got \"%s\", but expected \"%s\"!",
|
||||
C4ScriptOpMap[iOpID].Identifier, pCurVal->GetTypeInfo(), GetC4VName(C4ScriptOpMap[iOpID].Type1)).getData());
|
||||
}
|
||||
void CheckOpPar2(int iOpID)
|
||||
{
|
||||
CheckOpPar(iOpID);
|
||||
C4Value *pPar1 = pCurVal;
|
||||
|
||||
// check that the the first parameter references an int, not something else
|
||||
if (!pPar1->GetRefVal().ConvertTo(C4V_Int))
|
||||
throw new C4AulExecError(pCurCtx->Obj,
|
||||
FormatString("operator \"%s\": got reference to \"%s\", but expected reference to \"%s\"!",
|
||||
C4ScriptOpMap[iOpID].Identifier, pPar1->GetRefVal().GetTypeInfo(), GetC4VName(C4V_Int)).getData());
|
||||
C4V_Type CheckArrayAccess(C4Value *pStructure, C4Value *pIndex)
|
||||
{
|
||||
if (pStructure->ConvertTo(C4V_Array) && pStructure->GetType() != C4V_Any)
|
||||
{
|
||||
if (!pIndex->ConvertTo(C4V_Int))
|
||||
throw new C4AulExecError(pCurCtx->Obj, FormatString("array access: index of type %s, int expected!", pIndex->GetTypeName()).getData());
|
||||
return C4V_Array;
|
||||
}
|
||||
else if (pStructure->ConvertTo(C4V_PropList) && pStructure->GetType() != C4V_Any)
|
||||
{
|
||||
if (!pIndex->ConvertTo(C4V_String))
|
||||
throw new C4AulExecError(pCurCtx->Obj, FormatString("proplist access: index of type %s, string expected!", pIndex->GetTypeName()).getData());
|
||||
return C4V_PropList;
|
||||
}
|
||||
else
|
||||
throw new C4AulExecError(pCurCtx->Obj, FormatString("can't access %s as array or proplist!", pStructure->GetTypeName()).getData());
|
||||
}
|
||||
C4AulBCC *Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4Object *pObj = NULL, C4Def *pDef = NULL);
|
||||
};
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
#define C4AUL_If "if"
|
||||
#define C4AUL_Else "else"
|
||||
#define C4AUL_Do "do"
|
||||
#define C4AUL_Do "do"
|
||||
#define C4AUL_While "while"
|
||||
#define C4AUL_For "for"
|
||||
#define C4AUL_In "in"
|
||||
|
@ -116,6 +116,7 @@ enum C4AulTokenType
|
|||
ATT_AMP, // "&"
|
||||
ATT_TILDE, // '~'
|
||||
ATT_LDOTS, // '...'
|
||||
ATT_SET, // '='
|
||||
ATT_OPERATOR,// operator
|
||||
ATT_EOF // end of file
|
||||
};
|
||||
|
@ -183,9 +184,11 @@ private:
|
|||
bool fJump;
|
||||
int iStack;
|
||||
|
||||
int GetStackValue(C4AulBCCType eType, intptr_t X = 0);
|
||||
void AddBCC(C4AulBCCType eType, intptr_t X = 0);
|
||||
void RemoveLastBCC();
|
||||
|
||||
void SetNoRef(); // Switches the bytecode to generate a value instead of a reference
|
||||
C4AulBCC MakeSetter(bool fLeaveValue = false); // Prepares to generate a setter for the last value that was generated
|
||||
|
||||
int JumpHere(); // Get position for a later jump to next instruction added
|
||||
void SetJumpHere(int iJumpOp); // Use the next inserted instruction as jump target for the given jump operation
|
||||
|
@ -417,22 +420,22 @@ bool C4AulParseState::AdvanceSpaces()
|
|||
C4ScriptOpDef C4ScriptOpMap[] =
|
||||
{
|
||||
// priority postfix
|
||||
// | identifier | right-associative
|
||||
// | identifier | changer
|
||||
// | | Bytecode | | no second id
|
||||
// | | | | | | RetType ParType1 ParType2
|
||||
// prefix
|
||||
{ 15, "++", AB_Inc1, 0, 1, 0, C4V_Int, C4V_Ref, C4V_Any},
|
||||
{ 15, "--", AB_Dec1, 0, 1, 0, C4V_Int, C4V_Ref, C4V_Any},
|
||||
{ 15, "~", AB_BitNot, 0, 1, 0, C4V_Int, C4V_Int, C4V_Any},
|
||||
{ 15, "!", AB_Not, 0, 1, 0, C4V_Bool, C4V_Bool, C4V_Any},
|
||||
{ 15, "+", AB_ERR, 0, 1, 0, C4V_Int, C4V_Int, C4V_Any},
|
||||
{ 15, "-", AB_Neg, 0, 1, 0, C4V_Int, C4V_Int, C4V_Any},
|
||||
|
||||
{ 15, "++", AB_Inc, 0, 1, 0, C4V_Int, C4V_Int, C4V_Any},
|
||||
{ 15, "--", AB_Dec, 0, 1, 0, C4V_Int, C4V_Int, C4V_Any},
|
||||
{ 15, "~", AB_BitNot, 0, 0, 0, C4V_Int, C4V_Int, C4V_Any},
|
||||
{ 15, "!", AB_Not, 0, 0, 0, C4V_Bool, C4V_Bool, C4V_Any},
|
||||
{ 15, "+", AB_ERR, 0, 0, 0, C4V_Int, C4V_Int, C4V_Any},
|
||||
{ 15, "-", AB_Neg, 0, 0, 0, C4V_Int, C4V_Int, C4V_Any},
|
||||
|
||||
// postfix (whithout second statement)
|
||||
{ 16, "++", AB_Inc1_Postfix, 1, 1, 1, C4V_Int, C4V_Ref, C4V_Any},
|
||||
{ 16, "--", AB_Dec1_Postfix, 1, 1, 1, C4V_Int, C4V_Ref, C4V_Any},
|
||||
|
||||
// postfix
|
||||
{ 16, "++", AB_Inc, 1, 1, 1, C4V_Int, C4V_Int, C4V_Any},
|
||||
{ 16, "--", AB_Dec, 1, 1, 1, C4V_Int, C4V_Int, C4V_Any},
|
||||
|
||||
// postfix
|
||||
{ 14, "**", AB_Pow, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 13, "/", AB_Div, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 13, "*", AB_Mul, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
|
@ -452,16 +455,17 @@ C4ScriptOpDef C4ScriptOpMap[] =
|
|||
{ 6, "|", AB_BitOr, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 5, "&&", AB_JUMPAND, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool},
|
||||
{ 4, "||", AB_JUMPOR, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool},
|
||||
{ 2, "*=", AB_MulIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "/=", AB_DivIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "%=", AB_ModIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "+=", AB_Inc, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "-=", AB_Dec, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "&=", AB_AndIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "|=", AB_OrIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "^=", AB_XOrIt, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Int},
|
||||
{ 2, "=", AB_Set, 1, 1, 0, C4V_Ref, C4V_Ref, C4V_Any},
|
||||
|
||||
// changers
|
||||
{ 2, "*=", AB_Mul, 1, 1, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 2, "/=", AB_Div, 1, 1, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 2, "%=", AB_Mod, 1, 1, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 2, "+=", AB_Sum, 1, 1, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 2, "-=", AB_Sub, 1, 1, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 2, "&=", AB_BitAnd, 1, 1, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 2, "|=", AB_BitOr, 1, 1, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
{ 2, "^=", AB_BitXOr, 1, 1, 0, C4V_Int, C4V_Int, C4V_Int},
|
||||
|
||||
{ 0, NULL, AB_ERR, 0, 0, 0, C4V_Any, C4V_Any, C4V_Any}
|
||||
};
|
||||
|
||||
|
@ -636,6 +640,12 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
|
|||
SPos += SLen(C4ScriptOpMap[iOpID].Identifier);
|
||||
return ATT_OPERATOR;
|
||||
}
|
||||
// set?
|
||||
if (*SPos == '=')
|
||||
{
|
||||
SPos++;
|
||||
return ATT_SET;
|
||||
}
|
||||
}
|
||||
else if (C == '*') { SPos++; return ATT_STAR; } // "*"
|
||||
else if (C == '&') { SPos++; return ATT_AMP; } // "&"
|
||||
|
@ -831,33 +841,28 @@ static const char * GetTTName(C4AulBCCType e)
|
|||
{
|
||||
switch (e)
|
||||
{
|
||||
case AB_ARRAYA_R: return "ARRAYA_R"; // array access
|
||||
case AB_ARRAYA_V: return "ARRAYA_V"; // not creating a reference
|
||||
case AB_ARRAYA: return "ARRAYA"; // array access
|
||||
case AB_ARRAYA_SET: return "ARRAYA_SET"; // setter
|
||||
case AB_ARRAY_SLICE: return "ARRAY_SLICE";
|
||||
case AB_VARN_R: return "VARN_R"; // a named var
|
||||
case AB_VARN_V: return "VARN_V";
|
||||
case AB_PARN_R: return "PARN_R"; // a named parameter
|
||||
case AB_PARN_V: return "PARN_V";
|
||||
case AB_LOCALN_R: return "LOCALN_R"; // a named local
|
||||
case AB_LOCALN_V: return "LOCALN_V";
|
||||
case AB_GLOBALN_R: return "GLOBALN_R"; // a named global
|
||||
case AB_GLOBALN_V: return "GLOBALN_V";
|
||||
case AB_PAR_R: return "PAR_R"; // Par statement
|
||||
case AB_PAR_V: return "PAR_V";
|
||||
case AB_VARN: return "VARN"; // a named var
|
||||
case AB_VARN_SET: return "VARN_SET";
|
||||
case AB_PARN: return "PARN"; // a named parameter
|
||||
case AB_PARN_SET: return "PARN_SET";
|
||||
case AB_LOCALN: return "LOCALN"; // a named local
|
||||
case AB_LOCALN_SET: return "LOCALN_SET";
|
||||
case AB_GLOBALN: return "GLOBALN"; // a named global
|
||||
case AB_GLOBALN_SET: return "GLOBALN_SET";
|
||||
case AB_PAR: return "PAR"; // Par statement
|
||||
case AB_PAR_SET: return "PAR_SET";
|
||||
case AB_FUNC: return "FUNC"; // function
|
||||
|
||||
// prefix
|
||||
case AB_Inc1: return "Inc1"; // ++
|
||||
case AB_Dec1: return "Dec1"; // --
|
||||
case AB_Inc: return "Inc"; // ++
|
||||
case AB_Dec: return "Dec"; // --
|
||||
case AB_BitNot: return "BitNot"; // ~
|
||||
case AB_Not: return "Not"; // !
|
||||
// +
|
||||
case AB_Neg: return "Neg"; // -
|
||||
|
||||
// postfix (whithout second statement)
|
||||
case AB_Inc1_Postfix: return "Inc1_Postfix"; // ++
|
||||
case AB_Dec1_Postfix: return "Dec1_Postfix"; // --
|
||||
|
||||
// postfix
|
||||
case AB_Pow: return "Pow"; // **
|
||||
case AB_Div: return "Div"; // /
|
||||
|
@ -876,15 +881,6 @@ static const char * GetTTName(C4AulBCCType e)
|
|||
case AB_BitAnd: return "BitAnd"; // &
|
||||
case AB_BitXOr: return "BitXOr"; // ^
|
||||
case AB_BitOr: return "BitOr"; // |
|
||||
case AB_MulIt: return "MulIt"; // *=
|
||||
case AB_DivIt: return "DivIt"; // /=
|
||||
case AB_ModIt: return "ModIt"; // %=
|
||||
case AB_Inc: return "Inc"; // +=
|
||||
case AB_Dec: return "Dec"; // -=
|
||||
case AB_AndIt: return "AndIt"; // &=
|
||||
case AB_OrIt: return "OrIt"; // |=
|
||||
case AB_XOrIt: return "XOrIt"; // ^=
|
||||
case AB_Set: return "Set"; // =
|
||||
|
||||
case AB_CALL: return "CALL"; // direct object call
|
||||
case AB_CALLFS: return "CALLFS"; // failsafe direct call
|
||||
|
@ -894,6 +890,7 @@ static const char * GetTTName(C4AulBCCType e)
|
|||
case AB_STRING: return "STRING"; // constant: string
|
||||
case AB_C4ID: return "C4ID"; // constant: C4ID
|
||||
case AB_NIL: return "NIL"; // constant: nil
|
||||
case AB_DUP: return "DUP"; // constant: nil
|
||||
case AB_ARRAY: return "ARRAY"; // semi-constant: array
|
||||
case AB_PROPLIST: return "PROPLIST"; // semi-constant: array
|
||||
case AB_PROPSET: return "PROPSET";
|
||||
|
@ -935,7 +932,8 @@ void C4AulScript::AddBCC(C4AulBCCType eType, intptr_t X, const char * SPos)
|
|||
CPos->SPos = SPos;
|
||||
switch (eType)
|
||||
{
|
||||
case AB_STRING: case AB_CALL: case AB_CALLFS: case AB_LOCALN_R: case AB_LOCALN_V:
|
||||
case AB_STRING: case AB_CALL: case AB_CALLFS: case AB_LOCALN:
|
||||
/* case AB_LOCALN_SET: -- expected to already have a reference upon creation, see MakeSetter */
|
||||
CPos->Par.s->IncRef();
|
||||
break;
|
||||
default:
|
||||
|
@ -945,20 +943,24 @@ void C4AulScript::AddBCC(C4AulBCCType eType, intptr_t X, const char * SPos)
|
|||
CPos++; CodeSize++;
|
||||
}
|
||||
|
||||
void C4AulScript::RemoveLastBCC()
|
||||
{
|
||||
C4AulBCC *pBCC = Code + CodeSize - 1;
|
||||
switch (pBCC->bccType)
|
||||
{
|
||||
case AB_STRING: case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_LOCALN_SET:
|
||||
pBCC->Par.s->DecRef();
|
||||
break;
|
||||
default: break; // I don't want to do anything, thank you very much. Stupid warnings.
|
||||
}
|
||||
CodeSize--;
|
||||
CPos--;
|
||||
}
|
||||
|
||||
void C4AulScript::ClearCode()
|
||||
{
|
||||
for (int i = 0; i < CodeSize; ++i)
|
||||
{
|
||||
switch (Code[i].bccType)
|
||||
{
|
||||
case AB_STRING: case AB_CALL: case AB_CALLFS: case AB_LOCALN_R: case AB_LOCALN_V:
|
||||
Code[i].Par.s->DecRef();
|
||||
break;
|
||||
default:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(CodeSize > 0)
|
||||
RemoveLastBCC();
|
||||
delete[] Code;
|
||||
Code = 0;
|
||||
CodeSize = CodeBufSize = 0;
|
||||
|
@ -1008,10 +1010,9 @@ bool C4AulScript::Preparse()
|
|||
return true;
|
||||
}
|
||||
|
||||
void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
||||
|
||||
int C4AulParseState::GetStackValue(C4AulBCCType eType, intptr_t X)
|
||||
{
|
||||
if (Type != PARSER) return;
|
||||
// Track stack size
|
||||
switch (eType)
|
||||
{
|
||||
case AB_INT:
|
||||
|
@ -1020,16 +1021,12 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
case AB_C4ID:
|
||||
case AB_PROPLIST:
|
||||
case AB_NIL:
|
||||
case AB_VARN_R:
|
||||
case AB_VARN_V:
|
||||
case AB_PARN_R:
|
||||
case AB_PARN_V:
|
||||
case AB_LOCALN_R:
|
||||
case AB_LOCALN_V:
|
||||
case AB_GLOBALN_R:
|
||||
case AB_GLOBALN_V:
|
||||
iStack++;
|
||||
break;
|
||||
case AB_VARN:
|
||||
case AB_PARN:
|
||||
case AB_LOCALN:
|
||||
case AB_GLOBALN:
|
||||
case AB_DUP:
|
||||
return 1;
|
||||
|
||||
case AB_Pow:
|
||||
case AB_Div:
|
||||
|
@ -1048,17 +1045,7 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
case AB_BitAnd:
|
||||
case AB_BitXOr:
|
||||
case AB_BitOr:
|
||||
case AB_MulIt:
|
||||
case AB_DivIt:
|
||||
case AB_ModIt:
|
||||
case AB_Inc:
|
||||
case AB_Dec:
|
||||
case AB_AndIt:
|
||||
case AB_OrIt:
|
||||
case AB_XOrIt:
|
||||
case AB_Set:
|
||||
case AB_ARRAYA_R:
|
||||
case AB_ARRAYA_V:
|
||||
case AB_ARRAYA:
|
||||
case AB_CONDN:
|
||||
case AB_COND:
|
||||
case AB_IVARN:
|
||||
|
@ -1067,51 +1054,57 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
// or decrement the stack. Thus, for stack counting purposes, they decrement.
|
||||
case AB_JUMPAND:
|
||||
case AB_JUMPOR:
|
||||
iStack--;
|
||||
break;
|
||||
return -1;
|
||||
|
||||
case AB_FUNC:
|
||||
iStack-= reinterpret_cast<C4AulFunc *>(X)->GetParCount() - 1;
|
||||
break;
|
||||
return -reinterpret_cast<C4AulFunc *>(X)->GetParCount() + 1;
|
||||
|
||||
case AB_CALL:
|
||||
case AB_CALLFS:
|
||||
iStack-=C4AUL_MAX_Par;
|
||||
break;
|
||||
return -C4AUL_MAX_Par;
|
||||
|
||||
case AB_Inc1:
|
||||
case AB_Dec1:
|
||||
case AB_VARN_SET:
|
||||
case AB_PARN_SET:
|
||||
case AB_LOCALN_SET:
|
||||
case AB_GLOBALN_SET:
|
||||
case AB_PAR_SET:
|
||||
case AB_Inc:
|
||||
case AB_Dec:
|
||||
case AB_BitNot:
|
||||
case AB_Not:
|
||||
case AB_Neg:
|
||||
case AB_Inc1_Postfix:
|
||||
case AB_Dec1_Postfix:
|
||||
case AB_PAR_R:
|
||||
case AB_PAR_V:
|
||||
case AB_PAR:
|
||||
case AB_FOREACH_NEXT:
|
||||
case AB_ERR:
|
||||
case AB_EOFN:
|
||||
case AB_EOF:
|
||||
case AB_JUMP:
|
||||
case AB_DEBUG:
|
||||
break;
|
||||
return 0;
|
||||
|
||||
case AB_STACK:
|
||||
iStack+=X;
|
||||
break;
|
||||
return X;
|
||||
|
||||
case AB_ARRAY:
|
||||
iStack-=X-1;
|
||||
break;
|
||||
return -X+1;
|
||||
|
||||
case AB_ARRAYA_SET:
|
||||
case AB_ARRAY_SLICE:
|
||||
case AB_PROPSET:
|
||||
iStack -= 2;
|
||||
break;
|
||||
return -2;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
||||
{
|
||||
if (Type != PARSER) return;
|
||||
|
||||
// Track stack size
|
||||
iStack += GetStackValue(eType, X);
|
||||
|
||||
// Use stack operation instead of 0-Any (enable optimization)
|
||||
if (eType == AB_NIL)
|
||||
|
@ -1121,24 +1114,40 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
}
|
||||
|
||||
// Join checks only if it's not a jump target
|
||||
if (!fJump)
|
||||
if (!fJump && a->CPos > a->Code)
|
||||
{
|
||||
|
||||
// Join together stack operations
|
||||
if (eType == AB_STACK &&
|
||||
a->CPos > a->Code &&
|
||||
(a->CPos-1)->bccType == AB_STACK
|
||||
&& (X <= 0 || (a->CPos-1)->Par.i >= 0))
|
||||
C4AulBCC *pCPos1 = a->CPos - 1;
|
||||
if(eType == AB_STACK && pCPos1->bccType == AB_STACK &&
|
||||
(X <= 0 || pCPos1->Par.i >= 0))
|
||||
{
|
||||
(a->CPos-1)->Par.i += X;
|
||||
pCPos1->Par.i += X;
|
||||
// Empty? Remove it.
|
||||
if (!(a->CPos-1)->Par.i)
|
||||
{
|
||||
a->CPos--;
|
||||
a->CodeSize--;
|
||||
}
|
||||
if (!pCPos1->Par.i)
|
||||
a->RemoveLastBCC();
|
||||
return;
|
||||
}
|
||||
|
||||
// Join VARN_SET + STACK -1 to IVARN (equivalent)
|
||||
if(eType == AB_STACK && X == -1 && pCPos1->bccType == AB_VARN_SET)
|
||||
{
|
||||
pCPos1->bccType = AB_IVARN;
|
||||
return;
|
||||
}
|
||||
|
||||
// Reduce some constructs like SUM + INT 1 to INC or DEC
|
||||
if((eType == AB_Sum || eType == AB_Sub) &&
|
||||
pCPos1->bccType == AB_INT &&
|
||||
(pCPos1->Par.i == 1 || pCPos1->Par.i == -1))
|
||||
{
|
||||
if((pCPos1->Par.i > 0) == (eType == AB_Sum))
|
||||
pCPos1->bccType = AB_Inc;
|
||||
else
|
||||
pCPos1->bccType = AB_Dec;
|
||||
pCPos1->Par.i = X;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add
|
||||
|
@ -1148,20 +1157,64 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
fJump = false;
|
||||
}
|
||||
|
||||
void C4AulParseState::SetNoRef()
|
||||
void C4AulParseState::RemoveLastBCC()
|
||||
{
|
||||
if (Type != PARSER) return;
|
||||
C4AulBCC * CPos = a->CPos - 1;
|
||||
switch (CPos->bccType)
|
||||
// Security: This is unsafe on anything that might get optimized away
|
||||
C4AulBCC *pBCC = a->CPos-1;
|
||||
assert(pBCC->bccType != AB_STACK);
|
||||
// Correct stack
|
||||
iStack -= GetStackValue(pBCC->bccType, pBCC->Par.i);
|
||||
// Remove
|
||||
a->RemoveLastBCC();
|
||||
}
|
||||
|
||||
C4AulBCC C4AulParseState::MakeSetter(bool fLeaveValue)
|
||||
{
|
||||
if(Type != PARSER) { C4AulBCC Dummy; Dummy.bccType = AB_ERR; return Dummy; }
|
||||
C4AulBCC Value = *(a->CPos - 1), Setter = Value;
|
||||
// Check type
|
||||
switch (Value.bccType)
|
||||
{
|
||||
case AB_ARRAYA_R: CPos->bccType = AB_ARRAYA_V; break;
|
||||
case AB_PAR_R: CPos->bccType = AB_PAR_V; break;
|
||||
case AB_PARN_R: CPos->bccType = AB_PARN_V; break;
|
||||
case AB_VARN_R: CPos->bccType = AB_VARN_V; break;
|
||||
case AB_LOCALN_R: CPos->bccType = AB_LOCALN_V; break;
|
||||
case AB_GLOBALN_R: CPos->bccType = AB_GLOBALN_V; break;
|
||||
default: break;
|
||||
case AB_ARRAYA: Setter.bccType = AB_ARRAYA_SET; break;
|
||||
case AB_PAR: Setter.bccType = AB_PAR_SET; break;
|
||||
case AB_PARN: Setter.bccType = AB_PARN_SET; break;
|
||||
case AB_VARN: Setter.bccType = AB_VARN_SET; break;
|
||||
case AB_LOCALN:
|
||||
Setter.bccType = AB_LOCALN_SET;
|
||||
Setter.Par.s->IncRef(); // so string isn't dropped by RemoveLastBCC, see also C4AulScript::AddBCC
|
||||
break;
|
||||
case AB_GLOBALN: Setter.bccType = AB_GLOBALN_SET; break;
|
||||
case AB_CALL:
|
||||
// Huge hacks would required to make this work. EffectVar should get the Var treatment
|
||||
// and become a BCC of its own anyway.
|
||||
throw new C4AulParseError(this, "EffectVar call not supported right now, sorry!");
|
||||
case AB_FUNC:
|
||||
// This one at least works somewhat
|
||||
if(SEqual(Value.Par.f->Name, "EffectVar"))
|
||||
{
|
||||
Setter.Par.f = a->GetFuncRecursive("SetEffectVar");
|
||||
break;
|
||||
}
|
||||
// falthru
|
||||
default:
|
||||
throw new C4AulParseError(this, "assignment not possible for this value!");
|
||||
}
|
||||
// Remove value BCC
|
||||
RemoveLastBCC();
|
||||
// Want the value?
|
||||
if(fLeaveValue)
|
||||
{
|
||||
// Duplicate parameters on stack
|
||||
// (all push one value on the stack as result, so we have -(N-1) parameters)
|
||||
int iParCount = -GetStackValue(Value.bccType, Value.Par.i) + 1;
|
||||
for(int i = 0; i < iParCount; i++)
|
||||
AddBCC(AB_DUP, iParCount);
|
||||
// Finally re-add original BCC
|
||||
AddBCC(Value.bccType, Value.Par.i);
|
||||
}
|
||||
// Done. The returned BCC should be added later once the value to be set was pushed on top.
|
||||
assert(GetStackValue(Value.bccType, Value.Par.i) == GetStackValue(Setter.bccType, Setter.Par.i)+1);
|
||||
return Setter;
|
||||
}
|
||||
|
||||
int C4AulParseState::JumpHere()
|
||||
|
@ -1703,6 +1756,7 @@ void C4AulParseState::Parse_Statement()
|
|||
}
|
||||
case ATT_BOPEN:
|
||||
case ATT_BOPEN2:
|
||||
case ATT_SET:
|
||||
case ATT_OPERATOR:
|
||||
case ATT_INT: // constant in cInt
|
||||
case ATT_BOOL: // constant in cInt
|
||||
|
@ -1710,7 +1764,6 @@ void C4AulParseState::Parse_Statement()
|
|||
case ATT_C4ID: // converted ID in cInt
|
||||
{
|
||||
Parse_Expression();
|
||||
SetNoRef();
|
||||
AddBCC(AB_STACK, -1);
|
||||
Match(ATT_SCOLON);
|
||||
return;
|
||||
|
@ -1815,8 +1868,6 @@ void C4AulParseState::Parse_Statement()
|
|||
// return retval;
|
||||
Parse_Expression();
|
||||
}
|
||||
if (!Fn->bReturnRef)
|
||||
SetNoRef();
|
||||
AddBCC(AB_RETURN);
|
||||
}
|
||||
else if (SEqual(Idtf, C4AUL_Break)) // break
|
||||
|
@ -1862,7 +1913,6 @@ void C4AulParseState::Parse_Statement()
|
|||
else
|
||||
{
|
||||
Parse_Expression();
|
||||
SetNoRef();
|
||||
AddBCC(AB_STACK, -1);
|
||||
}
|
||||
Match(ATT_SCOLON);
|
||||
|
@ -1912,7 +1962,7 @@ int C4AulParseState::Parse_Params(int iMaxCnt, const char * sWarn, C4AulFunc * p
|
|||
int i = Fn->ParNamed.iSize;
|
||||
while (size < iMaxCnt && i < C4AUL_MAX_Par)
|
||||
{
|
||||
AddBCC(AB_PARN_R, i);
|
||||
AddBCC(AB_PARN, i);
|
||||
++i;
|
||||
++size;
|
||||
}
|
||||
|
@ -1927,15 +1977,6 @@ int C4AulParseState::Parse_Params(int iMaxCnt, const char * sWarn, C4AulFunc * p
|
|||
Parse_Expression();
|
||||
if (pFunc && (Type == PARSER))
|
||||
{
|
||||
bool anyfunctakesref = (pFunc->GetParType()[size] == C4V_Ref);
|
||||
// pFunc either was the return value from a GetFirstFunc-Call or
|
||||
// pFunc is the only function that could be called, so this loop is superflous
|
||||
C4AulFunc * pFunc2 = pFunc;
|
||||
while ((pFunc2 = a->Engine->GetNextSNFunc(pFunc2)))
|
||||
if (pFunc2->GetParType()[size] == C4V_Ref) anyfunctakesref = true;
|
||||
// Change the bytecode to the equivalent that does not produce a reference.
|
||||
if (!anyfunctakesref)
|
||||
SetNoRef();
|
||||
C4V_Type from = C4V_Any;
|
||||
C4V_Type to = pFunc->GetParType()[size];
|
||||
switch ((a->CPos-1)->bccType)
|
||||
|
@ -1944,7 +1985,6 @@ int C4AulParseState::Parse_Params(int iMaxCnt, const char * sWarn, C4AulFunc * p
|
|||
case AB_STRING: from = C4V_String; break;
|
||||
case AB_ARRAY: case AB_ARRAY_SLICE: from = C4V_Array; break;
|
||||
case AB_BOOL: from = C4V_Bool; break;
|
||||
// case AB_UNOP: case AB_BINOP: from = C4ScriptOpMap[(a->CPos-1)->Par.i].RetType; break;
|
||||
case AB_FUNC:
|
||||
if ((a->CPos-1)->Par.f) from = (a->CPos-1)->Par.f->GetRetType(); break;
|
||||
case AB_CALL: case AB_CALLFS:
|
||||
|
@ -1959,8 +1999,6 @@ int C4AulParseState::Parse_Params(int iMaxCnt, const char * sWarn, C4AulFunc * p
|
|||
pFunc2 = a->Engine->GetNextSNFunc(pFunc2);
|
||||
}
|
||||
}
|
||||
case AB_ARRAYA_R: case AB_PAR_R: case AB_PARN_R: case AB_VARN_R: case AB_LOCALN_R: case AB_GLOBALN_R:
|
||||
from = C4V_Ref; break;
|
||||
default: break; // avoid compiler warning about unhandled enumerators
|
||||
}
|
||||
if (C4Value::WarnAboutConversion(from, to))
|
||||
|
@ -2067,7 +2105,7 @@ void C4AulParseState::Parse_PropList()
|
|||
Shift();
|
||||
}
|
||||
else UnexpectedToken("string or identifier");
|
||||
if (TokenType != ATT_COLON && (TokenType != ATT_OPERATOR || !SEqual(C4ScriptOpMap[cInt].Identifier,"=")))
|
||||
if (TokenType != ATT_COLON && TokenType != ATT_SET)
|
||||
UnexpectedToken("':' or '='");
|
||||
Shift();
|
||||
Parse_Expression();
|
||||
|
@ -2094,7 +2132,6 @@ void C4AulParseState::Parse_DoWhile()
|
|||
Match(ATT_BOPEN);
|
||||
Parse_Expression();
|
||||
Match(ATT_BCLOSE);
|
||||
SetNoRef();
|
||||
// Jump back
|
||||
AddJump(AB_COND, iStart);
|
||||
if (Type != PARSER) return;
|
||||
|
@ -2115,7 +2152,6 @@ void C4AulParseState::Parse_While()
|
|||
Match(ATT_BOPEN);
|
||||
Parse_Expression();
|
||||
Match(ATT_BCLOSE);
|
||||
SetNoRef();
|
||||
// Check condition
|
||||
int iCond = a->GetCodePos();
|
||||
AddBCC(AB_CONDN);
|
||||
|
@ -2142,7 +2178,6 @@ void C4AulParseState::Parse_If()
|
|||
Match(ATT_BOPEN);
|
||||
Parse_Expression();
|
||||
Match(ATT_BCLOSE);
|
||||
SetNoRef();
|
||||
// create bytecode, remember position
|
||||
int iCond = a->GetCodePos();
|
||||
AddBCC(AB_CONDN);
|
||||
|
@ -2177,7 +2212,6 @@ void C4AulParseState::Parse_For()
|
|||
else if (TokenType != ATT_SCOLON)
|
||||
{
|
||||
Parse_Expression();
|
||||
SetNoRef();
|
||||
AddBCC(AB_STACK, -1);
|
||||
}
|
||||
// Consume first semicolon
|
||||
|
@ -2189,7 +2223,6 @@ void C4AulParseState::Parse_For()
|
|||
// Add condition code
|
||||
iCondition = JumpHere();
|
||||
Parse_Expression();
|
||||
SetNoRef();
|
||||
// Jump out
|
||||
iJumpOut = a->GetCodePos();
|
||||
AddBCC(AB_CONDN);
|
||||
|
@ -2206,7 +2239,6 @@ void C4AulParseState::Parse_For()
|
|||
// Add incrementor code
|
||||
iIncrementor = JumpHere();
|
||||
Parse_Expression();
|
||||
SetNoRef();
|
||||
AddBCC(AB_STACK, -1);
|
||||
// Jump to condition
|
||||
if (iCondition != -1)
|
||||
|
@ -2307,14 +2339,14 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
|
|||
if (Fn->ParNamed.GetItemNr(Idtf) != -1)
|
||||
{
|
||||
// insert variable by id
|
||||
AddBCC(AB_PARN_R, Fn->ParNamed.GetItemNr(Idtf));
|
||||
AddBCC(AB_PARN, Fn->ParNamed.GetItemNr(Idtf));
|
||||
Shift();
|
||||
}
|
||||
// check for variable (var)
|
||||
else if (Fn->VarNamed.GetItemNr(Idtf) != -1)
|
||||
{
|
||||
// insert variable by id
|
||||
AddBCC(AB_VARN_R, Fn->VarNamed.GetItemNr(Idtf));
|
||||
AddBCC(AB_VARN, Fn->VarNamed.GetItemNr(Idtf));
|
||||
Shift();
|
||||
}
|
||||
// check for variable (local)
|
||||
|
@ -2325,14 +2357,14 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
|
|||
throw new C4AulParseError(this, "using local variable in global function!");
|
||||
// insert variable by id
|
||||
C4String * pKey = Strings.RegString(Idtf);
|
||||
AddBCC(AB_LOCALN_R, (intptr_t) pKey);
|
||||
AddBCC(AB_LOCALN, (intptr_t) pKey);
|
||||
Shift();
|
||||
}
|
||||
// check for global variable (static)
|
||||
else if (a->Engine->GlobalNamedNames.GetItemNr(Idtf) != -1)
|
||||
{
|
||||
// insert variable by id
|
||||
AddBCC(AB_GLOBALN_R, a->Engine->GlobalNamedNames.GetItemNr(Idtf));
|
||||
AddBCC(AB_GLOBALN, a->Engine->GlobalNamedNames.GetItemNr(Idtf));
|
||||
Shift();
|
||||
}
|
||||
// function identifier: check special functions
|
||||
|
@ -2357,7 +2389,7 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
|
|||
// and for Par
|
||||
Shift();
|
||||
Parse_Params(1, C4AUL_Par);
|
||||
AddBCC(AB_PAR_R);
|
||||
AddBCC(AB_PAR);
|
||||
}
|
||||
else if (SEqual(Idtf, C4AUL_Inherited) || SEqual(Idtf, C4AUL_SafeInherited))
|
||||
{
|
||||
|
@ -2501,8 +2533,15 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
|
|||
(a->CPos - 1)->Par.i = -(a->CPos - 1)->Par.i;
|
||||
break;
|
||||
}
|
||||
// changer? make a setter BCC, leave value for operator
|
||||
C4AulBCC Changer;
|
||||
if(C4ScriptOpMap[OpID].Changer)
|
||||
Changer = MakeSetter(true);
|
||||
// write byte code
|
||||
AddBCC(C4ScriptOpMap[OpID].Code, OpID);
|
||||
// writter setter
|
||||
if(C4ScriptOpMap[OpID].Changer)
|
||||
AddBCC(Changer.bccType, Changer.Par.i);
|
||||
break;
|
||||
}
|
||||
case ATT_BOPEN:
|
||||
|
@ -2536,6 +2575,21 @@ void C4AulParseState::Parse_Expression2(int iParentPrio)
|
|||
{
|
||||
while (1) switch (TokenType)
|
||||
{
|
||||
case ATT_SET:
|
||||
{
|
||||
// back out of any kind of parent operator
|
||||
// (except other setters, as those are right-associative)
|
||||
if(iParentPrio > 1)
|
||||
return;
|
||||
// generate setter
|
||||
C4AulBCC Setter = MakeSetter(false);
|
||||
// parse value to set
|
||||
Shift();
|
||||
Parse_Expression(1);
|
||||
// write setter
|
||||
AddBCC(Setter.bccType, Setter.Par.i);
|
||||
break;
|
||||
}
|
||||
case ATT_OPERATOR:
|
||||
{
|
||||
// expect postfix operator
|
||||
|
@ -2557,14 +2611,25 @@ void C4AulParseState::Parse_Expression2(int iParentPrio)
|
|||
// otherwise use the new-found correct postfix operator
|
||||
OpID = nOpID;
|
||||
}
|
||||
// lower priority?
|
||||
if (C4ScriptOpMap[OpID].RightAssociative ?
|
||||
C4ScriptOpMap[OpID].Priority < iParentPrio :
|
||||
C4ScriptOpMap[OpID].Priority <= iParentPrio)
|
||||
return;
|
||||
// If the operator does not modify the first argument, no reference is necessary
|
||||
if (C4ScriptOpMap[OpID].Type1 != C4V_Ref)
|
||||
SetNoRef();
|
||||
|
||||
// changer?
|
||||
C4AulBCC Setter;
|
||||
if (C4ScriptOpMap[OpID].Changer)
|
||||
{
|
||||
// changer: back out only if parent operator is stronger
|
||||
// (everything but setters and other changers, as changers are right-associative)
|
||||
if(iParentPrio > C4ScriptOpMap[OpID].Priority)
|
||||
return;
|
||||
// generate setter, leave value on stack for operator
|
||||
Setter = MakeSetter(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal operator: back out if parent operator is at least as strong
|
||||
// (non-setter operators are left-associative)
|
||||
if(iParentPrio >= C4ScriptOpMap[OpID].Priority)
|
||||
return;
|
||||
}
|
||||
Shift();
|
||||
|
||||
if (C4ScriptOpMap[OpID].Code == AB_JUMPAND || C4ScriptOpMap[OpID].Code == AB_JUMPOR)
|
||||
|
@ -2577,20 +2642,21 @@ void C4AulParseState::Parse_Expression2(int iParentPrio)
|
|||
Parse_Expression(C4ScriptOpMap[OpID].Priority);
|
||||
// set condition jump target
|
||||
SetJumpHere(iCond);
|
||||
// write setter (unused - could also optimize to skip self-assign, but must keep stack balanced)
|
||||
if (C4ScriptOpMap[OpID].Changer)
|
||||
AddBCC(Setter.bccType, Setter.Par.i);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// expect second parameter for operator
|
||||
if (!C4ScriptOpMap[OpID].NoSecondStatement)
|
||||
{
|
||||
Parse_Expression(C4ScriptOpMap[OpID].Priority);
|
||||
// If the operator does not modify the second argument, no reference is necessary
|
||||
if (C4ScriptOpMap[OpID].Type2 != C4V_Ref)
|
||||
SetNoRef();
|
||||
}
|
||||
// write byte code
|
||||
AddBCC(C4ScriptOpMap[OpID].Code, OpID);
|
||||
// write setter
|
||||
if (C4ScriptOpMap[OpID].Changer)
|
||||
AddBCC(Setter.bccType, Setter.Par.i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2606,7 +2672,7 @@ void C4AulParseState::Parse_Expression2(int iParentPrio)
|
|||
if (TokenType == ATT_BCLOSE2)
|
||||
{
|
||||
Shift();
|
||||
AddBCC(AB_ARRAYA_R);
|
||||
AddBCC(AB_ARRAYA);
|
||||
}
|
||||
else if (TokenType == ATT_COLON)
|
||||
{
|
||||
|
@ -2692,36 +2758,23 @@ void C4AulParseState::Parse_Var()
|
|||
if (iVarID < 0)
|
||||
throw new C4AulParseError(this, "internal error: var definition: var not found in variable table");
|
||||
Shift();
|
||||
if (TokenType == ATT_OPERATOR)
|
||||
if(TokenType == ATT_SET)
|
||||
{
|
||||
// only accept "="
|
||||
int iOpID = cInt;
|
||||
if (SEqual(C4ScriptOpMap[iOpID].Identifier,"="))
|
||||
{
|
||||
// insert initialization in byte code
|
||||
Shift();
|
||||
Parse_Expression();
|
||||
AddBCC(AB_IVARN, iVarID);
|
||||
}
|
||||
else
|
||||
throw new C4AulParseError(this, "unexpected operator");
|
||||
// insert initialization in byte code
|
||||
Shift();
|
||||
Parse_Expression();
|
||||
AddBCC(AB_IVARN, iVarID);
|
||||
}
|
||||
switch (TokenType)
|
||||
{
|
||||
case ATT_COMMA:
|
||||
{
|
||||
Shift();
|
||||
break;
|
||||
}
|
||||
case ATT_SCOLON:
|
||||
{
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
UnexpectedToken("',' or ';'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2818,7 +2871,7 @@ void C4AulParseState::Parse_Const()
|
|||
Error("constant and variable with name ", Idtf);
|
||||
Match(ATT_IDTF);
|
||||
// expect '='
|
||||
if (TokenType != ATT_OPERATOR || !SEqual(C4ScriptOpMap[cInt].Identifier,"="))
|
||||
if (TokenType != ATT_SET)
|
||||
UnexpectedToken("'='");
|
||||
// expect value. Theoretically, something like C4AulScript::ExecOperator could be used here
|
||||
// this would allow for definitions like "static const OCF_Edible = 1<<23"
|
||||
|
|
|
@ -338,6 +338,20 @@ template <> struct C4ValueConv<C4Value *>
|
|||
inline static C4Value *_FromC4V(C4Value &v) { return v._getRef(); }
|
||||
inline static C4Value ToC4V(C4Value *v) { return C4VRef(v); }
|
||||
};
|
||||
template <> struct C4ValueConv<const C4Value &>
|
||||
{
|
||||
inline static C4V_Type Type() { return C4V_Any; }
|
||||
inline static const C4Value &FromC4V(C4Value &v) { return v; }
|
||||
inline static const C4Value &_FromC4V(C4Value &v) { return v; }
|
||||
inline static C4Value ToC4V(const C4Value &v) { return v; }
|
||||
};
|
||||
template <> struct C4ValueConv<C4Value>
|
||||
{
|
||||
inline static C4V_Type Type() { return C4V_Any; }
|
||||
inline static C4Value FromC4V(C4Value &v) { return v; }
|
||||
inline static C4Value _FromC4V(C4Value &v) { return v; }
|
||||
inline static C4Value ToC4V(C4Value v) { return v; }
|
||||
};
|
||||
|
||||
// aliases
|
||||
template <> struct C4ValueConv<long> : public C4ValueConv<int32_t> { };
|
||||
|
|
Loading…
Reference in New Issue