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