make tests pass.

This commit is contained in:
Jeff Hutchinson 2021-04-03 01:53:40 -04:00
parent f776e73b04
commit 3e04196a53
8 changed files with 103 additions and 124 deletions

View file

@ -254,7 +254,7 @@ StrConstNode* StrConstNode::alloc(S32 lineNumber, char* str, bool tag, bool doc)
ret->str = (char*)consoleAlloc(len + 1); ret->str = (char*)consoleAlloc(len + 1);
ret->tag = tag; ret->tag = tag;
ret->doc = doc; ret->doc = doc;
dStrcpy(ret->str, str, len); dStrcpy(ret->str, str, len + 1);
ret->str[len] = '\0'; ret->str[len] = '\0';
return ret; return ret;

View file

@ -512,6 +512,12 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
curStringTable = globalStrings; curStringTable = globalStrings;
curStringTableLen = globalStringsMaxLen; curStringTableLen = globalStringsMaxLen;
// If requested stack frame isn't available, request a new one
// (this prevents assert failures when creating local
// variables without a stack frame)
if (gEvalState.getStackDepth() <= setFrame)
setFrame = -1;
// Do we want this code to execute using a new stack frame? // Do we want this code to execute using a new stack frame?
if (setFrame < 0) if (setFrame < 0)
{ {
@ -519,13 +525,13 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
gCallStack.pushFrame(0); gCallStack.pushFrame(0);
popFrame = true; popFrame = true;
} }
else if (!gEvalState.stack.empty()) else
{ {
// We want to copy a reference to an existing stack frame // We want to copy a reference to an existing stack frame
// on to the top of the stack. Any change that occurs to // on to the top of the stack. Any change that occurs to
// the locals during this new frame will also occur in the // the locals during this new frame will also occur in the
// original frame. // original frame.
S32 stackIndex = gEvalState.stack.size() - setFrame - 1; S32 stackIndex = gEvalState.getTopOfStack() - setFrame - 1;
gEvalState.pushFrameRef(stackIndex); gEvalState.pushFrameRef(stackIndex);
popFrame = true; popFrame = true;
} }
@ -1062,7 +1068,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
// We're falling thru here on purpose. // We're falling thru here on purpose.
case OP_RETURN: case OP_RETURN:
{
if (iterDepth > 0) if (iterDepth > 0)
{ {
// Clear iterator state. // Clear iterator state.
@ -1074,13 +1080,13 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
const char* retVal = STR.getStringValue(); const char* retVal = STR.getStringValue();
STR.rewind(); STR.rewind();
returnValue.setString(retVal, STR.mLen);
STR.setStringValue(retVal); // Not nice but works. STR.setStringValue(retVal); // Not nice but works.
} }
goto execFinished; returnValue.setString(STR.getStringValue(), STR.mLen);
goto execFinished;
}
case OP_RETURN_FLT: case OP_RETURN_FLT:
if (iterDepth > 0) if (iterDepth > 0)
@ -1739,8 +1745,8 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
{ {
if (nsEntry->mFunctionOffset) if (nsEntry->mFunctionOffset)
{ {
const char* ret = nsEntry->mCode->exec(nsEntry->mFunctionOffset, fnName, nsEntry->mNamespace, callArgc, callArgv, false, nsEntry->mPackage).getString(); ConsoleValue returnFromFn = nsEntry->mCode->exec(nsEntry->mFunctionOffset, fnName, nsEntry->mNamespace, callArgc, callArgv, false, nsEntry->mPackage);
STR.setStringValue(ret); STR.setStringValue(returnFromFn.getString());
} }
else // no body else // no body
STR.setStringValue(""); STR.setStringValue("");

View file

@ -203,6 +203,7 @@ public:
break; break;
} }
ref.data = NULL;
ref.setEmptyString(); ref.setEmptyString();
} }
@ -283,7 +284,7 @@ public:
TORQUE_FORCEINLINE void setString(const char* val) TORQUE_FORCEINLINE void setString(const char* val)
{ {
setString(val, dStrlen(val) + 1); setString(val, dStrlen(val));
} }
TORQUE_FORCEINLINE void setString(const char* val, S32 len) TORQUE_FORCEINLINE void setString(const char* val, S32 len)
@ -298,9 +299,9 @@ public:
type = ConsoleValueType::cvString; type = ConsoleValueType::cvString;
s = (char*)dMalloc(len + 1); s = (char*)dMalloc(static_cast<dsize_t>(len) + 1);
s[len] = 0x0; s[len] = '\0';
dStrcpy(s, val, len); dStrcpy(s, val, static_cast<dsize_t>(len) + 1);
} }
TORQUE_FORCEINLINE void setBool(const bool val) TORQUE_FORCEINLINE void setBool(const bool val)

