Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / animator / SkScriptTokenizer.cpp
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, NULL);
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 == NULL) {
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) != NULL;
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) != NULL;
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, NULL }
1277 #define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (float) (expression), NULL }
1278 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmodf((float) exp1, (float) exp2), NULL }
1279 #define testTrue(expression) { #expression, SkOperand2::kS32, 1, 0, NULL }
1280 #define testFalse(expression) { #expression, SkOperand2::kS32, 0, 0, NULL }
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, 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     // 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, NULL }
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