Script: Make non-#strict and #strict behave the same as #strict 2

This allows some simplifications, mostly code that's just not needed
anymore.
stable-5.2
Günther Brammer 2009-07-23 01:02:41 +02:00
parent 51179151ff
commit 87e12484e7
5 changed files with 64 additions and 375 deletions

View File

@ -163,17 +163,13 @@ enum C4AulBCCType
AB_LessThanEqual, // <= AB_LessThanEqual, // <=
AB_GreaterThan, // > AB_GreaterThan, // >
AB_GreaterThanEqual, // >= AB_GreaterThanEqual, // >=
AB_EqualIdent, // old == AB_Equal, // ==
AB_Equal, // new == AB_NotEqual, // !=
AB_NotEqualIdent, // old !=
AB_NotEqual, // new !=
AB_SEqual, // S=, eq AB_SEqual, // S=, eq
AB_SNEqual, // ne AB_SNEqual, // ne
AB_BitAnd, // & AB_BitAnd, // &
AB_BitXOr, // ^ AB_BitXOr, // ^
AB_BitOr, // | AB_BitOr, // |
AB_And, // &&
AB_Or, // ||
AB_MulIt, // *= AB_MulIt, // *=
AB_DivIt, // /= AB_DivIt, // /=
AB_ModIt, // %= AB_ModIt, // %=
@ -326,7 +322,6 @@ class C4AulScriptFunc : public C4AulFunc
C4ValueMapNames VarNamed; // list of named vars in this function C4ValueMapNames VarNamed; // list of named vars in this function
C4ValueMapNames ParNamed; // list of named pars in this function C4ValueMapNames ParNamed; // list of named pars in this function
C4V_Type ParType[C4AUL_MAX_Par]; // parameter types C4V_Type ParType[C4AUL_MAX_Par]; // parameter types
bool bNewFormat; // new func format? [ func xyz(par abc) { ... } ]
bool bReturnRef; // return reference bool bReturnRef; // return reference
C4AulScript *pOrgScript; // the orginal script (!= Owner if included or appended) C4AulScript *pOrgScript; // the orginal script (!= Owner if included or appended)

View File

@ -173,7 +173,7 @@ void C4AulScript::Default()
IncludesResolved = false; IncludesResolved = false;
// defaults // defaults
Strict = NONSTRICT; Strict = MAXSTRICT;
Preparsing=Resolving=false; Preparsing=Resolving=false;
Temporary = false; Temporary = false;
LocalNamed.Reset(); LocalNamed.Reset();
@ -390,7 +390,6 @@ void C4AulScriptFunc::CopyBody(C4AulScriptFunc &FromFunc)
Script = FromFunc.Script; Script = FromFunc.Script;
VarNamed = FromFunc.VarNamed; VarNamed = FromFunc.VarNamed;
ParNamed = FromFunc.ParNamed; ParNamed = FromFunc.ParNamed;
bNewFormat = FromFunc.bNewFormat;
bReturnRef = FromFunc.bReturnRef; bReturnRef = FromFunc.bReturnRef;
pOrgScript = FromFunc.pOrgScript; pOrgScript = FromFunc.pOrgScript;
for(int i = 0; i < C4AUL_MAX_Par; i++) for(int i = 0; i < C4AUL_MAX_Par; i++)

View File

