Pārlūkot izejas kodu

Fix bugs with certain properties (and .x .y .z accessors) and add tests.

Jeff Hutchinson 4 gadi atpakaļ
vecāks
revīzija
6ec40e86da

+ 13 - 29
Engine/source/console/astNodes.cpp

@@ -1262,9 +1262,10 @@ U32 SlotAccessNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
    codeStream.emit(OP_SETCUROBJECT);
 
    codeStream.emit(OP_SETCURFIELD);
-
    codeStream.emitSTE(slotName);
 
+   codeStream.emit(OP_POP_STK);
+
    if (arrayExpr)
    {
       codeStream.emit(OP_SETCURFIELD_ARRAY);
@@ -1307,6 +1308,8 @@ U32 InternalSlotAccessNode::compile(CodeStream& codeStream, U32 ip, TypeReq type
    codeStream.emit(OP_SETCUROBJECT_INTERNAL);
    codeStream.emit(recurse);
 
+   codeStream.emit(OP_POP_STK);
+
    return codeStream.tell();
 }
 
@@ -1319,34 +1322,6 @@ TypeReq InternalSlotAccessNode::getPreferredType()
 
 U32 SlotAssignNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
 {
-   // first eval the expression TypeReqString
-
-   // if it's an array:
-
-   // if OP_ADVANCE_STR 1
-   // eval array
-
-   // OP_ADVANCE_STR 1
-   // evaluate object expr
-   // OP_SETCUROBJECT 1
-   // OP_SETCURFIELD 1
-   // fieldName 1
-   // OP_TERMINATE_REWIND_STR 1
-
-   // OP_SETCURFIELDARRAY 1
-   // OP_TERMINATE_REWIND_STR 1
-
-   // else
-   // OP_ADVANCE_STR
-   // evaluate object expr
-   // OP_SETCUROBJECT
-   // OP_SETCURFIELD
-   // fieldName
-   // OP_TERMINATE_REWIND_STR
-
-   // OP_SAVEFIELD
-   // convert to return type if necessary.
-
    precompileIdent(slotName);
 
    ip = valueExpr->compile(codeStream, ip, TypeReqString);
@@ -1364,6 +1339,13 @@ U32 SlotAssignNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
    codeStream.emit(OP_SETCURFIELD);
    codeStream.emitSTE(slotName);
 
+   if (objectExpr)
+   {
+      // Don't pop unless we are assigning a field to an object
+      // (For initializer fields, we don't wanna pop)
+      codeStream.emit(OP_POP_STK);
+   }
+
    if (arrayExpr)
    {
       codeStream.emit(OP_SETCURFIELD_ARRAY);
@@ -1429,6 +1411,8 @@ U32 SlotAssignOpNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
    codeStream.emit(OP_SETCURFIELD);
    codeStream.emitSTE(slotName);
 
+   codeStream.emit(OP_POP_STK);
+
    if (arrayExpr)
    {
       codeStream.emit(OP_SETCURFIELD_ARRAY);

+ 1 - 1
Engine/source/console/codeBlock.cpp

@@ -1114,7 +1114,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
 
       case OP_SETCUROBJECT:
       {
-         Con::printf("%i: OP_SETCUROBJECT stk=-1", ip - 1);
+         Con::printf("%i: OP_SETCUROBJECT stk=0", ip - 1);
          break;
       }
 

+ 50 - 18
Engine/source/console/compiledEval.cpp

@@ -166,18 +166,17 @@ namespace Con
 
 // Gets a component of an object's field value or a variable and returns it
 // in val.
-static void getFieldComponent(SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField, char val[])
+static void getFieldComponent(SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField, char val[], S32 currentLocalRegister)
 {
    const char* prevVal = NULL;
 
    // Grab value from object.
    if (object && field)
       prevVal = object->getDataField(field, array);
-
-   // Otherwise, grab from the string stack. The value coming in will always
-   // be a string because that is how multicomponent variables are handled.
-   else
-      prevVal = stack[_STK].getString();
+   else if (currentLocalRegister != -1)
+      prevVal = gEvalState.getLocalStringVariable(currentLocalRegister);
+   else if (gEvalState.currentVariable)
+      prevVal = gEvalState.getStringVariable();
 
    // Make sure we got a value.
    if (prevVal && *prevVal)
@@ -198,15 +197,22 @@ static void getFieldComponent(SimObject* object, StringTableEntry field, const c
          StringTable->insert("a")
       };
 
+      static const StringTableEntry uvw[] =
+      {
+         StringTable->insert("u"),
+         StringTable->insert("v"),
+         StringTable->insert("w")
+      };
+
       // Translate xyzw and rgba into the indexed component 
       // of the variable or field.
-      if (subField == xyzw[0] || subField == rgba[0])
+      if (subField == xyzw[0] || subField == rgba[0] || subField == uvw[0])
          dStrcpy(val, StringUnit::getUnit(prevVal, 0, " \t\n"), 128);
 
-      else if (subField == xyzw[1] || subField == rgba[1])
+      else if (subField == xyzw[1] || subField == rgba[1] || subField == uvw[1])
          dStrcpy(val, StringUnit::getUnit(prevVal, 1, " \t\n"), 128);
 
-      else if (subField == xyzw[2] || subField == rgba[2])
+      else if (subField == xyzw[2] || subField == rgba[2] || subField == uvw[2])
          dStrcpy(val, StringUnit::getUnit(prevVal, 2, " \t\n"), 128);
 
       else if (subField == xyzw[3] || subField == rgba[3])
@@ -221,7 +227,7 @@ static void getFieldComponent(SimObject* object, StringTableEntry field, const c
 
 // Sets a component of an object's field value based on the sub field. 'x' will
 // set the first field, 'y' the second, and 'z' the third.
-static void setFieldComponent(SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField)
+static void setFieldComponent(SimObject* object, StringTableEntry field, const char* array, StringTableEntry subField, S32 currentLocalRegister)
 {
    // Copy the current string value
    char strValue[1024];
@@ -233,7 +239,8 @@ static void setFieldComponent(SimObject* object, StringTableEntry field, const c
    // Set the value on an object field.
    if (object && field)
       prevVal = object->getDataField(field, array);
-
+   else if (currentLocalRegister != -1)
+      prevVal = gEvalState.getLocalStringVariable(currentLocalRegister);
    // Set the value on a variable.
    else if (gEvalState.currentVariable)
       prevVal = gEvalState.getStringVariable();
@@ -277,6 +284,8 @@ static void setFieldComponent(SimObject* object, StringTableEntry field, const c
       // Update the field or variable.
       if (object && field)
          object->setDataField(field, 0, val);
+      else if (currentLocalRegister != -1)
+         gEvalState.setLocalStringVariable(currentLocalRegister, val, dStrlen(val));
       else if (gEvalState.currentVariable)
          gEvalState.setStringVariable(val);
    }
@@ -758,6 +767,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
    }
    const char* val;
    S32 reg;
+   S32 currentRegister = -1;
 
    // The frame temp is used by the variable accessor ops (OP_SAVEFIELD_* and
    // OP_LOADFIELD_*) to store temporary values for the fields.
@@ -1427,6 +1437,10 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          prevObject = NULL;
          curObject = NULL;
 
+         // Used for local variable caching of what is active...when we
+         // set a global, we aren't active
+         currentRegister = -1;
+
          gEvalState.setCurVarName(var);
 
          // In order to let docblocks work properly with variables, we have
@@ -1445,6 +1459,10 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          prevObject = NULL;
          curObject = NULL;
 
+         // Used for local variable caching of what is active...when we
+         // set a global, we aren't active
+         currentRegister = -1;
+
          gEvalState.setCurVarNameCreate(var);
 
          // See OP_SETCURVAR for why we do this.
@@ -1460,6 +1478,10 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          prevObject = NULL;
          curObject = NULL;
 
+         // Used for local variable caching of what is active...when we
+         // set a global, we aren't active
+         currentRegister = -1;
+
          gEvalState.setCurVarName(var);
 
          // See OP_SETCURVAR for why we do this.
@@ -1475,6 +1497,10 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          prevObject = NULL;
          curObject = NULL;
 
+         // Used for local variable caching of what is active...when we
+         // set a global, we aren't active
+         currentRegister = -1;
+
          gEvalState.setCurVarNameCreate(var);
 
          // See OP_SETCURVAR for why we do this.
@@ -1483,16 +1509,19 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          break;
 
       case OP_LOADVAR_UINT:
+         currentRegister = -1;
          stack[_STK + 1].setInt(gEvalState.getIntVariable());
          _STK++;
          break;
 
       case OP_LOADVAR_FLT:
+         currentRegister = -1;
          stack[_STK + 1].setFloat(gEvalState.getFloatVariable());
          _STK++;
          break;
 
       case OP_LOADVAR_STR:
+         currentRegister = -1;
          stack[_STK + 1].setString(gEvalState.getStringVariable());
          _STK++;
          break;
@@ -1511,18 +1540,21 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
 
       case OP_LOAD_LOCAL_VAR_UINT:
          reg = code[ip++];
+         currentRegister = reg;
          stack[_STK + 1].setInt(gEvalState.getLocalIntVariable(reg));
          _STK++;
          break;
 
       case OP_LOAD_LOCAL_VAR_FLT:
          reg = code[ip++];
+         currentRegister = reg;
          stack[_STK + 1].setFloat(gEvalState.getLocalFloatVariable(reg));
          _STK++;
          break;
 
       case OP_LOAD_LOCAL_VAR_STR:
          reg = code[ip++];
+         currentRegister = reg;
          val = gEvalState.getLocalStringVariable(reg);
          stack[_STK + 1].setString(val);
          _STK++;
@@ -1548,7 +1580,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          // Save the previous object for parsing vector fields.
          prevObject = curObject;
          val = stack[_STK].getString();
-         _STK--;
+         //_STK--;
 
          // Sim::findObject will sometimes find valid objects from
          // multi-component strings. This makes sure that doesn't
@@ -1616,7 +1648,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             // a special accessor?
             char buff[FieldBufferSizeNumeric];
             memset(buff, 0, sizeof(buff));
-            getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff);
+            getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff, currentRegister);
             stack[_STK + 1].setInt(dAtol(buff));
          }
          _STK++;
@@ -1631,7 +1663,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             // a special accessor?
             char buff[FieldBufferSizeNumeric];
             memset(buff, 0, sizeof(buff));
-            getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff);
+            getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff, currentRegister);
             stack[_STK + 1].setFloat(dAtod(buff));
          }
          _STK++;
@@ -1649,7 +1681,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             // a special accessor?
             char buff[FieldBufferSizeString];
             memset(buff, 0, sizeof(buff));
-            getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff);
+            getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff, currentRegister);
             stack[_STK + 1].setString(buff);
          }
          _STK++;