View file

@ -637,6 +637,8 @@ void ExprEvalState::pushFrame(StringTableEntry frameName, Namespace *ns, S32 reg
localStack.push_back(ConsoleValueFrame(consoleValArray, false)); localStack.push_back(ConsoleValueFrame(consoleValArray, false));
currentRegisterArray = &localStack.last(); currentRegisterArray = &localStack.last();
AssertFatal(mStackDepth == localStack.size(), avar("Stack sizes do not match. mStackDepth = %d, localStack = %d", mStackDepth, localStack.size()));
#ifdef DEBUG_SPEW #ifdef DEBUG_SPEW
validate(); validate();
#endif #endif
@ -664,6 +666,8 @@ void ExprEvalState::popFrame()
currentRegisterArray = localStack.size() ? &localStack.last() : NULL; currentRegisterArray = localStack.size() ? &localStack.last() : NULL;
AssertFatal(mStackDepth == localStack.size(), avar("Stack sizes do not match. mStackDepth = %d, localStack = %d", mStackDepth, localStack.size()));
#ifdef DEBUG_SPEW #ifdef DEBUG_SPEW
validate(); validate();
#endif #endif
@ -671,7 +675,7 @@ void ExprEvalState::popFrame()
void ExprEvalState::pushFrameRef(S32 stackIndex) void ExprEvalState::pushFrameRef(S32 stackIndex)
{ {
AssertFatal(stackIndex >= 0 && stackIndex < stack.size(), "You must be asking for a valid frame!"); AssertFatal(stackIndex >= 0 && stackIndex < mStackDepth, "You must be asking for a valid frame!");
#ifdef DEBUG_SPEW #ifdef DEBUG_SPEW
validate(); validate();
@ -695,6 +699,12 @@ void ExprEvalState::pushFrameRef(S32 stackIndex)
mStackDepth++; mStackDepth++;
currentVariable = NULL; currentVariable = NULL;
ConsoleValue* values = localStack[stackIndex].values;
localStack.push_back(ConsoleValueFrame(values, true));
currentRegisterArray = &localStack.last();
AssertFatal(mStackDepth == localStack.size(), avar("Stack sizes do not match. mStackDepth = %d, localStack = %d", mStackDepth, localStack.size()));
#ifdef DEBUG_SPEW #ifdef DEBUG_SPEW
validate(); validate();
#endif #endif

View file

@ -494,6 +494,8 @@ public:
/// an interior pointer that will become invalid when the object changes address. /// an interior pointer that will become invalid when the object changes address.
Vector< Dictionary* > stack; Vector< Dictionary* > stack;
S32 getTopOfStack() { return (S32)mStackDepth; }
Vector< ConsoleValueFrame > localStack; Vector< ConsoleValueFrame > localStack;
ConsoleValueFrame* currentRegisterArray; // contains array at to top of localStack ConsoleValueFrame* currentRegisterArray; // contains array at to top of localStack

View file

@ -151,7 +151,7 @@ template< typename T >
inline void EngineMarshallData( const T& arg, S32& argc, ConsoleValue *argv ) inline void EngineMarshallData( const T& arg, S32& argc, ConsoleValue *argv )
{ {
const char* str = castConsoleTypeToString(arg);; const char* str = castConsoleTypeToString(arg);;
argv[ argc++ ].setString(str, dStrlen(str)); argv[ argc++ ].setString(str);
} }
inline void EngineMarshallData( bool arg, S32& argc, ConsoleValue *argv ) inline void EngineMarshallData( bool arg, S32& argc, ConsoleValue *argv )
{ {

View file

@ -30,139 +30,99 @@
#include "math/mMath.h" #include "math/mMath.h"
#include "console/stringStack.h" #include "console/stringStack.h"
template<typename T> inline ConsoleValue RunScript(const char* str)
inline T Convert(ConsoleValue&);
template<>
inline U32 Convert(ConsoleValue &val)
{ {
return val.getInt(); return std::move(Con::evaluate(str, false, NULL));
}
template<>
inline S32 Convert(ConsoleValue &val)
{
return val.getInt();
}
template<>
inline bool Convert(ConsoleValue &val)
{
return val.getBool();
}
template<>
inline F32 Convert(ConsoleValue &val)
{
return val.getFloat();
}
template<>
inline const char* Convert(ConsoleValue &val)
{
return val.getString();
}
template<>
inline SimObject* Convert(ConsoleValue &val)
{
return Sim::findObject(val);
}
template<typename T>
inline T RunScript(const char* str)
{
return Convert<T>(std::move(Con::evaluate(str, false, NULL)));
} }
TEST(Script, Basic_Arithmetic) TEST(Script, Basic_Arithmetic)
{ {
S32 add = RunScript<S32>(R"( ConsoleValue add = RunScript(R"(
return 1.0 + 1; return 1.0 + 1;
)"); )");
EXPECT_EQ(add, 2); ASSERT_EQ(add.getInt(), 2);
S32 sub = RunScript<S32>(R"( ConsoleValue sub = RunScript(R"(
return 10 - 1.0; return 10 - 1.0;
)"); )");
EXPECT_EQ(sub, 9); ASSERT_EQ(sub.getInt(), 9);
S32 mult = RunScript<S32>(R"( ConsoleValue mult = RunScript(R"(
return 10 * 2.5; return 10 * 2.5;
)"); )");
EXPECT_EQ(mult, 25); ASSERT_EQ(mult.getInt(), 25);
S32 div = RunScript<S32>(R"( ConsoleValue div = RunScript(R"(
return 10.0 / 2; return 10.0 / 2;
)"); )");
EXPECT_EQ(div, 5); ASSERT_EQ(div.getInt(), 5);
} }
TEST(Script, Complex_Arithmetic) TEST(Script, Complex_Arithmetic)
{ {
S32 result = RunScript<S32>(R"( ConsoleValue result = RunScript(R"(
return 1 * 2 - (0.5 * 2); return 1 * 2 - (0.5 * 2);
)"); )");
EXPECT_EQ(result, 1); ASSERT_EQ(result.getInt(), 1);
S32 result2 = RunScript<S32>(R"( ConsoleValue result2 = RunScript(R"(
return 1 * 2 * 3 % 2; return 1 * 2 * 3 % 2;
)"); )");
EXPECT_EQ(result2, 0); ASSERT_EQ(result2.getInt(), 0);
} }
TEST(Script, Basic_Concatination) TEST(Script, Basic_Concatination)
{ {
const char* result1 = RunScript<const char*>(R"( ConsoleValue result1 = RunScript(R"(
return "a" @ "b"; return "a" @ "b";
)"); )");
EXPECT_STREQ(result1, "ab"); ASSERT_STREQ(result1.getString(), "ab");
const char* result2 = RunScript<const char*>(R"( ConsoleValue result2 = RunScript(R"(
return "a" SPC "b"; return "a" SPC "b";
)"); )");
EXPECT_STREQ(result2, "a b"); ASSERT_STREQ(result2.getString(), "a b");
const char* result3 = RunScript<const char*>(R"( ConsoleValue result3 = RunScript(R"(
return "a" TAB "b"; return "a" TAB "b";
)"); )");
EXPECT_STREQ(result3, "a\tb"); ASSERT_STREQ(result3.getString(), "a\tb");
const char* result4 = RunScript<const char*>(R"( ConsoleValue result4 = RunScript(R"(
return "a" NL "b"; return "a" NL "b";
)"); )");
EXPECT_STREQ(result4, "a\nb"); ASSERT_STREQ(result4.getString(), "a\nb");
const char* complex = RunScript<const char*>(R"( ConsoleValue complex = RunScript(R"(
return "a" @ "b" @ "c" @ "d"; return "a" @ "b" @ "c" @ "d";
)"); )");
EXPECT_STREQ(complex, "abcd"); ASSERT_STREQ(complex.getString(), "abcd");
} }
TEST(Script, Basic_Global_Variable_Tests) TEST(Script, Basic_Global_Variable_Tests)
{ {
S32 value = RunScript<S32>(R"( ConsoleValue value = RunScript(R"(
$a = 1; $a = 1;
return $a; return $a;
)"); )");
EXPECT_EQ(value, 1); ASSERT_EQ(value.getInt(), 1);
} }
TEST(Script, Variable_Chaining_And_Usage) TEST(Script, Variable_Chaining_And_Usage)
{ {
S32 value = RunScript<S32>(R"( ConsoleValue value = RunScript(R"(
function t() function t()
{ {
%a = %b = 2; %a = %b = 2;
@ -171,9 +131,9 @@ TEST(Script, Variable_Chaining_And_Usage)
return t(); return t();
)"); )");
EXPECT_EQ(value, 2); ASSERT_EQ(value.getInt(), 2);
S32 valueGlobal = RunScript<S32>(R"( ConsoleValue valueGlobal = RunScript(R"(
function t() function t()
{ {
$a = %b = 2; $a = %b = 2;
@ -182,9 +142,9 @@ TEST(Script, Variable_Chaining_And_Usage)
return $a; return $a;
)"); )");
EXPECT_EQ(valueGlobal, 2); ASSERT_EQ(valueGlobal.getInt(), 2);
S32 value2 = RunScript<S32>(R"( ConsoleValue value2 = RunScript(R"(
function t(%a) function t(%a)
{ {
if ((%b = 2 * %a) != 5) if ((%b = 2 * %a) != 5)
@ -195,26 +155,26 @@ TEST(Script, Variable_Chaining_And_Usage)
return t(2); return t(2);
)"); )");
EXPECT_EQ(value2, 4); ASSERT_EQ(value2.getInt(), 4);
} }
TEST(Script, Basic_Function_Call_And_Local_Variable_Testing) TEST(Script, Basic_Function_Call_And_Local_Variable_Testing)
{ {
S32 value = RunScript<S32>(R"( ConsoleValue value = RunScript(R"(
function t() { %a = 2; return %a; } function t() { %a = 2; return %a; }
return t(); return t();
)"); )");
EXPECT_EQ(value, 2); ASSERT_EQ(value.getInt(), 2);
S32 value2 = RunScript<S32>(R"( ConsoleValue value2 = RunScript(R"(
function add(%a, %b) { return %a + %b; } function add(%a, %b) { return %a + %b; }
return add(2, 4); return add(2, 4);
)"); )");
EXPECT_EQ(value2, 6); ASSERT_EQ(value2.getInt(), 6);
S32 value3 = RunScript<S32>(R"( ConsoleValue value3 = RunScript(R"(
function fib(%a) { function fib(%a) {
if (%a == 0) if (%a == 0)
return 0; return 0;
@ -225,48 +185,48 @@ TEST(Script, Basic_Function_Call_And_Local_Variable_Testing)
return fib(15); return fib(15);
)"); )");
EXPECT_EQ(value3, 610); ASSERT_EQ(value3.getInt(), 610);
S32 staticCall = RunScript<S32>(R"( ConsoleValue staticCall = RunScript(R"(
function SimObject::bar(%a, %b) { function SimObject::bar(%a, %b) {
return %a + %b; return %a + %b;
} }
return SimObject::bar(1, 2); return SimObject::bar(1, 2);
)"); )");
EXPECT_EQ(staticCall, 3); ASSERT_EQ(staticCall.getInt(), 3);
} }
TEST(Script, Basic_Conditional_Statements) TEST(Script, Basic_Conditional_Statements)
{ {
S32 value = RunScript<S32>(R"( ConsoleValue value = RunScript(R"(
$a = "hello"; $a = "hello";
if ($a $= "hello") if ($a $= "hello")
return 1; return 1;
return 2; return 2;
)"); )");
EXPECT_EQ(value, 1); ASSERT_EQ(value.getInt(), 1);
const char* ternaryValue = RunScript<const char*>(R"( ConsoleValue ternaryValue = RunScript(R"(
return $a $= "hello" ? "World" : "No U"; return $a $= "hello" ? "World" : "No U";
)"); )");
EXPECT_STREQ(ternaryValue, "World"); ASSERT_STREQ(ternaryValue.getString(), "World");
} }
TEST(Script, Basic_Loop_Statements) TEST(Script, Basic_Loop_Statements)
{ {
S32 whileValue = RunScript<S32>(R"( ConsoleValue whileValue = RunScript(R"(
$count = 0; $count = 0;
while ($count < 5) while ($count < 5)
$count++; $count++;
return $count; return $count;
)"); )");
EXPECT_EQ(whileValue, 5); ASSERT_EQ(whileValue.getInt(), 5);
const char* forValue = RunScript<const char*>(R"( ConsoleValue forValue = RunScript(R"(
function t(%times) function t(%times)
{ {
%result = ""; %result = "";
@ -278,9 +238,9 @@ TEST(Script, Basic_Loop_Statements)
return t(3); return t(3);
)"); )");
EXPECT_STREQ(forValue, "aaa"); ASSERT_STREQ(forValue.getString(), "aaa");
const char* forIfValue = RunScript<const char*>(R"( ConsoleValue forIfValue = RunScript(R"(
function t() { function t() {
%str = ""; %str = "";
for (%i = 0; %i < 5; %i++) { for (%i = 0; %i < 5; %i++) {
@ -298,43 +258,43 @@ TEST(Script, Basic_Loop_Statements)
return t(); return t();
)"); )");
EXPECT_STREQ(forIfValue, "0, 1, 2, 3, 4"); ASSERT_STREQ(forIfValue.getString(), "0, 1, 2, 3, 4");
} }
TEST(Script, TorqueScript_Array_Testing) TEST(Script, TorqueScript_Array_Testing)
{ {
S32 value = RunScript<S32>(R"( ConsoleValue value = RunScript(R"(
function t(%idx) { %a[idx] = 2; return %a[idx]; } function t(%idx) { %a[idx] = 2; return %a[idx]; }
return t(5); return t(5);
)"); )");
EXPECT_EQ(value, 2); ASSERT_EQ(value.getInt(), 2);
S32 value2 = RunScript<S32>(R"( ConsoleValue value2 = RunScript(R"(
function t(%idx) { %a[idx, 0] = 2; return %a[idx, 0]; } function t(%idx) { %a[idx, 0] = 2; return %a[idx, 0]; }
return t(5); return t(5);
)"); )");
EXPECT_EQ(value2, 2); ASSERT_EQ(value2.getInt(), 2);
} }
TEST(Script, Basic_SimObject) TEST(Script, Basic_SimObject)
{ {
SimObject* object = RunScript<SimObject*>(R"( ConsoleValue object = RunScript(R"(
return new SimObject(FudgeCollector) { return new SimObject(FudgeCollector) {
fudge = "Chocolate"; fudge = "Chocolate";
}; };
)"); )");
EXPECT_NE(object, (SimObject*)NULL); ASSERT_NE(Sim::findObject(object), (SimObject*)NULL);
const char* propertyValue = RunScript<const char*>(R"( ConsoleValue propertyValue = RunScript(R"(
return FudgeCollector.fudge; return FudgeCollector.fudge;
)"); )");
EXPECT_STREQ(propertyValue, "Chocolate"); ASSERT_STREQ(propertyValue.getString(), "Chocolate");
const char* funcReturn = RunScript<const char*>(R"( ConsoleValue funcReturn = RunScript(R"(
function SimObject::fooFunc(%this) function SimObject::fooFunc(%this)
{ {
return "Bar"; return "Bar";
@ -343,9 +303,9 @@ TEST(Script, Basic_SimObject)
return FudgeCollector.fooFunc(); return FudgeCollector.fooFunc();
)"); )");
EXPECT_STREQ(funcReturn, "Bar"); ASSERT_STREQ(funcReturn.getString(), "Bar");
const char* parentFn = RunScript<const char*>(R"( ConsoleValue parentFn = RunScript(R"(
new SimObject(Hello); new SimObject(Hello);
function SimObject::fooFunc2(%this) function SimObject::fooFunc2(%this)
@ -362,12 +322,12 @@ TEST(Script, Basic_SimObject)
return Hello.fooFunc2(); return Hello.fooFunc2();
)"); )");
EXPECT_STREQ(parentFn, "FooBar"); ASSERT_STREQ(parentFn.getString(), "FooBar");
} }
TEST(Script, Basic_Package) TEST(Script, Basic_Package)
{ {
S32 value = RunScript<S32>(R"( ConsoleValue value = RunScript(R"(
function a() { return 3; } function a() { return 3; }
package overrides { package overrides {
function a() { return 5; } function a() { return 5; }
@ -375,21 +335,21 @@ TEST(Script, Basic_Package)
return a(); return a();
)"); )");
EXPECT_EQ(value, 3); ASSERT_EQ(value.getInt(), 3);
S32 overrideValue = RunScript<S32>(R"( ConsoleValue overrideValue = RunScript(R"(
activatePackage(overrides); activatePackage(overrides);
return a(); return a();
)"); )");
EXPECT_EQ(overrideValue, 5); ASSERT_EQ(overrideValue.getInt(), 5);
S32 deactivatedValue = RunScript<S32>(R"( ConsoleValue deactivatedValue = RunScript(R"(
deactivatePackage(overrides); deactivatePackage(overrides);
return a(); return a();
)"); )");
EXPECT_EQ(deactivatedValue, 3); ASSERT_EQ(deactivatedValue.getInt(), 3);
} }
#endif #endif

View file

@ -428,7 +428,7 @@ S32 dStrlcpy(char *dst, const char *src, dsize_t dstSize)
S32 copyLen = srcLen; S32 copyLen = srcLen;
//Check for buffer overflow and don't allow it. Warn on debug so we can fix it //Check for buffer overflow and don't allow it. Warn on debug so we can fix it
AssertWarn(copyLen < dstSize, "Buffer too small in call to dStrlcpy!"); AssertFatal(copyLen < dstSize, "Buffer too small in call to dStrlcpy!");
if (srcLen + 1 > dstSize) if (srcLen + 1 > dstSize)
{ {
copyLen = dstSize - 1; copyLen = dstSize - 1;