Home | History | Annotate | Download | only in animator
      1 #include "SkScript2.h"
      2 #include "SkFloatingPoint.h"
      3 #include "SkMath.h"
      4 #include "SkParse.h"
      5 #include "SkScriptCallBack.h"
      6 #include "SkScriptRuntime.h"
      7 #include "SkString.h"
      8 #include "SkOpArray.h"
      9 
     10 const SkScriptEngine2::OperatorAttributes SkScriptEngine2::gOpAttributes[] = {
     11 { SkOperand2::kNoType, SkOperand2::kNoType, kNoBias, kResultIsNotBoolean },
     12 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString),
     13     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsString, kResultIsNotBoolean },    // kAdd
     14 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitAnd
     15 { SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitNot
     16 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitOr
     17 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
     18     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kDivide
     19 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString),
     20     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar |SkOperand2:: kString), kTowardsNumber,
     21     kResultIsBoolean }, // kEqual
     22 { SkOperand2::kS32, SkOperand2::kNoType, kNoBias, kResultIsNotBoolean },     // kFlipOps
     23 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString),
     24     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsNumber,
     25     kResultIsBoolean }, // kGreaterEqual
     26 { SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalAnd    (really, ToBool)
     27 { SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalNot
     28 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalOr
     29 { SkOperand2::kNoType, SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kMinus
     30 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
     31     SkOperand2::OpType(SkOperand2::kS32 |SkOperand2:: kScalar), kNoBias, kResultIsNotBoolean }, // kModulo
     32 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
     33     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kMultiply
     34 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kShiftLeft
     35 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kShiftRight
     36 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
     37     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kSubtract
     38 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean } // kXor
     39 };
     40 
     41 #define kBracketPrecedence 16
     42 #define kIfElsePrecedence 15
     43 
     44 const signed char SkScriptEngine2::gPrecedence[] = {
     45     17, // kUnassigned,
     46     6, // kAdd,
     47     10, // kBitAnd,
     48     4, // kBitNot,
     49     12, // kBitOr,
     50     5, // kDivide,
     51     9, // kEqual,
     52     -1, // kFlipOps,
     53     8, // kGreaterEqual,
     54     13, // kLogicalAnd,
     55     4, // kLogicalNot,
     56     14, // kLogicalOr,
     57     4, // kMinus,
     58     5, // kModulo,
     59     5, // kMultiply,
     60     7, // kShiftLeft,
     61     7, // kShiftRight,    // signed
     62     6, // kSubtract,
     63     11, // kXor
     64     kBracketPrecedence, // kArrayOp
     65     kIfElsePrecedence, // kElse
     66     kIfElsePrecedence, // kIf
     67     kBracketPrecedence, // kParen
     68 };
     69 
     70 const SkScriptEngine2::TypeOp SkScriptEngine2::gTokens[] = {
     71     kNop, // unassigned
     72     kAddInt, // kAdd,
     73     kBitAndInt, // kBitAnd,
     74     kBitNotInt, // kBitNot,
     75     kBitOrInt, // kBitOr,
     76     kDivideInt, // kDivide,
     77     kEqualInt, // kEqual,
     78     kFlipOpsOp, // kFlipOps,
     79     kGreaterEqualInt, // kGreaterEqual,
     80     kLogicalAndInt, // kLogicalAnd,
     81     kLogicalNotInt, // kLogicalNot,
     82     kLogicalOrInt, // kLogicalOr,
     83     kMinusInt, // kMinus,
     84     kModuloInt, // kModulo,
     85     kMultiplyInt, // kMultiply,
     86     kShiftLeftInt, // kShiftLeft,
     87     kShiftRightInt, // kShiftRight,    // signed
     88     kSubtractInt, // kSubtract,
     89     kXorInt // kXor
     90 };
     91 
     92 static inline bool is_between(int c, int min, int max)
     93 {
     94     return (unsigned)(c - min) <= (unsigned)(max - min);
     95 }
     96 
     97 static inline bool is_ws(int c)
     98 {
     99     return is_between(c, 1, 32);
    100 }
    101 
    102 static int token_length(const char* start) {
    103     char ch = start[0];
    104     if (! is_between(ch, 'a' , 'z') &&  ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$')
    105         return -1;
    106     int length = 0;
    107     do
    108         ch = start[++length];
    109     while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') ||
    110            ch == '_' || ch == '$');
    111     return length;
    112 }
    113 
    114 SkScriptEngine2::SkScriptEngine2(SkOperand2::OpType returnType) : fActiveStream(&fStream),
    115 fTokenLength(0), fReturnType(returnType), fError(kNoError),
    116 fAccumulatorType(SkOperand2::kNoType),
    117 fBranchPopAllowed(true), fConstExpression(true), fOperandInUse(false)
    118 {
    119     Branch branch(kUnassigned, 0, 0);
    120     fBranchStack.push(branch);
    121     *fOpStack.push() = (Op) kParen;
    122 }
    123 
    124 SkScriptEngine2::~SkScriptEngine2() {
    125     for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
    126         delete *stringPtr;
    127     for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
    128         delete *arrayPtr;
    129 }
    130 
    131 void SkScriptEngine2::addToken(SkScriptEngine2::TypeOp op) {
    132     int limit = fBranchStack.count() - 1;
    133     for (int index = 0; index < limit; index++) {
    134         Branch& branch = fBranchStack.index(index);
    135         if (branch.fPrimed == Branch::kIsPrimed)
    136             resolveBranch(branch);
    137     }
    138     if (fBranchPopAllowed) {
    139         while (fBranchStack.top().fDone == Branch::kIsDone)
    140             fBranchStack.pop();
    141     }
    142     unsigned char charOp = (unsigned char) op;
    143     fActiveStream->write(&charOp, sizeof(charOp));
    144 }
    145 
    146 void SkScriptEngine2::addTokenConst(SkScriptValue2* value, AddTokenRegister reg,
    147                                     SkOperand2::OpType toType, SkScriptEngine2::TypeOp op) {
    148     if (value->fIsConstant == SkScriptValue2::kConstant && convertTo(toType, value))
    149         return;
    150     addTokenValue(*value, reg);
    151     addToken(op);
    152     value->fIsWritten = SkScriptValue2::kWritten;
    153     value->fType = toType;
    154 }
    155 
    156 void SkScriptEngine2::addTokenInt(int integer) {
    157     fActiveStream->write(&integer, sizeof(integer));
    158 }
    159 
    160 void SkScriptEngine2::addTokenScalar(SkScalar scalar) {
    161     fActiveStream->write(&scalar, sizeof(scalar));
    162 }
    163 
    164 void SkScriptEngine2::addTokenString(const SkString& string) {
    165     int size = string.size();
    166     addTokenInt(size);
    167     fActiveStream->write(string.c_str(), size);
    168 }
    169 
    170 void SkScriptEngine2::addTokenValue(const SkScriptValue2& value, AddTokenRegister reg) {
    171     if (value.isConstant() == false) {
    172         if (reg == kAccumulator) {
    173             if (fAccumulatorType == SkOperand2::kNoType)
    174                 addToken(kAccumulatorPop);
    175         } else {
    176             ; // !!! incomplete?
    177         }
    178         return;
    179     }
    180     if (reg == kAccumulator && fAccumulatorType != SkOperand2::kNoType)
    181         addToken(kAccumulatorPush);
    182     switch (value.fType) {
    183         case SkOperand2::kS32:
    184             addToken(reg == kAccumulator ? kIntegerAccumulator : kIntegerOperand);
    185             addTokenInt(value.fOperand.fS32);
    186             if (reg == kAccumulator)
    187                 fAccumulatorType = SkOperand2::kS32;
    188             else
    189                 fOperandInUse = true;
    190             break;
    191         case SkOperand2::kScalar:
    192             addToken(reg == kAccumulator ? kScalarAccumulator : kScalarOperand);
    193             addTokenScalar(value.fOperand.fScalar);
    194             if (reg == kAccumulator)
    195                 fAccumulatorType = SkOperand2::kScalar;
    196             else
    197                 fOperandInUse = true;
    198             break;
    199         case SkOperand2::kString:
    200             addToken(reg == kAccumulator ? kStringAccumulator : kStringOperand);
    201             addTokenString(*value.fOperand.fString);
    202             if (reg == kAccumulator)
    203                 fAccumulatorType = SkOperand2::kString;
    204             else
    205                 fOperandInUse = true;
    206             break;
    207         default:
    208             SkASSERT(0); //!!! not implemented yet
    209     }
    210 }
    211 
    212 int SkScriptEngine2::arithmeticOp(char ch, char nextChar, bool lastPush) {
    213     Op op = kUnassigned;
    214     bool reverseOperands = false;
    215     bool negateResult = false;
    216     int advance = 1;
    217     switch (ch) {
    218         case '+':
    219             // !!! ignoring unary plus as implemented here has the side effect of
    220             // suppressing errors like +"hi"
    221             if (lastPush == false)    // unary plus, don't push an operator
    222                 return advance;
    223             op = kAdd;
    224             break;
    225         case '-':
    226             op = lastPush ? kSubtract : kMinus;
    227             break;
    228         case '*':
    229             op = kMultiply;
    230             break;
    231         case '/':
    232             op = kDivide;
    233             break;
    234         case '>':
    235             if (nextChar == '>') {
    236                 op = kShiftRight;
    237                 goto twoChar;
    238             }
    239             op = kGreaterEqual;
    240             if (nextChar == '=')
    241                 goto twoChar;
    242                 reverseOperands = negateResult = true;
    243             break;
    244         case '<':
    245             if (nextChar == '<') {
    246                 op = kShiftLeft;
    247                 goto twoChar;
    248             }
    249             op = kGreaterEqual;
    250             reverseOperands = nextChar == '=';
    251             negateResult = ! reverseOperands;
    252             advance += reverseOperands;
    253             break;
    254         case '=':
    255             if (nextChar == '=') {
    256                 op = kEqual;
    257                 goto twoChar;
    258             }
    259             break;
    260         case '!':
    261             if (nextChar == '=') {
    262                 op = kEqual;
    263                 negateResult = true;
    264 twoChar:
    265                     advance++;
    266                 break;
    267             }
    268             op = kLogicalNot;
    269             break;
    270         case '?':
    271             op =(Op)  kIf;
    272             break;
    273         case ':':
    274             op = (Op) kElse;
    275             break;
    276         case '^':
    277             op = kXor;
    278             break;
    279         case '(':
    280             *fOpStack.push() = (Op) kParen;
    281             return advance;
    282         case '&':
    283             SkASSERT(nextChar != '&');
    284             op = kBitAnd;
    285             break;
    286         case '|':
    287             SkASSERT(nextChar != '|');
    288             op = kBitOr;
    289             break;
    290         case '%':
    291             op = kModulo;
    292             break;
    293         case '~':
    294             op = kBitNot;
    295             break;
    296     }
    297     if (op == kUnassigned)
    298         return 0;
    299     signed char precedence = gPrecedence[op];
    300     do {
    301         int idx = 0;
    302         Op compare;
    303         do {
    304             compare = fOpStack.index(idx);
    305             if ((compare & kArtificialOp) == 0)
    306                 break;
    307             idx++;
    308         } while (true);
    309         signed char topPrecedence = gPrecedence[compare];
    310         SkASSERT(topPrecedence != -1);
    311         if (topPrecedence > precedence || (topPrecedence == precedence &&
    312             gOpAttributes[op].fLeftType == SkOperand2::kNoType)) {
    313             break;
    314         }
    315         processOp();
    316     } while (true);
    317     if (negateResult)
    318         *fOpStack.push() = (Op) (kLogicalNot | kArtificialOp);
    319     fOpStack.push(op);
    320     if (reverseOperands)
    321         *fOpStack.push() = (Op) (kFlipOps | kArtificialOp);
    322 
    323     return advance;
    324 }
    325 
    326 bool SkScriptEngine2::convertParams(SkTDArray<SkScriptValue2>* params,
    327                                     const SkOperand2::OpType* paramTypes, int paramCount) {
    328     int count = params->count();
    329     if (count > paramCount) {
    330         SkASSERT(0);
    331         return false;    // too many parameters passed
    332     }
    333     for (int index = 0; index < count; index++)
    334         convertTo(paramTypes[index], &(*params)[index]);
    335     return true;
    336 }
    337 
    338 bool SkScriptEngine2::convertTo(SkOperand2::OpType toType, SkScriptValue2* value ) {
    339     SkOperand2::OpType type = value->fType;
    340     if (type == toType)
    341         return true;
    342     if (type == SkOperand2::kObject) {
    343         if (handleUnbox(value) == false)
    344             return false;
    345         return convertTo(toType, value);
    346     }
    347     return ConvertTo(this, toType, value);
    348 }
    349 
    350 bool SkScriptEngine2::evaluateDot(const char*& script) {
    351     size_t fieldLength = token_length(++script);        // skip dot
    352     SkASSERT(fieldLength > 0); // !!! add error handling
    353     const char* field = script;
    354     script += fieldLength;
    355     bool success = handleProperty();
    356     if (success == false) {
    357         fError = kCouldNotFindReferencedID;
    358         goto error;
    359     }
    360     return evaluateDotParam(script, field, fieldLength);
    361 error:
    362         return false;
    363 }
    364 
    365 bool SkScriptEngine2::evaluateDotParam(const char*& script, const char* field, size_t fieldLength) {
    366     SkScriptValue2& top = fValueStack.top();
    367     if (top.fType != SkOperand2::kObject)
    368         return false;
    369     void* object = top.fOperand.fObject;
    370     fValueStack.pop();
    371     char ch; // see if it is a simple member or a function
    372     while (is_ws(ch = script[0]))
    373         script++;
    374     bool success = true;
    375     if (ch != '(')
    376         success = handleMember(field, fieldLength, object);
    377     else {
    378         SkTDArray<SkScriptValue2> params;
    379         *fBraceStack.push() = kFunctionBrace;
    380         success = functionParams(&script, &params);
    381         if (success)
    382             success = handleMemberFunction(field, fieldLength, object, &params);
    383     }
    384     return success;
    385 }
    386 
    387 bool SkScriptEngine2::evaluateScript(const char** scriptPtr, SkScriptValue2* value) {
    388     //    fArrayOffset = 0;        // no support for structures for now
    389     bool success;
    390     const char* inner;
    391     if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) {
    392         *scriptPtr += sizeof("#script:") - 1;
    393         if (fReturnType == SkOperand2::kNoType || fReturnType == SkOperand2::kString) {
    394             success = innerScript(scriptPtr, value);
    395             SkASSERT(success);
    396             inner = value->fOperand.fString->c_str();
    397             scriptPtr = &inner;
    398         }
    399     }
    400     success = innerScript(scriptPtr, value);
    401     const char* script = *scriptPtr;
    402     char ch;
    403     while (is_ws(ch = script[0]))
    404         script++;
    405     if (ch != '\0') {
    406         // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]"
    407         return false;
    408     }
    409     return success;
    410 }
    411 
    412 void SkScriptEngine2::forget(SkOpArray* array) {
    413     if (array->getType() == SkOperand2::kString) {
    414         for (int index = 0; index < array->count(); index++) {
    415             SkString* string = (*array)[index].fString;
    416             int found = fTrackString.find(string);
    417             if (found >= 0)
    418                 fTrackString.remove(found);
    419         }
    420         return;
    421     }
    422     if (array->getType() == SkOperand2::kArray) {
    423         for (int index = 0; index < array->count(); index++) {
    424             SkOpArray* child = (*array)[index].fArray;
    425             forget(child);    // forgets children of child
    426             int found = fTrackArray.find(child);
    427             if (found >= 0)
    428                 fTrackArray.remove(found);
    429         }
    430     }
    431 }
    432 
    433 bool SkScriptEngine2::functionParams(const char** scriptPtr, SkTDArray<SkScriptValue2>* params) {
    434     (*scriptPtr)++; // skip open paren
    435     *fOpStack.push() = (Op) kParen;
    436     *fBraceStack.push() = kFunctionBrace;
    437     do {
    438         SkScriptValue2 value;
    439         bool success = innerScript(scriptPtr, &value);
    440         SkASSERT(success);
    441         if (success == false)
    442             return false;
    443         *params->append() = value;
    444     } while ((*scriptPtr)[-1] == ',');
    445     fBraceStack.pop();
    446     fOpStack.pop(); // pop paren
    447     (*scriptPtr)++; // advance beyond close paren
    448     return true;
    449 }
    450 
    451 size_t SkScriptEngine2::getTokenOffset() {
    452     return fActiveStream->getOffset();
    453 }
    454 
    455 SkOperand2::OpType SkScriptEngine2::getUnboxType(SkOperand2 scriptValue) {
    456     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    457         if ((*callBack)->getType() != SkScriptCallBack::kUnbox)
    458             continue;
    459         return (*callBack)->getReturnType(0, &scriptValue);
    460     }
    461     return SkOperand2::kObject;
    462 }
    463 
    464 bool SkScriptEngine2::innerScript(const char** scriptPtr, SkScriptValue2* value) {
    465     const char* script = *scriptPtr;
    466     char ch;
    467     bool lastPush = false;
    468     bool success = true;
    469     int opBalance = fOpStack.count();
    470     int baseBrace = fBraceStack.count();
    471     int branchBalance = fBranchStack.count();
    472     while ((ch = script[0]) != '\0') {
    473         if (is_ws(ch)) {
    474             script++;
    475             continue;
    476         }
    477         SkScriptValue2 operand;
    478         const char* dotCheck;
    479         if (fBraceStack.count() > baseBrace) {
    480             if (fBraceStack.top() == kArrayBrace) {
    481                 SkScriptValue2 tokenValue;
    482                 success = innerScript(&script, &tokenValue);    // terminate and return on comma, close brace
    483                 SkASSERT(success);
    484                 {
    485                     SkOperand2::OpType type = fReturnType;
    486                     if (fReturnType == SkOperand2::kNoType) {
    487                         // !!! short sighted; in the future, allow each returned array component to carry
    488                         // its own type, and let caller do any needed conversions
    489                         if (value->fOperand.fArray->count() == 0)
    490                             value->fOperand.fArray->setType(type = tokenValue.fType);
    491                         else
    492                             type = value->fOperand.fArray->getType();
    493                     }
    494                     if (tokenValue.fType != type)
    495                         convertTo(type, &tokenValue);
    496                     *value->fOperand.fArray->append() = tokenValue.fOperand;
    497                 }
    498                 lastPush = false;
    499                 continue;
    500             } else
    501                 SkASSERT(token_length(script) > 0);
    502         }
    503         if (lastPush != false && fTokenLength > 0) {
    504             if (ch == '(') {
    505                 *fBraceStack.push() = kFunctionBrace;
    506                 SkString functionName(fToken, fTokenLength);
    507 
    508                 if (handleFunction(&script) == false)
    509                     return false;
    510                 lastPush = true;
    511                 continue;
    512             } else if (ch == '[') {
    513                 if (handleProperty() == false) {
    514                     SkASSERT(0);
    515                     return false;
    516                 }
    517                 if (handleArrayIndexer(&script) == false)
    518                     return false;
    519                 lastPush = true;
    520                 continue;
    521             } else if (ch != '.') {
    522                 if (handleProperty() == false) {
    523                     SkASSERT(0);
    524                     return false;
    525                 }
    526                 lastPush = true;
    527                 continue;
    528             }
    529         }
    530         if (ch == '0' && (script[1] & ~0x20) == 'X') {
    531             SkASSERT(lastPush == false);
    532             script += 2;
    533             script = SkParse::FindHex(script, (uint32_t*) &operand.fOperand.fS32);
    534             SkASSERT(script);
    535             goto intCommon;
    536         }
    537         if (lastPush == false && ch == '.')
    538             goto scalarCommon;
    539         if (ch >= '0' && ch <= '9') {
    540             SkASSERT(lastPush == false);
    541             dotCheck = SkParse::FindS32(script, &operand.fOperand.fS32);
    542             if (dotCheck[0] != '.') {
    543                 script = dotCheck;
    544 intCommon:
    545                 operand.fType = SkOperand2::kS32;
    546             } else {
    547 scalarCommon:
    548                 script = SkParse::FindScalar(script, &operand.fOperand.fScalar);
    549                 operand.fType = SkOperand2::kScalar;
    550             }
    551             operand.fIsConstant = SkScriptValue2::kConstant;
    552             fValueStack.push(operand);
    553             lastPush = true;
    554             continue;
    555         }
    556         int length = token_length(script);
    557         if (length > 0) {
    558             SkASSERT(lastPush == false);
    559             fToken = script;
    560             fTokenLength = length;
    561             script += length;
    562             lastPush = true;
    563             continue;
    564         }
    565         char startQuote = ch;
    566         if (startQuote == '\'' || startQuote == '\"') {
    567             SkASSERT(lastPush == false);
    568             operand.fOperand.fString = new SkString();
    569             ++script;
    570             const char* stringStart = script;
    571             do {    // measure string
    572                 if (script[0] == '\\')
    573                     ++script;
    574                 ++script;
    575                 SkASSERT(script[0]); // !!! throw an error
    576             } while (script[0] != startQuote);
    577             operand.fOperand.fString->set(stringStart, script - stringStart);
    578             script = stringStart;
    579             char* stringWrite = operand.fOperand.fString->writable_str();
    580             do {    // copy string
    581                 if (script[0] == '\\')
    582                     ++script;
    583                 *stringWrite++ = script[0];
    584                 ++script;
    585                 SkASSERT(script[0]); // !!! throw an error
    586             } while (script[0] != startQuote);
    587             ++script;
    588             track(operand.fOperand.fString);
    589             operand.fType = SkOperand2::kString;
    590             operand.fIsConstant = SkScriptValue2::kConstant;
    591             fValueStack.push(operand);
    592             lastPush = true;
    593             continue;
    594         }
    595         if (ch ==  '.') {
    596             if (fTokenLength == 0) {
    597                 SkScriptValue2 scriptValue;
    598                 SkDEBUGCODE(scriptValue.fOperand.fObject = NULL);
    599                 int tokenLength = token_length(++script);
    600                 const char* token = script;
    601                 script += tokenLength;
    602                 SkASSERT(fValueStack.count() > 0); // !!! add error handling
    603                 SkScriptValue2 top;
    604                 fValueStack.pop(&top);
    605 
    606                 addTokenInt(top.fType);
    607                 addToken(kBoxToken);
    608                 top.fType = SkOperand2::kObject;
    609                 top.fIsConstant = SkScriptValue2::kVariable;
    610                 fConstExpression = false;
    611                 fValueStack.push(top);
    612                 success = evaluateDotParam(script, token, tokenLength);
    613                 SkASSERT(success);
    614                 lastPush = true;
    615                 continue;
    616             }
    617             // get next token, and evaluate immediately
    618             success = evaluateDot(script);
    619             if (success == false) {
    620                 //                SkASSERT(0);
    621                 return false;
    622             }
    623             lastPush = true;
    624             continue;
    625         }
    626         if (ch == '[') {
    627             if (lastPush == false) {
    628                 script++;
    629                 *fBraceStack.push() = kArrayBrace;
    630                 operand.fOperand.fArray = value->fOperand.fArray = new SkOpArray(fReturnType);
    631                 track(value->fOperand.fArray);
    632 
    633                 operand.fType = SkOperand2::kArray;
    634                 operand.fIsConstant = SkScriptValue2::kVariable;
    635                 fValueStack.push(operand);
    636                 continue;
    637             }
    638             if (handleArrayIndexer(&script) == false)
    639                 return false;
    640             lastPush = true;
    641             continue;
    642         }
    643 #if 0 // structs not supported for now
    644         if (ch == '{') {
    645             if (lastPush == false) {
    646                 script++;
    647                 *fBraceStack.push() = kStructBrace;
    648                 operand.fS32 = 0;
    649                 *fTypeStack.push() = (SkOpType) kStruct;
    650                 fOperandStack.push(operand);
    651                 continue;
    652             }
    653             SkASSERT(0); // braces in other contexts aren't supported yet
    654         }
    655 #endif
    656         if (ch == ')' && fBraceStack.count() > 0) {
    657             BraceStyle braceStyle = fBraceStack.top();
    658             if (braceStyle == kFunctionBrace) {
    659                 fBraceStack.pop();
    660                 break;
    661             }
    662         }
    663         if (ch == ',' || ch == ']') {
    664             if (ch != ',') {
    665                 BraceStyle match;
    666                 fBraceStack.pop(&match);
    667                 SkASSERT(match == kArrayBrace);
    668             }
    669             script++;
    670             // !!! see if brace or bracket is correct closer
    671             break;
    672         }
    673         char nextChar = script[1];
    674         int advance = logicalOp(ch, nextChar);
    675         if (advance == 0)
    676             advance = arithmeticOp(ch, nextChar, lastPush);
    677         if (advance == 0) // unknown token
    678             return false;
    679         if (advance > 0)
    680             script += advance;
    681         lastPush = ch == ']' || ch == ')';
    682     }
    683     if (fTokenLength > 0) {
    684         success = handleProperty();
    685         SkASSERT(success);
    686     }
    687     int branchIndex = 0;
    688     branchBalance = fBranchStack.count() - branchBalance;
    689     fBranchPopAllowed = false;
    690     while (branchIndex < branchBalance) {
    691         Branch& branch = fBranchStack.index(branchIndex++);
    692         if (branch.fPrimed == Branch::kIsPrimed)
    693             break;
    694         Op branchOp = branch.fOperator;
    695         SkOperand2::OpType lastType = fValueStack.top().fType;
    696         addTokenValue(fValueStack.top(), kAccumulator);
    697         fValueStack.pop();
    698         if (branchOp == kLogicalAnd || branchOp == kLogicalOr) {
    699             if (branch.fOperator == kLogicalAnd)
    700                 branch.prime();
    701             addToken(kToBool);
    702         } else {
    703             resolveBranch(branch);
    704             SkScriptValue2 operand;
    705             operand.fType = lastType;
    706             // !!! note that many branching expressions could be constant
    707             // today, we always evaluate branches as returning variables
    708             operand.fIsConstant = SkScriptValue2::kVariable;
    709             fValueStack.push(operand);
    710         }
    711         if (branch.fDone == Branch::kIsNotDone)
    712             branch.prime();
    713     }
    714     fBranchPopAllowed = true;
    715     while (fBranchStack.top().fDone == Branch::kIsDone)
    716         fBranchStack.pop();
    717     while (fOpStack.count() > opBalance) {     // leave open paren
    718         if (processOp() == false)
    719             return false;
    720     }
    721     SkOperand2::OpType topType = fValueStack.count() > 0 ? fValueStack.top().fType : SkOperand2::kNoType;
    722     if (topType != fReturnType &&
    723         topType == SkOperand2::kString && fReturnType != SkOperand2::kNoType) { // if result is a string, give handle property a chance to convert it to the property value
    724         SkString* string = fValueStack.top().fOperand.fString;
    725         fToken = string->c_str();
    726         fTokenLength = string->size();
    727         fValueStack.pop();
    728         success = handleProperty();
    729         if (success == false) {    // if it couldn't convert, return string (error?)
    730             SkScriptValue2 operand;
    731             operand.fType = SkOperand2::kString;
    732             operand.fOperand.fString = string;
    733             operand.fIsConstant = SkScriptValue2::kVariable;     // !!! ?
    734             fValueStack.push(operand);
    735         }
    736     }
    737     if (fStream.getOffset() > 0) {
    738         addToken(kEnd);
    739 #ifdef SK_DEBUG
    740         decompile((const unsigned char*)fStream.getStream(), fStream.getOffset());
    741 #endif
    742         SkScriptRuntime runtime(fCallBackArray);
    743         runtime.executeTokens((unsigned char*) fStream.getStream());
    744         SkScriptValue2 value1;
    745         runtime.getResult(&value1.fOperand);
    746         value1.fType = fReturnType;
    747         fValueStack.push(value1);
    748     }
    749     if (value) {
    750         if (fValueStack.count() == 0)
    751             return false;
    752         fValueStack.pop(value);
    753         if (value->fType != fReturnType && value->fType == SkOperand2::kObject &&
    754             fReturnType != SkOperand2::kNoType)
    755             convertTo(fReturnType, value);
    756     }
    757     //    if (fBranchStack.top().fOpStackDepth > fOpStack.count())
    758     //        resolveBranch();
    759     *scriptPtr = script;
    760     return true; // no error
    761 }
    762 
    763 bool SkScriptEngine2::handleArrayIndexer(const char** scriptPtr) {
    764     SkScriptValue2 scriptValue;
    765     (*scriptPtr)++;
    766     *fOpStack.push() = (Op) kParen;
    767     *fBraceStack.push() = kArrayBrace;
    768     SkOperand2::OpType saveType = fReturnType;
    769     fReturnType = SkOperand2::kS32;
    770     bool success = innerScript(scriptPtr, &scriptValue);
    771     fReturnType = saveType;
    772     SkASSERT(success);
    773     success = convertTo(SkOperand2::kS32, &scriptValue);
    774     SkASSERT(success);
    775     int index = scriptValue.fOperand.fS32;
    776     fValueStack.pop(&scriptValue);
    777     if (scriptValue.fType == SkOperand2::kObject) {
    778         success = handleUnbox(&scriptValue);
    779         SkASSERT(success);
    780         SkASSERT(scriptValue.fType == SkOperand2::kArray);
    781     }
    782     scriptValue.fType = scriptValue.fOperand.fArray->getType();
    783     //    SkASSERT(index >= 0);
    784     if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) {
    785         fError = kArrayIndexOutOfBounds;
    786         return false;
    787     }
    788     scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index];
    789     scriptValue.fIsConstant = SkScriptValue2::kVariable;
    790     fValueStack.push(scriptValue);
    791     fOpStack.pop(); // pop paren
    792     return success;
    793 }
    794 
    795 bool SkScriptEngine2::handleFunction(const char** scriptPtr) {
    796     const char* functionName = fToken;
    797     size_t functionNameLen = fTokenLength;
    798     fTokenLength = 0;
    799     SkTDArray<SkScriptValue2> params;
    800     bool success = functionParams(scriptPtr, &params);
    801     if (success == false)
    802         goto done;
    803     {
    804         for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    805             if ((*callBack)->getType() != SkScriptCallBack::kFunction)
    806                 continue;
    807             SkScriptValue2 callbackResult;
    808             success = (*callBack)->getReference(functionName, functionNameLen, &callbackResult);
    809             if (success) {
    810                 callbackResult.fType = (*callBack)->getReturnType(callbackResult.fOperand.fReference, NULL);
    811                 callbackResult.fIsConstant = SkScriptValue2::kVariable;
    812                 fValueStack.push(callbackResult);
    813                 goto done;
    814             }
    815         }
    816     }
    817     return false;
    818 done:
    819         fOpStack.pop();
    820     return success;
    821 }
    822 
    823 bool SkScriptEngine2::handleMember(const char* field, size_t len, void* object) {
    824     bool success = true;
    825     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    826         if ((*callBack)->getType() != SkScriptCallBack::kMember)
    827             continue;
    828         SkScriptValue2 callbackResult;
    829         success = (*callBack)->getReference(field, len, &callbackResult);
    830         if (success) {
    831             if (callbackResult.fType == SkOperand2::kString)
    832                 track(callbackResult.fOperand.fString);
    833             callbackResult.fIsConstant = SkScriptValue2::kVariable;
    834             fValueStack.push(callbackResult);
    835             goto done;
    836         }
    837     }
    838     return false;
    839 done:
    840         return success;
    841 }
    842 
    843 bool SkScriptEngine2::handleMemberFunction(const char* field, size_t len, void* object,
    844                                            SkTDArray<SkScriptValue2>* params) {
    845     bool success = true;
    846     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    847         if ((*callBack)->getType() != SkScriptCallBack::kMemberFunction)
    848             continue;
    849         SkScriptValue2 callbackResult;
    850         success = (*callBack)->getReference(field, len, &callbackResult);
    851         if (success) {
    852             if (callbackResult.fType == SkOperand2::kString)
    853                 track(callbackResult.fOperand.fString);
    854             callbackResult.fIsConstant = SkScriptValue2::kVariable;
    855             fValueStack.push(callbackResult);
    856             goto done;
    857         }
    858     }
    859     return false;
    860 done:
    861         return success;
    862 }
    863 
    864 bool SkScriptEngine2::handleProperty() {
    865     bool success = true;
    866     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    867         if ((*callBack)->getType() != SkScriptCallBack::kProperty)
    868             continue;
    869         SkScriptValue2 callbackResult;
    870         success = (*callBack)->getReference(fToken, fTokenLength, &callbackResult);
    871         if (success) {
    872             if (callbackResult.fType == SkOperand2::kString && callbackResult.fOperand.fString == NULL) {
    873                 callbackResult.fOperand.fString = new SkString(fToken, fTokenLength);
    874                 track(callbackResult.fOperand.fString);
    875             }
    876             callbackResult.fIsConstant = SkScriptValue2::kVariable;
    877             fValueStack.push(callbackResult);
    878             goto done;
    879         }
    880     }
    881 done:
    882         fTokenLength = 0;
    883     return success;
    884 }
    885 
    886 bool SkScriptEngine2::handleUnbox(SkScriptValue2* scriptValue) {
    887     bool success = true;
    888     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    889         if ((*callBack)->getType() != SkScriptCallBack::kUnbox)
    890             continue;
    891         SkScriptCallBackConvert* callBackConvert = (SkScriptCallBackConvert*) *callBack;
    892         success = callBackConvert->convert(scriptValue->fType, &scriptValue->fOperand);
    893         if (success) {
    894             if (scriptValue->fType == SkOperand2::kString)
    895                 track(scriptValue->fOperand.fString);
    896             goto done;
    897         }
    898     }
    899     return false;
    900 done:
    901         return success;
    902 }
    903 
    904 // note that entire expression is treated as if it were enclosed in parens
    905 // an open paren is always the first thing in the op stack
    906 
    907 int SkScriptEngine2::logicalOp(char ch, char nextChar) {
    908     int advance = 1;
    909     Op op;
    910     signed char precedence;
    911     switch (ch) {
    912         case ')':
    913             op = (Op) kParen;
    914             break;
    915         case ']':
    916             op = (Op) kArrayOp;
    917             break;
    918         case '?':
    919             op = (Op) kIf;
    920             break;
    921         case ':':
    922             op = (Op) kElse;
    923             break;
    924         case '&':
    925             if (nextChar != '&')
    926                 goto noMatch;
    927             op = kLogicalAnd;
    928             advance = 2;
    929             break;
    930         case '|':
    931             if (nextChar != '|')
    932                 goto noMatch;
    933             op = kLogicalOr;
    934             advance = 2;
    935             break;
    936         default:
    937             noMatch:
    938             return 0;
    939     }
    940     precedence = gPrecedence[op];
    941     int branchIndex = 0;
    942     fBranchPopAllowed = false;
    943     do {
    944         while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence)
    945             processOp();
    946         Branch& branch = fBranchStack.index(branchIndex++);
    947         Op branchOp = branch.fOperator;
    948         if (gPrecedence[branchOp] >= precedence)
    949             break;
    950         addTokenValue(fValueStack.top(), kAccumulator);
    951         fValueStack.pop();
    952         if (branchOp == kLogicalAnd || branchOp == kLogicalOr) {
    953             if (branch.fOperator == kLogicalAnd)
    954                 branch.prime();
    955             addToken(kToBool);
    956         } else
    957             resolveBranch(branch);
    958         if (branch.fDone == Branch::kIsNotDone)
    959             branch.prime();
    960     } while (true);
    961     fBranchPopAllowed = true;
    962     while (fBranchStack.top().fDone == Branch::kIsDone)
    963         fBranchStack.pop();
    964     processLogicalOp(op);
    965     return advance;
    966 }
    967 
    968 void SkScriptEngine2::processLogicalOp(Op op) {
    969     switch (op) {
    970         case kParen:
    971         case kArrayOp:
    972             SkASSERT(fOpStack.count() > 1 && fOpStack.top() == op);    // !!! add error handling
    973             if (op == kParen)
    974                 fOpStack.pop();
    975             else {
    976                 SkScriptValue2 value;
    977                 fValueStack.pop(&value);
    978                 SkASSERT(value.fType == SkOperand2::kS32 || value.fType == SkOperand2::kScalar); // !!! add error handling (although, could permit strings eventually)
    979                 int index = value.fType == SkOperand2::kScalar ? SkScalarFloor(value.fOperand.fScalar) :
    980                     value.fOperand.fS32;
    981                 SkScriptValue2 arrayValue;
    982                 fValueStack.pop(&arrayValue);
    983                 SkASSERT(arrayValue.fType == SkOperand2::kArray);  // !!! add error handling
    984                 SkOpArray* array = arrayValue.fOperand.fArray;
    985                 SkOperand2 operand;
    986                 bool success = array->getIndex(index, &operand);
    987                 SkASSERT(success); // !!! add error handling
    988                 SkScriptValue2 resultValue;
    989                 resultValue.fType = array->getType();
    990                 resultValue.fOperand = operand;
    991                 resultValue.fIsConstant = SkScriptValue2::kVariable;
    992                 fValueStack.push(resultValue);
    993             }
    994                 break;
    995         case kIf: {
    996             if (fAccumulatorType == SkOperand2::kNoType) {
    997                 addTokenValue(fValueStack.top(), kAccumulator);
    998                 fValueStack.pop();
    999             }
   1000             SkASSERT(fAccumulatorType != SkOperand2::kString); // !!! add error handling
   1001             addToken(kIfOp);
   1002             Branch branch(op, fOpStack.count(), getTokenOffset());
   1003             *fBranchStack.push() = branch;
   1004             addTokenInt(0); // placeholder for future branch
   1005             fAccumulatorType = SkOperand2::kNoType;
   1006         } break;
   1007         case kElse: {
   1008             addTokenValue(fValueStack.top(), kAccumulator);
   1009             fValueStack.pop();
   1010             addToken(kElseOp);
   1011             size_t newOffset = getTokenOffset();
   1012             addTokenInt(0); // placeholder for future branch
   1013             Branch& branch = fBranchStack.top();
   1014             resolveBranch(branch);
   1015             branch.fOperator = op;
   1016             branch.fDone = Branch::kIsNotDone;
   1017             SkASSERT(branch.fOpStackDepth == fOpStack.count());
   1018             branch.fOffset = newOffset;
   1019             fAccumulatorType = SkOperand2::kNoType;
   1020         } break;
   1021         case kLogicalAnd:
   1022         case kLogicalOr: {
   1023             Branch& oldTop = fBranchStack.top();
   1024             Branch::Primed wasPrime = oldTop.fPrimed;
   1025             Branch::Done wasDone = oldTop.fDone;
   1026             oldTop.fPrimed = Branch::kIsNotPrimed;
   1027             oldTop.fDone = Branch::kIsNotDone;
   1028             if (fAccumulatorType == SkOperand2::kNoType) {
   1029                 SkASSERT(fValueStack.top().fType == SkOperand2::kS32); // !!! add error handling, and conversion to int?
   1030                 addTokenValue(fValueStack.top(), kAccumulator);
   1031                 fValueStack.pop();
   1032             } else
   1033                 SkASSERT(fAccumulatorType == SkOperand2::kS32);
   1034             // if 'and', write beq goto opcode after end of predicate (after to bool)
   1035             // if 'or', write bne goto to bool
   1036             addToken(op == kLogicalAnd ? kLogicalAndInt : kLogicalOrInt);
   1037             Branch branch(op, fOpStack.count(), getTokenOffset());
   1038             addTokenInt(0); // placeholder for future branch
   1039             oldTop.fPrimed = wasPrime;
   1040             oldTop.fDone = wasDone;
   1041             *fBranchStack.push() = branch;
   1042             fAccumulatorType = SkOperand2::kNoType;
   1043         }    break;
   1044         default:
   1045             SkASSERT(0);
   1046     }
   1047 }
   1048 
   1049 bool SkScriptEngine2::processOp() {
   1050     Op op;
   1051     fOpStack.pop(&op);
   1052     op = (Op) (op & ~kArtificialOp);
   1053     const OperatorAttributes* attributes = &gOpAttributes[op];
   1054     SkScriptValue2 value1;
   1055     memset(&value1, 0, sizeof(SkScriptValue2));
   1056     SkScriptValue2 value2;
   1057     fValueStack.pop(&value2);
   1058     value2.fIsWritten = SkScriptValue2::kUnwritten;
   1059     //    SkScriptEngine2::SkTypeOp convert1[3];
   1060     //    SkScriptEngine2::SkTypeOp convert2[3];
   1061     //    SkScriptEngine2::SkTypeOp* convert2Ptr = convert2;
   1062     bool constantOperands = value2.fIsConstant == SkScriptValue2::kConstant;
   1063     if (attributes->fLeftType != SkOperand2::kNoType) {
   1064         fValueStack.pop(&value1);
   1065         constantOperands &= value1.fIsConstant == SkScriptValue2::kConstant;
   1066         value1.fIsWritten = SkScriptValue2::kUnwritten;
   1067         if (op == kFlipOps) {
   1068             SkTSwap(value1, value2);
   1069             fOpStack.pop(&op);
   1070             op = (Op) (op & ~kArtificialOp);
   1071             attributes = &gOpAttributes[op];
   1072             if (constantOperands == false)
   1073                 addToken(kFlipOpsOp);
   1074         }
   1075         if (value1.fType == SkOperand2::kObject && (value1.fType & attributes->fLeftType) == 0) {
   1076             value1.fType = getUnboxType(value1.fOperand);
   1077             addToken(kUnboxToken);
   1078         }
   1079     }
   1080     if (value2.fType == SkOperand2::kObject && (value2.fType & attributes->fLeftType) == 0) {
   1081         value1.fType = getUnboxType(value2.fOperand);
   1082         addToken(kUnboxToken2);
   1083     }
   1084     if (attributes->fLeftType != SkOperand2::kNoType) {
   1085         if (value1.fType != value2.fType) {
   1086             if ((attributes->fLeftType & SkOperand2::kString) && attributes->fBias & kTowardsString &&
   1087                 ((value1.fType | value2.fType) & SkOperand2::kString)) {
   1088                 if (value1.fType == SkOperand2::kS32 || value1.fType == SkOperand2::kScalar) {
   1089                     addTokenConst(&value1, kAccumulator, SkOperand2::kString,
   1090                                   value1.fType == SkOperand2::kS32 ? kIntToString : kScalarToString);
   1091                 }
   1092                 if (value2.fType == SkOperand2::kS32 || value2.fType == SkOperand2::kScalar) {
   1093                     addTokenConst(&value2, kOperand, SkOperand2::kString,
   1094                                   value2.fType == SkOperand2::kS32 ? kIntToString2 : kScalarToString2);
   1095                 }
   1096             } else if (attributes->fLeftType & SkOperand2::kScalar && ((value1.fType | value2.fType) &
   1097                                                                        SkOperand2::kScalar)) {
   1098                 if (value1.fType == SkOperand2::kS32)
   1099                     addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kIntToScalar);
   1100                 if (value2.fType == SkOperand2::kS32)
   1101                     addTokenConst(&value2, kOperand, SkOperand2::kScalar, kIntToScalar2);
   1102             }
   1103         }
   1104         if ((value1.fType & attributes->fLeftType) == 0 || value1.fType != value2.fType) {
   1105             if (value1.fType == SkOperand2::kString)
   1106                 addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kStringToScalar);
   1107             if (value1.fType == SkOperand2::kScalar && (attributes->fLeftType == SkOperand2::kS32 ||
   1108                                                         value2.fType == SkOperand2::kS32))
   1109                 addTokenConst(&value1, kAccumulator, SkOperand2::kS32, kScalarToInt);
   1110         }
   1111     }
   1112     AddTokenRegister rhRegister = attributes->fLeftType != SkOperand2::kNoType ?
   1113         kOperand : kAccumulator;
   1114     if ((value2.fType & attributes->fRightType) == 0 || value1.fType != value2.fType) {
   1115         if (value2.fType == SkOperand2::kString)
   1116             addTokenConst(&value2, rhRegister, SkOperand2::kScalar, kStringToScalar2);
   1117         if (value2.fType == SkOperand2::kScalar && (attributes->fRightType == SkOperand2::kS32 ||
   1118                                                     value1.fType == SkOperand2::kS32))
   1119             addTokenConst(&value2, rhRegister, SkOperand2::kS32, kScalarToInt2);
   1120     }
   1121     TypeOp typeOp = gTokens[op];
   1122     if (value2.fType == SkOperand2::kScalar)
   1123         typeOp = (TypeOp) (typeOp + 1);
   1124     else if (value2.fType == SkOperand2::kString)
   1125         typeOp = (TypeOp) (typeOp + 2);
   1126     SkDynamicMemoryWStream stream;
   1127     SkOperand2::OpType saveType;
   1128     SkBool saveOperand;
   1129     if (constantOperands) {
   1130         fActiveStream = &stream;
   1131         saveType = fAccumulatorType;
   1132         saveOperand = fOperandInUse;
   1133         fAccumulatorType = SkOperand2::kNoType;
   1134         fOperandInUse = false;
   1135     }
   1136     if (attributes->fLeftType != SkOperand2::kNoType) {    // two operands
   1137         if (value1.fIsWritten == SkScriptValue2::kUnwritten)
   1138             addTokenValue(value1, kAccumulator);
   1139     }
   1140     if (value2.fIsWritten == SkScriptValue2::kUnwritten)
   1141         addTokenValue(value2, rhRegister);
   1142     addToken(typeOp);
   1143     if (constantOperands) {
   1144         addToken(kEnd);
   1145 #ifdef SK_DEBUG
   1146         decompile((const unsigned char*) stream.getStream(), stream.getOffset());
   1147 #endif
   1148         SkScriptRuntime runtime(fCallBackArray);
   1149         runtime.executeTokens((unsigned char*) stream.getStream());
   1150         runtime.getResult(&value1.fOperand);
   1151         if (attributes->fResultIsBoolean == kResultIsBoolean)
   1152             value1.fType = SkOperand2::kS32;
   1153         else if (attributes->fLeftType == SkOperand2::kNoType) // unary operand
   1154             value1.fType = value2.fType;
   1155         fValueStack.push(value1);
   1156         if (value1.fType == SkOperand2::kString)
   1157             runtime.untrack(value1.fOperand.fString);
   1158         else if (value1.fType == SkOperand2::kArray)
   1159             runtime.untrack(value1.fOperand.fArray);
   1160         fActiveStream = &fStream;
   1161         fAccumulatorType = saveType;
   1162         fOperandInUse = saveOperand;
   1163         return true;
   1164     }
   1165     value2.fIsConstant = SkScriptValue2::kVariable;
   1166     fValueStack.push(value2);
   1167     return true;
   1168 }
   1169 
   1170 void SkScriptEngine2::Branch::resolve(SkDynamicMemoryWStream* stream, size_t off) {
   1171     SkASSERT(fDone == kIsNotDone);
   1172     fPrimed = kIsNotPrimed;
   1173     fDone = kIsDone;
   1174     SkASSERT(off > fOffset + sizeof(size_t));
   1175     size_t offset = off - fOffset - sizeof(offset);
   1176     stream->write(&offset, fOffset, sizeof(offset));
   1177 }
   1178 
   1179 void SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) {
   1180     branch.resolve(fActiveStream, getTokenOffset());
   1181 }
   1182 
   1183 bool SkScriptEngine2::ConvertTo(SkScriptEngine2* engine, SkOperand2::OpType toType, SkScriptValue2* value ) {
   1184     SkASSERT(value);
   1185     SkOperand2::OpType type = value->fType;
   1186     if (type == toType)
   1187         return true;
   1188     SkOperand2& operand = value->fOperand;
   1189     bool success = true;
   1190     switch (toType) {
   1191         case SkOperand2::kS32:
   1192             if (type == SkOperand2::kScalar)
   1193                 operand.fS32 = SkScalarFloor(operand.fScalar);
   1194             else {
   1195                 SkASSERT(type == SkOperand2::kString);
   1196                 success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != NULL;
   1197             }
   1198                 break;
   1199         case SkOperand2::kScalar:
   1200             if (type == SkOperand2::kS32)
   1201                 operand.fScalar = IntToScalar(operand.fS32);
   1202             else {
   1203                 SkASSERT(type == SkOperand2::kString);
   1204                 success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != NULL;
   1205             }
   1206                 break;
   1207         case SkOperand2::kString: {
   1208             SkString* strPtr = new SkString();
   1209             SkASSERT(engine);
   1210             engine->track(strPtr);
   1211             if (type == SkOperand2::kS32)
   1212                 strPtr->appendS32(operand.fS32);
   1213             else {
   1214                 SkASSERT(type == SkOperand2::kScalar);
   1215                 strPtr->appendScalar(operand.fScalar);
   1216             }
   1217             operand.fString = strPtr;
   1218         } break;
   1219         case SkOperand2::kArray: {
   1220             SkOpArray* array = new SkOpArray(type);
   1221             *array->append() = operand;
   1222             engine->track(array);
   1223             operand.fArray = array;
   1224         } break;
   1225         default:
   1226             SkASSERT(0);
   1227     }
   1228     value->fType = toType;
   1229     return success;
   1230 }
   1231 
   1232 SkScalar SkScriptEngine2::IntToScalar(int32_t s32) {
   1233     SkScalar scalar;
   1234     if (s32 == (int32_t) SK_NaN32)
   1235         scalar = SK_ScalarNaN;
   1236     else if (SkAbs32(s32) == SK_MaxS32)
   1237         scalar = SkSign32(s32) * SK_ScalarMax;
   1238     else
   1239         scalar = SkIntToScalar(s32);
   1240     return scalar;
   1241 }
   1242 
   1243 bool SkScriptEngine2::ValueToString(const SkScriptValue2& value, SkString* string) {
   1244     switch (value.fType) {
   1245         case SkOperand2::kS32:
   1246             string->reset();
   1247             string->appendS32(value.fOperand.fS32);
   1248             break;
   1249         case SkOperand2::kScalar:
   1250             string->reset();
   1251             string->appendScalar(value.fOperand.fScalar);
   1252             break;
   1253         case SkOperand2::kString:
   1254             string->set(*value.fOperand.fString);
   1255             break;
   1256         default:
   1257             SkASSERT(0);
   1258             return false;
   1259     }
   1260     return true; // no error
   1261 }
   1262 
   1263 #ifdef SK_DEBUG
   1264 
   1265 #define testInt(expression) { #expression, SkOperand2::kS32, expression, 0, NULL }
   1266 #ifdef SK_SCALAR_IS_FLOAT
   1267 #define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (float) expression, NULL }
   1268 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmodf(exp1, exp2), NULL }
   1269 #else
   1270 #ifdef SK_CAN_USE_FLOAT
   1271 #define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (int) ((expression) * 65536.0f), NULL }
   1272 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, (int) (fmod(exp1, exp2)  * 65536.0f), NULL }
   1273 #endif
   1274 #endif
   1275 #define testTrue(expression) { #expression, SkOperand2::kS32, 1, 0, NULL }
   1276 #define testFalse(expression) { #expression, SkOperand2::kS32, 0, 0, NULL }
   1277 
   1278 static const SkScriptNAnswer2 scriptTests[]  = {
   1279     testInt(1||(0&&3)),
   1280 #ifdef SK_CAN_USE_FLOAT
   1281     testScalar(- -5.5- -1.5),
   1282     testScalar(1.0+5),
   1283 #endif
   1284     testInt((6+7)*8),
   1285     testInt(3*(4+5)),
   1286 #ifdef SK_CAN_USE_FLOAT
   1287     testScalar(1.0+2.0),
   1288     testScalar(3.0-1.0),
   1289     testScalar(6-1.0),
   1290     testScalar(2.5*6.),
   1291     testScalar(0.5*4),
   1292     testScalar(4.5/.5),
   1293     testScalar(9.5/19),
   1294     testRemainder(9.5, 0.5),
   1295     testRemainder(9.,2),
   1296     testRemainder(9,2.5),
   1297     testRemainder(-9,2.5),
   1298     testTrue(-9==-9.0),
   1299     testTrue(-9.==-4.0-5),
   1300     testTrue(-9.*1==-4-5),
   1301     testFalse(-9!=-9.0),
   1302     testFalse(-9.!=-4.0-5),
   1303     testFalse(-9.*1!=-4-5),
   1304 #endif
   1305     testInt(0x123),
   1306     testInt(0XABC),
   1307     testInt(0xdeadBEEF),
   1308     {    "'123'+\"456\"", SkOperand2::kString, 0, 0, "123456" },
   1309     {    "123+\"456\"", SkOperand2::kString, 0, 0, "123456" },
   1310     {    "'123'+456", SkOperand2::kString, 0, 0, "123456" },
   1311     {    "'123'|\"456\"", SkOperand2::kS32, 123|456, 0, NULL },
   1312     {    "123|\"456\"", SkOperand2::kS32, 123|456, 0, NULL },
   1313     {    "'123'|456", SkOperand2::kS32, 123|456, 0, NULL },
   1314     {    "'2'<11", SkOperand2::kS32, 1, 0, NULL },
   1315     {    "2<'11'", SkOperand2::kS32, 1, 0, NULL },
   1316     {    "'2'<'11'", SkOperand2::kS32, 0, 0, NULL },
   1317     testInt(123),
   1318     testInt(-345),
   1319     testInt(+678),
   1320     testInt(1+2+3),
   1321     testInt(3*4+5),
   1322     testInt(6+7*8),
   1323     testInt(-1-2-8/4),
   1324     testInt(-9%4),
   1325     testInt(9%-4),
   1326     testInt(-9%-4),
   1327     testInt(123|978),
   1328     testInt(123&978),
   1329     testInt(123^978),
   1330     testInt(2<<4),
   1331     testInt(99>>3),
   1332     testInt(~55),
   1333     testInt(~~55),
   1334     testInt(!55),
   1335     testInt(!!55),
   1336     // both int
   1337     testInt(2<2),
   1338     testInt(2<11),
   1339     testInt(20<11),
   1340     testInt(2<=2),
   1341     testInt(2<=11),
   1342     testInt(20<=11),
   1343     testInt(2>2),
   1344     testInt(2>11),
   1345     testInt(20>11),
   1346     testInt(2>=2),
   1347     testInt(2>=11),
   1348     testInt(20>=11),
   1349     testInt(2==2),
   1350     testInt(2==11),
   1351     testInt(20==11),
   1352     testInt(2!=2),
   1353     testInt(2!=11),
   1354     testInt(20!=11),
   1355 #ifdef SK_CAN_USE_FLOAT
   1356     // left int, right scalar
   1357     testInt(2<2.),
   1358     testInt(2<11.),
   1359     testInt(20<11.),
   1360     testInt(2<=2.),
   1361     testInt(2<=11.),
   1362     testInt(20<=11.),
   1363     testInt(2>2.),
   1364     testInt(2>11.),
   1365     testInt(20>11.),
   1366     testInt(2>=2.),
   1367     testInt(2>=11.),
   1368     testInt(20>=11.),
   1369     testInt(2==2.),
   1370     testInt(2==11.),
   1371     testInt(20==11.),
   1372     testInt(2!=2.),
   1373     testInt(2!=11.),
   1374     testInt(20!=11.),
   1375     // left scalar, right int
   1376     testInt(2.<2),
   1377     testInt(2.<11),
   1378     testInt(20.<11),
   1379     testInt(2.<=2),
   1380     testInt(2.<=11),
   1381     testInt(20.<=11),
   1382     testInt(2.>2),
   1383     testInt(2.>11),
   1384     testInt(20.>11),
   1385     testInt(2.>=2),
   1386     testInt(2.>=11),
   1387     testInt(20.>=11),
   1388     testInt(2.==2),
   1389     testInt(2.==11),
   1390     testInt(20.==11),
   1391     testInt(2.!=2),
   1392     testInt(2.!=11),
   1393     testInt(20.!=11),
   1394     // both scalar
   1395     testInt(2.<11.),
   1396     testInt(20.<11.),
   1397     testInt(2.<=2.),
   1398     testInt(2.<=11.),
   1399     testInt(20.<=11.),
   1400     testInt(2.>2.),
   1401     testInt(2.>11.),
   1402     testInt(20.>11.),
   1403     testInt(2.>=2.),
   1404     testInt(2.>=11.),
   1405     testInt(20.>=11.),
   1406     testInt(2.==2.),
   1407     testInt(2.==11.),
   1408     testInt(20.==11.),
   1409     testInt(2.!=2.),
   1410     testInt(2.!=11.),
   1411     testInt(20.!=11.),
   1412 #endif
   1413     // int, string (string is int)
   1414     testFalse(2<'2'),
   1415     testTrue(2<'11'),
   1416     testFalse(20<'11'),
   1417     testTrue(2<='2'),
   1418     testTrue(2<='11'),
   1419     testFalse(20<='11'),
   1420     testFalse(2>'2'),
   1421     testFalse(2>'11'),
   1422     testTrue(20>'11'),
   1423     testTrue(2>='2'),
   1424     testFalse(2>='11'),
   1425     testTrue(20>='11'),
   1426     testTrue(2=='2'),
   1427     testFalse(2=='11'),
   1428     testFalse(2!='2'),
   1429     testTrue(2!='11'),
   1430     // int, string (string is scalar)
   1431     testFalse(2<'2.'),
   1432     testTrue(2<'11.'),
   1433     testFalse(20<'11.'),
   1434     testTrue(2=='2.'),
   1435     testFalse(2=='11.'),
   1436 #ifdef SK_CAN_USE_FLOAT
   1437     // scalar, string
   1438     testFalse(2.<'2.'),
   1439     testTrue(2.<'11.'),
   1440     testFalse(20.<'11.'),
   1441     testTrue(2.=='2.'),
   1442     testFalse(2.=='11.'),
   1443     // string, int
   1444     testFalse('2'<2),
   1445     testTrue('2'<11),
   1446     testFalse('20'<11),
   1447     testTrue('2'==2),
   1448     testFalse('2'==11),
   1449     // string, scalar
   1450     testFalse('2'<2.),
   1451     testTrue('2'<11.),
   1452     testFalse('20'<11.),
   1453     testTrue('2'==2.),
   1454     testFalse('2'==11.),
   1455 #endif
   1456     // string, string
   1457     testFalse('2'<'2'),
   1458     testFalse('2'<'11'),
   1459     testFalse('20'<'11'),
   1460     testTrue('2'=='2'),
   1461     testFalse('2'=='11'),
   1462     // logic
   1463     testInt(1?2:3),
   1464     testInt(0?2:3),
   1465     testInt((1&&2)||3),
   1466     testInt((1&&0)||3),
   1467     testInt((1&&0)||0),
   1468     testInt(1||(0&&3)),
   1469     testInt(0||(0&&3)),
   1470     testInt(0||(1&&3)),
   1471     testInt(0&&1?2:3)
   1472 #ifdef SK_CAN_USE_FLOAT
   1473     , {    "123.5", SkOperand2::kScalar, 0, SkIntToScalar(123) + SK_Scalar1/2, NULL }
   1474 #endif
   1475 };
   1476 
   1477 #define SkScriptNAnswer_testCount    SK_ARRAY_COUNT(scriptTests)
   1478 
   1479 void SkScriptEngine2::UnitTest() {
   1480 #if defined(SK_SUPPORT_UNITTEST)
   1481     ValidateDecompileTable();
   1482     for (int index = 0; index < SkScriptNAnswer_testCount; index++) {
   1483         SkScriptEngine2 engine(scriptTests[index].fType);
   1484         SkScriptValue2 value;
   1485         const char* script = scriptTests[index].fScript;
   1486         const char* scriptPtr = script;
   1487         SkASSERT(engine.evaluateScript(&scriptPtr, &value) == true);
   1488         SkASSERT(value.fType == scriptTests[index].fType);
   1489         SkScalar error;
   1490         switch (value.fType) {
   1491             case SkOperand2::kS32:
   1492                 if (value.fOperand.fS32 != scriptTests[index].fIntAnswer)
   1493                     SkDEBUGF(("script '%s' == value %d != expected answer %d\n", script, value.fOperand.fS32, scriptTests[index].fIntAnswer));
   1494                 SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer);
   1495                 break;
   1496             case SkOperand2::kScalar:
   1497                 error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer);
   1498 #ifdef SK_CAN_USE_FLOAT
   1499                 if (error >= SK_Scalar1 / 10000)
   1500                     SkDEBUGF(("script '%s' == value %g != expected answer %g\n", script, value.fOperand.fScalar / (1.0f * SK_Scalar1), scriptTests[index].fScalarAnswer / (1.0f * SK_Scalar1)));
   1501 #endif
   1502                 SkASSERT(error < SK_Scalar1 / 10000);
   1503                 break;
   1504             case SkOperand2::kString:
   1505                 SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer));
   1506                 break;
   1507             default:
   1508                 SkASSERT(0);
   1509         }
   1510     }
   1511 #endif
   1512 }
   1513 #endif
   1514