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