@@ -1662,7 +1694,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          {
             // The field is not being set on an object. Maybe it's
             // a special accessor?
-            setFieldComponent( prevObject, prevField, prevFieldArray, curField );
+            setFieldComponent( prevObject, prevField, prevFieldArray, curField, currentRegister );
             prevObject = NULL;
          }
          break;
@@ -1674,7 +1706,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          {
             // The field is not being set on an object. Maybe it's
             // a special accessor?
-            setFieldComponent( prevObject, prevField, prevFieldArray, curField );
+            setFieldComponent( prevObject, prevField, prevFieldArray, curField, currentRegister );
             prevObject = NULL;
          }
          break;
@@ -1686,7 +1718,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          {
             // The field is not being set on an object. Maybe it's
             // a special accessor?
-            setFieldComponent( prevObject, prevField, prevFieldArray, curField );
+            setFieldComponent( prevObject, prevField, prevFieldArray, curField, currentRegister );
             prevObject = NULL;
          }
          break;

+ 61 - 0
Engine/source/console/test/ScriptTest.cpp

@@ -471,6 +471,17 @@ TEST(Script, Basic_SimObject)
 
    ASSERT_STREQ(parentFn.getString(), "FooBar");
 
+   ConsoleValue simpleFieldTest = RunScript(R"(
+         function a()
+         {
+            FudgeCollector.field = "A";
+            return FudgeCollector.field;
+         }
+         return a();
+   )");
+
+   ASSERT_STREQ(simpleFieldTest.getString(), "A");
+
    ConsoleValue grp = RunScript(R"(
          new SimGroup(FudgeCollectorGroup)
          {
@@ -587,4 +598,54 @@ TEST(Script, Basic_Package)
    ASSERT_EQ(deactivatedValue.getInt(), 3);
 }
 
+TEST(Script, Sugar_Syntax)
+{
+   ConsoleValue value = RunScript(R"(
+         function a()
+         {
+            %vector = "1 2 3";
+            return %vector.y;
+         }
+         return a();
+   )");
+
+   ASSERT_EQ(value.getInt(), 2);
+
+   ConsoleValue setValue = RunScript(R"(
+         function a()
+         {
+            %vector = "1 2 3";
+            %vector.y = 4;
+            return %vector.y;
+         }
+         return a();
+   )");
+
+   ASSERT_EQ(setValue.getInt(), 4);
+
+   ConsoleValue valueArray = RunScript(R"(
+         function a()
+         {
+            %vector[0] = "1 2 3";
+            return %vector[0].y;
+         }
+         return a();
+   )");
+
+   ASSERT_EQ(valueArray.getInt(), 2);
+
+   ConsoleValue valueSetArray = RunScript(R"(
+         function a()
+         {
+            %vector[0] = "1 2 3";
+            %vector[0].z = 5;
+            return %vector[0].z;
+         }
+         return a();
+   )");
+
+   ASSERT_EQ(valueSetArray.getInt(), 5);
+}
+
+
 #endif