@ -534,15 +534,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
PopValue(); PopValue();
break; break;
} }
case AB_EqualIdent: // old == case AB_Equal: // ==
{
CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
pPar1->SetBool(pPar1->_getRaw() == pPar2->_getRaw());
PopValue();
break;
}
case AB_Equal: // new ==
{ {
CheckOpPars(pCPos->Par.i); CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal; C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
@ -550,15 +542,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
PopValue(); PopValue();
break; break;
} }
case AB_NotEqualIdent: // old != case AB_NotEqual: // !=
{
CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
pPar1->SetBool(pPar1->_getRaw() != pPar2->_getRaw());
PopValue();
break;
}
case AB_NotEqual: // new !=
{ {
CheckOpPars(pCPos->Par.i); CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal; C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
@ -608,22 +592,6 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
PopValue(); PopValue();
break; break;
} }
case AB_And: // &&
{
CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
pPar1->SetBool(pPar1->_getRaw() && pPar2->_getRaw());
PopValue();
break;
}
case AB_Or: // ||
{
CheckOpPars(pCPos->Par.i);
C4Value *pPar1 = pCurVal - 1, *pPar2 = pCurVal;
pPar1->SetBool(pPar1->_getRaw() || pPar2->_getRaw());
PopValue();
break;
}
case AB_MulIt: // *= case AB_MulIt: // *=
{ {
CheckOpPars(pCPos->Par.i); CheckOpPars(pCPos->Par.i);

View File

@ -172,8 +172,7 @@ class C4AulParseState
const char * GetTokenName(C4AulTokenType TokenType); const char * GetTokenName(C4AulTokenType TokenType);
void Warn(const char *pMsg, const char *pIdtf=0); void Warn(const char *pMsg, const char *pIdtf=0);
void StrictError(const char *pMsg, const char *pIdtf=0); void Error(const char *pMsg, const char *pIdtf=0);
void Strict2Error(const char *pMsg, const char *pIdtf=0);
private: private:
@ -236,19 +235,9 @@ void C4AulParseState::Warn(const char *pMsg, const char *pIdtf)
++::ScriptEngine.warnCnt; ++::ScriptEngine.warnCnt;
} }
void C4AulParseState::StrictError(const char *pMsg, const char *pIdtf) void C4AulParseState::Error(const char *pMsg, const char *pIdtf)
{ {
if (Fn ? (Fn->pOrgScript->Strict < C4AulScript::STRICT1) : (a->Strict < C4AulScript::STRICT1)) throw new C4AulParseError(this, pMsg, pIdtf);
Warn(pMsg, pIdtf);
else
throw new C4AulParseError(this, pMsg, pIdtf);
}
void C4AulParseState::Strict2Error(const char *pMsg, const char *pIdtf)
{
if (Fn ? (Fn->pOrgScript->Strict < C4AulScript::STRICT2) : (a->Strict < C4AulScript::STRICT2))
Warn(pMsg, pIdtf);
else
throw new C4AulParseError(this, pMsg, pIdtf);
} }
C4AulParseError::C4AulParseError(C4AulParseState * state, const char *pMsg, const char *pIdtf, BOOL Warn) C4AulParseError::C4AulParseError(C4AulParseState * state, const char *pMsg, const char *pIdtf, BOOL Warn)
@ -457,8 +446,8 @@ C4ScriptOpDef C4ScriptOpMap[] = {
{ 8, "&", AB_BitAnd, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int}, { 8, "&", AB_BitAnd, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 6, "^", AB_BitXOr, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int}, { 6, "^", AB_BitXOr, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 6, "|", AB_BitOr, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int}, { 6, "|", AB_BitOr, 1, 0, 0, C4V_Int, C4V_Int, C4V_Int},
{ 5, "&&", AB_And, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool}, { 5, "&&", AB_JUMPAND, 1, 0, 0, C4V_Bool, C4V_Bool, C4V_Bool},
{ 4, "||", AB_Or, 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_Any, C4V_pC4Value, C4V_Int}, { 2, "*=", AB_MulIt, 1, 1, 0, C4V_Any, C4V_pC4Value, C4V_Int},
{ 2, "/=", AB_DivIt, 1, 1, 0, C4V_Any, C4V_pC4Value, C4V_Int}, { 2, "/=", AB_DivIt, 1, 1, 0, C4V_Any, C4V_pC4Value, C4V_Int},
{ 2, "%=", AB_ModIt, 1, 1, 0, C4V_Any, C4V_pC4Value, C4V_Int}, { 2, "%=", AB_ModIt, 1, 1, 0, C4V_Any, C4V_pC4Value, C4V_Int},
@ -481,20 +470,11 @@ int C4AulParseState::GetOperator(const char* pScript)
unsigned int i; unsigned int i;
if(!*pScript) return 0; if(!*pScript) return 0;
// text with > 2 characters or text and #strict 2? // operators are not alphabetical
// then break (may be misinterpreted as operator
if((*pScript >= 'a' && *pScript <= 'z') || if((*pScript >= 'a' && *pScript <= 'z') ||
(*pScript >= 'A' && *pScript <= 'Z')) (*pScript >= 'A' && *pScript <= 'Z'))
{ {
if(Fn ? (Fn->pOrgScript->Strict >= C4AulScript::STRICT2) : (a->Strict >= C4AulScript::STRICT2)) return -1;
return -1;
if((*(pScript+1) >= 'a' && *(pScript+1) <= 'z') ||
(*(pScript+1) >= 'A' && *(pScript+1) <= 'Z'))
if((*(pScript+2) >= 'a' && *(pScript+2) <= 'z') ||
(*(pScript+2) >= 'A' && *(pScript+2) <= 'Z') ||
(*(pScript+2) >= '0' && *(pScript+2) <= '9') ||
*(pScript+2) == '_')
return -1;
} }
// it is a two-char-operator? // it is a two-char-operator?
@ -646,14 +626,8 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
// identifier by all non-special chars // identifier by all non-special chars
if (C >= '@') if (C >= '@')
{ {
// Old Scripts could have wacky identifier // only the alphabet and '_' is allowed
if (a->Strict < C4AulScript::STRICT2) if ((C >= 'A' && C <= 'Z') || (C >= 'a' && C <= 'z') || (C == '_'))
{
State = TGS_Ident;
break;
}
// But now only the alphabet and '_' is allowed
else if ((C >= 'A' && C <= 'Z') || (C >= 'a' && C <= 'z') || (C == '_'))
{ {
State = TGS_Ident; State = TGS_Ident;
break; break;
@ -757,12 +731,6 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
// return integer // return integer
Len = Min(Len, C4AUL_MAX_Identifier); Len = Min(Len, C4AUL_MAX_Identifier);
SCopy(SPos0, pToken, Len); SCopy(SPos0, pToken, Len);
// or is it a func label?
if ((C == '(') || (C == ':'))
{
Strict2Error("stupid func label: ", pToken);
return ATT_IDTF;
}
// do not parse 0x prefix for hex // do not parse 0x prefix for hex
if (State == TGS_IntHex) pToken += 2; if (State == TGS_IntHex) pToken += 2;
// it's not, so return the int // it's not, so return the int
@ -779,12 +747,6 @@ C4AulTokenType C4AulParseState::GetNextToken(char *pToken, long int *pInt, HoldS
// return C4ID string // return C4ID string
Len = Min(Len, C4AUL_MAX_Identifier); Len = Min(Len, C4AUL_MAX_Identifier);
SCopy(SPos0, pToken, Len); SCopy(SPos0, pToken, Len);
// another stupid label identifier?
if ((C == '(') || (C == ':' && *(SPos+1) != ':'))
{
Strict2Error("stupid func label: ", pToken);
return ATT_IDTF;
}
// check if valid // check if valid
if (!LooksLikeID(pToken)) throw new C4AulParseError(this, "erroneous Ident: ", pToken); if (!LooksLikeID(pToken)) throw new C4AulParseError(this, "erroneous Ident: ", pToken);
// get id of it // get id of it
@ -886,17 +848,13 @@ static const char * GetTTName(C4AulBCCType e)
case AB_LessThanEqual: return "LessThanEqual"; // <= case AB_LessThanEqual: return "LessThanEqual"; // <=
case AB_GreaterThan: return "GreaterThan"; // > case AB_GreaterThan: return "GreaterThan"; // >
case AB_GreaterThanEqual: return "GreaterThanEqual"; // >= case AB_GreaterThanEqual: return "GreaterThanEqual"; // >=
case AB_EqualIdent: return "EqualIdent"; // old == case AB_Equal: return "Equal"; // ==
case AB_Equal: return "Equal"; // new == case AB_NotEqual: return "NotEqual"; // !=
case AB_NotEqualIdent: return "NotEqualIdent"; // old !=
case AB_NotEqual: return "NotEqual"; // new !=
case AB_SEqual: return "SEqual"; // S=, eq case AB_SEqual: return "SEqual"; // S=, eq
case AB_SNEqual: return "SNEqual"; // ne case AB_SNEqual: return "SNEqual"; // ne
case AB_BitAnd: return "BitAnd"; // & case AB_BitAnd: return "BitAnd"; // &
case AB_BitXOr: return "BitXOr"; // ^ case AB_BitXOr: return "BitXOr"; // ^
case AB_BitOr: return "BitOr"; // | case AB_BitOr: return "BitOr"; // |
case AB_And: return "And"; // &&
case AB_Or: return "Or"; // ||
case AB_MulIt: return "MulIt"; // *= case AB_MulIt: return "MulIt"; // *=
case AB_DivIt: return "DivIt"; // /= case AB_DivIt: return "DivIt"; // /=
case AB_ModIt: return "ModIt"; // %= case AB_ModIt: return "ModIt"; // %=
@ -1005,7 +963,7 @@ BOOL C4AulScript::Preparse()
state.Parse_Script(); state.Parse_Script();
// no #strict? we don't like that :( // no #strict? we don't like that :(
if (!Strict) if (Strict < MAXSTRICT)
{ {
Engine->nonStrictCnt++; Engine->nonStrictCnt++;
} }
@ -1057,16 +1015,12 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
case AB_GreaterThan: case AB_GreaterThan:
case AB_GreaterThanEqual: case AB_GreaterThanEqual:
case AB_Equal: case AB_Equal:
case AB_EqualIdent:
case AB_NotEqual: case AB_NotEqual:
case AB_NotEqualIdent:
case AB_SEqual: case AB_SEqual:
case AB_SNEqual: case AB_SNEqual:
case AB_BitAnd: case AB_BitAnd:
case AB_BitXOr: case AB_BitXOr:
case AB_BitOr: case AB_BitOr:
case AB_And:
case AB_Or:
case AB_MulIt: case AB_MulIt:
case AB_DivIt: case AB_DivIt:
case AB_ModIt: case AB_ModIt:
@ -1526,7 +1480,7 @@ void C4AulParseState::Parse_FuncHead()
if (a->Engine->GlobalNamedNames.GetItemNr(Idtf) != -1) if (a->Engine->GlobalNamedNames.GetItemNr(Idtf) != -1)
throw new C4AulParseError(this, "function definition: name already in use (global variable)"); throw new C4AulParseError(this, "function definition: name already in use (global variable)");
if (a->Engine->GlobalConstNames.GetItemNr(Idtf) != -1) if (a->Engine->GlobalConstNames.GetItemNr(Idtf) != -1)
Strict2Error("function definition: name already in use (global variable)", 0); Error("function definition: name already in use (global constant)", 0);
} }
// create script fn // create script fn
if (Acc == AA_GLOBAL) if (Acc == AA_GLOBAL)
@ -1545,7 +1499,7 @@ void C4AulParseState::Parse_FuncHead()
// set up func (in the case we got an error) // set up func (in the case we got an error)
Fn->Script = SPos; // temporary Fn->Script = SPos; // temporary
Fn->Access = Acc; Fn->pOrgScript = a; Fn->Access = Acc; Fn->pOrgScript = a;
Fn->bNewFormat = true; Fn->bReturnRef = bReturnRef; Fn->bReturnRef = bReturnRef;
Shift(Discard,false); Shift(Discard,false);
// expect an opening bracket now // expect an opening bracket now
if (TokenType != ATT_BOPEN) if (TokenType != ATT_BOPEN)
@ -1572,11 +1526,6 @@ void C4AulParseState::Parse_FuncHead()
{ {
UnexpectedToken("parameter or closing bracket"); UnexpectedToken("parameter or closing bracket");
} }
char TypeIdtf[C4AUL_MAX_Identifier] = ""; // current identifier
if (TokenType == ATT_IDTF)
{
SCopy(Idtf, TypeIdtf);
}
// type identifier? // type identifier?
if (SEqual(Idtf, C4AUL_TypeInt)) { Fn->ParType[cpar] = C4V_Int; Shift(Discard,false); } if (SEqual(Idtf, C4AUL_TypeInt)) { Fn->ParType[cpar] = C4V_Int; Shift(Discard,false); }
else if (SEqual(Idtf, C4AUL_TypeBool)) { Fn->ParType[cpar] = C4V_Bool; Shift(Discard,false); } else if (SEqual(Idtf, C4AUL_TypeBool)) { Fn->ParType[cpar] = C4V_Bool; Shift(Discard,false); }
@ -1589,12 +1538,7 @@ void C4AulParseState::Parse_FuncHead()
if (TokenType == ATT_AMP) { Fn->ParType[cpar] = C4V_pC4Value; Shift(Discard,false); } if (TokenType == ATT_AMP) { Fn->ParType[cpar] = C4V_pC4Value; Shift(Discard,false); }
if (TokenType != ATT_IDTF) if (TokenType != ATT_IDTF)
{ {
if (SEqual(TypeIdtf,"")) UnexpectedToken("parameter name");
UnexpectedToken("parameter or closing bracket");
// A parameter with the same name as a type
Strict2Error("parameter has the same name as type ", TypeIdtf);
Fn->ParType[cpar] = C4V_Any;
Fn->ParNamed.AddName(TypeIdtf);
} }
else else
{ {
@ -1614,132 +1558,14 @@ void C4AulParseState::Parse_FuncHead()
Shift(Discard,false); Shift(Discard,false);
cpar++; cpar++;
} }
// ok, expect opening block Fn->Script = SPos;
if(TokenType != ATT_BLOPEN) Match(ATT_BLOPEN);
{
// warn
Strict2Error("'func': expecting opening block ('{') after func declaration", 0);
// not really new syntax (a sort of legacy mode)
Fn->bNewFormat = false;
}
else
{
Fn->Script = SPos;
Shift();
}
Parse_Desc(); Parse_Desc();
Parse_Function(); Parse_Function();
Match(ATT_BLCLOSE); Match(ATT_BLCLOSE);
return; return;
} }
// Must be old-style function declaration now throw new C4AulParseError(this, "Declaration expected, but found identifier ", Idtf);
if (a->Strict >= C4AulScript::STRICT2)
throw new C4AulParseError(this, "Declaration expected, but found identifier ", Idtf);
// check: symbol already in use?
switch(Acc)
{
case AA_PRIVATE:
case AA_PROTECTED:
case AA_PUBLIC:
if(a->LocalNamed.GetItemNr(Idtf) != -1)
throw new C4AulParseError(this, "function definition: name already in use (local variable)");
if(a->Def)
break;
// func in global context: fallthru
case AA_GLOBAL:
if(a->Engine->GlobalNamedNames.GetItemNr(Idtf) != -1)
throw new C4AulParseError(this, "function definition: name already in use (global variable)");
}
char FuncIdtf[C4AUL_MAX_Identifier] = ""; // current identifier
SCopy(Idtf, FuncIdtf);
Shift();
if (TokenType != ATT_COLON)
throw new C4AulParseError(this, FormatString("declaration expected, but found identifier '%s'", FuncIdtf).getData());
// create script fn
if (Acc == AA_GLOBAL)
{
// global func
Fn = new C4AulScriptFunc(a->Engine, FuncIdtf);
C4AulFunc *FnLink = new C4AulFunc(a, NULL);
FnLink->LinkedTo = Fn; Fn->LinkedTo = FnLink;
Acc = AA_PUBLIC;
}
else
{
// normal, local func
Fn = new C4AulScriptFunc(a, FuncIdtf);
}
Fn->Script = SPos;
Fn->Access = Acc;
Fn->pOrgScript = a;
Fn->bNewFormat = false;
Fn->bReturnRef = false;
Shift();
Parse_Desc();
const char * SPos0 = SPos;
while(1) switch(TokenType)
{
// end of function
case ATT_EOF: case ATT_DIR: return;
case ATT_IDTF:
{
// check for func declaration
if (SEqual(Idtf, C4AUL_Private)) return;
else if (SEqual(Idtf, C4AUL_Protected)) return;
else if (SEqual(Idtf, C4AUL_Public)) return;
else if (SEqual(Idtf, C4AUL_Global)) return;
else if (SEqual(Idtf, C4AUL_Func)) return;
// check for variable definition (var)
else if(SEqual(Idtf, C4AUL_VarNamed))
{
Shift();
Parse_Var();
}
// check for variable definition (local)
else if(SEqual(Idtf, C4AUL_LocalNamed))
{
if(a->Def)
{
Shift();
Parse_Local();
}
else
throw new C4AulParseError(this, "'local' variable declaration in global script");
}
// check for variable definition (static)
else if(SEqual(Idtf, C4AUL_GlobalNamed))
{
Shift();
Parse_Static();
}
// might be old style declaration
else
{
const char * SPos0_ = SPos;
Shift();
if (TokenType == ATT_COLON)
{
// Reset source position to the point before the label
SPos = SPos0;
Shift();
return;
}
else
{
// The current token might be a label
// In that case the next round of the loop will need to reset the position to what's in SPos0_ now
SPos0 = SPos0_;
}
}
break;
}
default:
{
SPos0 = SPos;
Shift();
break;
}
}
} }
void C4AulParseState::Parse_Desc() void C4AulParseState::Parse_Desc()
@ -1785,23 +1611,18 @@ void C4AulParseState::Parse_Function()
// a block end? // a block end?
case ATT_BLCLOSE: case ATT_BLCLOSE:
{ {
// new-form func? // all ok, insert a return
if(Fn->bNewFormat) C4AulBCC * CPos = a->GetCodeByPos(Max(a->GetCodePos() - 1,0));
if (!CPos || CPos->bccType != AB_RETURN || fJump)
{ {
// all ok, insert a return AddBCC(AB_INT);
C4AulBCC * CPos = a->GetCodeByPos(Max(a->GetCodePos() - 1,0)); AddBCC(AB_RETURN);
if (!CPos || CPos->bccType != AB_RETURN || fJump)
{
AddBCC(AB_INT);
AddBCC(AB_RETURN);
}
// and break
Done = TRUE;
// Do not blame this function for script errors between functions
Fn = 0;
return;
} }
throw new C4AulParseError(this, "no '{' found for '}'"); // and break
Done = TRUE;
// Do not blame this function for script errors between functions
Fn = 0;
return;
} }
case ATT_EOF: case ATT_EOF:
{ {
@ -1967,23 +1788,11 @@ void C4AulParseState::Parse_Statement()
} }
else if (SEqual(Idtf, C4AUL_Return)) // return else if (SEqual(Idtf, C4AUL_Return)) // return
{ {
bool multi_params_hack = false;
Shift(); Shift();
if (TokenType == ATT_BOPEN && Fn->pOrgScript->Strict < C4AulScript::STRICT2) if(TokenType == ATT_SCOLON)
{ {
// parse return(retvals) - return(retval, unused, parameters, ...) allowed for backwards compatibility // allow return; without return value (implies nil)
if (Parse_Params(1, NULL) == 1) AddBCC(AB_NIL);
{
// return (1 + 1) * 3 returns 6, not 2
Parse_Expression2();
}
else
multi_params_hack = true;
}
else if(TokenType == ATT_SCOLON)
{
// allow return; without return value (implies 0)
AddBCC(AB_INT);
} }
else else
{ {
@ -1993,15 +1802,6 @@ void C4AulParseState::Parse_Statement()
if(!Fn->bReturnRef) if(!Fn->bReturnRef)
SetNoRef(); SetNoRef();
AddBCC(AB_RETURN); AddBCC(AB_RETURN);
if (multi_params_hack && TokenType != ATT_SCOLON)
{
// return (1, 1) * 3 returns 1
// but warn about it, the * 3 won't get executed and a stray ',' could lead to unexpected results
Warn("';' expected, but found ", GetTokenName(TokenType));
AddBCC(AB_STACK, +1);
Parse_Expression2();
AddBCC(AB_STACK, -1);
}
} }
else if (SEqual(Idtf, C4AUL_this)) // this on top level else if (SEqual(Idtf, C4AUL_this)) // this on top level
{ {
@ -2017,7 +1817,7 @@ void C4AulParseState::Parse_Statement()
// Must be inside a loop // Must be inside a loop
if(!pLoopStack) if(!pLoopStack)
{ {
Strict2Error("'break' is only allowed inside loops"); Error("'break' is only allowed inside loops");
} }
else else
{ {
@ -2037,7 +1837,7 @@ void C4AulParseState::Parse_Statement()
// Must be inside a loop // Must be inside a loop
if(!pLoopStack) if(!pLoopStack)
{ {
Strict2Error("'continue' is only allowed inside loops"); Error("'continue' is only allowed inside loops");
} }
else else
{ {
@ -2093,23 +1893,14 @@ void C4AulParseState::Parse_Statement()
} }
else else
{ {
bool gotohack = false;
// none of these? then it's a function // none of these? then it's a function
// if it's a label, it will be missinterpreted here, which will be corrected later // if it's a label, it will be missinterpreted here, which will be corrected later
// it may be the first goto() found? (old syntax only!)
if (SEqual(Idtf, C4AUL_Goto) && !Fn->pOrgScript->Strict)
// add AB_RETURN later on
gotohack=true;
C4AulFunc *FoundFn; C4AulFunc *FoundFn;
// old syntax: do not allow recursive calls in overloaded functions // get regular function
if (!Fn->pOrgScript->Strict && Fn->OwnerOverloaded && SEqual(Idtf, Fn->Name)) if(Fn->Owner == &::ScriptEngine)
FoundFn = Fn->OwnerOverloaded; FoundFn = a->Owner->GetFuncRecursive(Idtf);
else else
// get regular function FoundFn = a->GetFuncRecursive(Idtf);
if(Fn->Owner == &::ScriptEngine)
FoundFn = a->Owner->GetFuncRecursive(Idtf);
else
FoundFn = a->GetFuncRecursive(Idtf);
// ignore func-not-found errors in the preparser, because the function tables are not built yet // ignore func-not-found errors in the preparser, because the function tables are not built yet
if (!FoundFn && Type == PARSER) if (!FoundFn && Type == PARSER)
{ {
@ -2138,11 +1929,6 @@ void C4AulParseState::Parse_Statement()
if (TokenType == ATT_BOPEN || Type == PARSER) if (TokenType == ATT_BOPEN || Type == PARSER)
Parse_Params(FoundFn ? FoundFn->GetParCount() : 10, FoundFn ? FoundFn->Name : Idtf, FoundFn); Parse_Params(FoundFn ? FoundFn->GetParCount() : 10, FoundFn ? FoundFn->Name : Idtf, FoundFn);
AddBCC(AB_FUNC, (long) FoundFn); AddBCC(AB_FUNC, (long) FoundFn);
if (gotohack)
{
AddBCC(AB_RETURN);
AddBCC(AB_STACK, +1);
}
Parse_Expression2(); Parse_Expression2();
SetNoRef(); SetNoRef();
AddBCC(AB_STACK, -1); AddBCC(AB_STACK, -1);
@ -2352,14 +2138,9 @@ void C4AulParseState::Parse_While()
// Save position for later jump back // Save position for later jump back
int iStart = JumpHere(); int iStart = JumpHere();
// Execute condition // Execute condition
if (Fn->pOrgScript->Strict >= C4AulScript::STRICT2) Match(ATT_BOPEN);
{ Parse_Expression();
Match(ATT_BOPEN); Match(ATT_BCLOSE);
Parse_Expression();
Match(ATT_BCLOSE);
}
else
Parse_Params(1, C4AUL_While);
SetNoRef(); SetNoRef();
// Check condition // Check condition
int iCond = a->GetCodePos(); int iCond = a->GetCodePos();
@ -2384,14 +2165,9 @@ void C4AulParseState::Parse_While()
void C4AulParseState::Parse_If() void C4AulParseState::Parse_If()
{ {
if (Fn->pOrgScript->Strict >= C4AulScript::STRICT2) Match(ATT_BOPEN);
{ Parse_Expression();
Match(ATT_BOPEN); Match(ATT_BCLOSE);
Parse_Expression();
Match(ATT_BCLOSE);
}
else
Parse_Params(1, C4AUL_If);
SetNoRef(); SetNoRef();
// create bytecode, remember position // create bytecode, remember position
int iCond = a->GetCodePos(); int iCond = a->GetCodePos();
@ -2599,12 +2375,7 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
throw new C4AulParseError(this, "'for' may not be used as a parameter"); throw new C4AulParseError(this, "'for' may not be used as a parameter");
else if (SEqual(Idtf, C4AUL_Return)) else if (SEqual(Idtf, C4AUL_Return))
{ {
// return: treat as regular function with special byte code Error("return may not be used as a parameter", 0);
Strict2Error("return used as a parameter", 0);
Shift();
Parse_Params(1, NULL);
AddBCC(AB_RETURN);
AddBCC(AB_STACK, +1);
} }
else if (SEqual(Idtf, C4AUL_Par)) else if (SEqual(Idtf, C4AUL_Par))
{ {
@ -2616,8 +2387,6 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
else if (SEqual(Idtf, C4AUL_Inherited) || SEqual(Idtf, C4AUL_SafeInherited)) else if (SEqual(Idtf, C4AUL_Inherited) || SEqual(Idtf, C4AUL_SafeInherited))
{ {
Shift(); Shift();
// inherited keyword: check strict syntax
if (!Fn->pOrgScript->Strict) throw new C4AulParseError(this, "inherited disabled; use #strict syntax!");
// get function // get function
if (Fn->OwnerOverloaded) if (Fn->OwnerOverloaded)
{ {
@ -2628,7 +2397,7 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
else else
// not found? raise an error, if it's not a safe call // not found? raise an error, if it's not a safe call
if (SEqual(Idtf, C4AUL_Inherited) && Type == PARSER) if (SEqual(Idtf, C4AUL_Inherited) && Type == PARSER)
throw new C4AulParseError(this, "inherited function not found, use _inherited to call failsafe"); throw new C4AulParseError(this, "inherited function not found (use _inherited to disable this message)");
else else
{ {
// otherwise, parse parameters, but discard them // otherwise, parse parameters, but discard them
@ -2637,13 +2406,6 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
AddBCC(AB_STACK, 1); AddBCC(AB_STACK, 1);
} }
} }
else if (!Fn->pOrgScript->Strict && Fn->OwnerOverloaded && SEqual(Idtf, Fn->Name))
{
// old syntax: do not allow recursive calls in overloaded functions
Shift();
Parse_Params(Fn->OwnerOverloaded->GetParCount(), Fn->Name, Fn);
AddBCC(AB_FUNC, (long) Fn->OwnerOverloaded);
}
else else
{ {
C4AulFunc *FoundFn; C4AulFunc *FoundFn;
@ -2701,14 +2463,6 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
} }
} }
Shift(); Shift();
// now let's check whether it used old- or new-style
if (TokenType == ATT_BOPEN && Fn->pOrgScript->Strict < C4AulScript::STRICT2)
{
// old-style usage: ignore function call
// must not use parameters here (although generating the byte code for that would be possible)
Shift();
Match(ATT_BCLOSE, "parameters not allowed in functional usage of constants");
}
} }
else else
{ {
@ -2785,9 +2539,6 @@ void C4AulParseState::Parse_Expression(int iParentPrio)
} }
case ATT_BOPEN2: case ATT_BOPEN2:
{ {
// Arrays are not tested in non-strict mode at all
if(!Fn->pOrgScript->Strict)
throw new C4AulParseError(this, "unexpected '['");
Parse_Array(); Parse_Array();
break; break;
} }
@ -2840,12 +2591,12 @@ void C4AulParseState::Parse_Expression2(int iParentPrio)
SetNoRef(); SetNoRef();
Shift(); Shift();
if ((C4ScriptOpMap[OpID].Code == AB_And || C4ScriptOpMap[OpID].Code == AB_Or) && Fn->pOrgScript->Strict >= C4AulScript::STRICT2) if (C4ScriptOpMap[OpID].Code == AB_JUMPAND || C4ScriptOpMap[OpID].Code == AB_JUMPOR)
{ {
// create bytecode, remember position // create bytecode, remember position
int iCond = a->GetCodePos(); int iCond = a->GetCodePos();
// Jump or discard first parameter // Jump or discard first parameter
AddBCC(C4ScriptOpMap[OpID].Code == AB_And ? AB_JUMPAND : AB_JUMPOR); AddBCC(C4ScriptOpMap[OpID].Code);
// parse second expression // parse second expression
Parse_Expression(C4ScriptOpMap[OpID].Priority); Parse_Expression(C4ScriptOpMap[OpID].Priority);
// set condition jump target // set condition jump target
@ -2857,38 +2608,18 @@ void C4AulParseState::Parse_Expression2(int iParentPrio)
// expect second parameter for operator // expect second parameter for operator
if(!C4ScriptOpMap[OpID].NoSecondStatement) if(!C4ScriptOpMap[OpID].NoSecondStatement)
{ {
switch (TokenType) Parse_Expression(C4ScriptOpMap[OpID].Priority);
{ // If the operator does not modify the second argument, no reference is necessary
case ATT_IDTF: case ATT_INT: case ATT_BOOL: case ATT_STRING: case ATT_C4ID: case ATT_NIL: if(C4ScriptOpMap[OpID].Type2 != C4V_pC4Value)
case ATT_OPERATOR: case ATT_BOPEN: case ATT_BOPEN2: SetNoRef();
Parse_Expression(C4ScriptOpMap[OpID].Priority);
// If the operator does not modify the second argument, no reference is necessary
if(C4ScriptOpMap[OpID].Type2 != C4V_pC4Value)
SetNoRef();
break;
default:
// Stuff like foo(42+,1) used to silently work
Strict2Error(FormatString("Operator %s: Second expression expected, but %s found",
C4ScriptOpMap[OpID].Identifier, GetTokenName(TokenType)).getData(), NULL);
AddBCC(AB_INT, 0);
break;
}
} }
// write byte code, with a few backward compat changes // write byte code
if (C4ScriptOpMap[OpID].Code == AB_Equal && Fn->pOrgScript->Strict < C4AulScript::STRICT2) AddBCC(C4ScriptOpMap[OpID].Code, OpID);
AddBCC(AB_EqualIdent, OpID);
else if (C4ScriptOpMap[OpID].Code == AB_NotEqual && Fn->pOrgScript->Strict < C4AulScript::STRICT2)
AddBCC(AB_NotEqualIdent, OpID);
else
AddBCC(C4ScriptOpMap[OpID].Code, OpID);
} }
break; break;
} }
case ATT_BOPEN2: case ATT_BOPEN2:
{ {
// Arrays are not tested in non-strict mode at all
if(!Fn->pOrgScript->Strict)
throw new C4AulParseError(this, "unexpected '['");
// Access the array // Access the array
Shift(); Shift();
Parse_Expression(); Parse_Expression();
@ -3073,10 +2804,10 @@ void C4AulParseState::Parse_Static()
UnexpectedToken("variable name"); UnexpectedToken("variable name");
// global variable definition // global variable definition
// check: symbol already in use? // check: symbol already in use?
if(a->Engine->GetFuncRecursive(Idtf)) throw new C4AulParseError(this, "variable definition: name already in use"); if (a->Engine->GetFuncRecursive(Idtf)) Error("function and variable with name ", Idtf);
if (a->Engine->GetGlobalConstant(Idtf, NULL)) Strict2Error("constant and variable with name ", Idtf); if (a->Engine->GetGlobalConstant(Idtf, NULL)) Error("constant and variable with name ", Idtf);
// insert variable if not defined already // insert variable if not defined already
if(a->Engine->GlobalNamedNames.GetItemNr(Idtf) == -1) if (a->Engine->GlobalNamedNames.GetItemNr(Idtf) == -1)
a->Engine->GlobalNamedNames.AddName(Idtf); a->Engine->GlobalNamedNames.AddName(Idtf);
} }
Match(ATT_IDTF); Match(ATT_IDTF);
@ -3113,9 +2844,9 @@ void C4AulParseState::Parse_Const()
// (e.g., for overloading constants such as OCF_Living() in chaos scenarios) // (e.g., for overloading constants such as OCF_Living() in chaos scenarios)
// it is not encouraged though, so better warn // it is not encouraged though, so better warn
if(a->Engine->GetFuncRecursive(Idtf)) if(a->Engine->GetFuncRecursive(Idtf))
Strict2Error("definition of constant hidden by function ", Idtf); Error("definition of constant hidden by function ", Idtf);
if(a->Engine->GlobalNamedNames.GetItemNr(Idtf) != -1) if(a->Engine->GlobalNamedNames.GetItemNr(Idtf) != -1)
Strict2Error("constant and variable with name ", Idtf); Error("constant and variable with name ", Idtf);
Match(ATT_IDTF); Match(ATT_IDTF);
// expect '=' // expect '='
if (TokenType != ATT_OPERATOR || !SEqual(C4ScriptOpMap[cInt].Identifier,"=")) if (TokenType != ATT_OPERATOR || !SEqual(C4ScriptOpMap[cInt].Identifier,"="))
@ -3309,7 +3040,7 @@ void C4AulScript::ParseDescs()
C4AulScript *C4AulScript::FindFirstNonStrictScript() C4AulScript *C4AulScript::FindFirstNonStrictScript()
{ {
// self is not #strict? // self is not #strict?
if (Script && !Strict) return this; if (Script && Strict < MAXSTRICT) return this;
// search children // search children
C4AulScript *pNonStrScr; C4AulScript *pNonStrScr;
for (C4AulScript *pScr=Child0; pScr; pScr=pScr->Next) for (C4AulScript *pScr=Child0; pScr; pScr=pScr->Next)

View File

@ -1911,8 +1911,6 @@ static C4Object *FnCreateObject(C4AulContext *cthr,
{ {
iXOffset+=cthr->Obj->GetX(); iXOffset+=cthr->Obj->GetX();
iYOffset+=cthr->Obj->GetY(); iYOffset+=cthr->Obj->GetY();
if (!cthr->Caller || !cthr->Caller->Func->Owner->Strict)
iOwner=cthr->Obj->Owner;
} }
C4Object *pNewObj = Game.CreateObject(PropList,cthr->Obj,iOwner,iXOffset,iYOffset); C4Object *pNewObj = Game.CreateObject(PropList,cthr->Obj,iOwner,iXOffset,iYOffset);
@ -1932,8 +1930,6 @@ static C4Object *FnCreateConstruction(C4AulContext *cthr,
{ {
iXOffset+=cthr->Obj->GetX(); iXOffset+=cthr->Obj->GetX();
iYOffset+=cthr->Obj->GetY(); iYOffset+=cthr->Obj->GetY();
if (!cthr->Caller || !cthr->Caller->Func->Owner->Strict)
iOwner=cthr->Obj->Owner;
} }
// Check site // Check site