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 = 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, ¶ms); 389 if (success) 390 success = handleMemberFunction(field, fieldLength, object, ¶ms); 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 SkDEBUGCODE(SkScriptValue2 scriptValue;) 607 SkDEBUGCODE(scriptValue.fOperand.fObject = NULL); 608 int tokenLength = token_length(++script); 609 const char* token = script; 610 script += tokenLength; 611 SkASSERT(fValueStack.count() > 0); // !!! add error handling 612 SkScriptValue2 top; 613 fValueStack.pop(&top); 614 615 addTokenInt(top.fType); 616 addToken(kBoxToken); 617 top.fType = SkOperand2::kObject; 618 top.fIsConstant = SkScriptValue2::kVariable; 619 fConstExpression = false; 620 fValueStack.push(top); 621 success = evaluateDotParam(script, token, tokenLength); 622 SkASSERT(success); 623 lastPush = true; 624 continue; 625 } 626 // get next token, and evaluate immediately 627 success = evaluateDot(script); 628 if (success == false) { 629 // SkASSERT(0); 630 return false; 631 } 632 lastPush = true; 633 continue; 634 } 635 if (ch == '[') { 636 if (lastPush == false) { 637 script++; 638 *fBraceStack.push() = kArrayBrace; 639 operand.fOperand.fArray = value->fOperand.fArray = new SkOpArray(fReturnType); 640 track(value->fOperand.fArray); 641 642 operand.fType = SkOperand2::kArray; 643 operand.fIsConstant = SkScriptValue2::kVariable; 644 fValueStack.push(operand); 645 continue; 646 } 647 if (handleArrayIndexer(&script) == false) 648 return false; 649 lastPush = true; 650 continue; 651 } 652 #if 0 // structs not supported for now 653 if (ch == '{') { 654 if (lastPush == false) { 655 script++; 656 *fBraceStack.push() = kStructBrace; 657 operand.fS32 = 0; 658 *fTypeStack.push() = (SkOpType) kStruct; 659 fOperandStack.push(operand); 660 continue; 661 } 662 SkASSERT(0); // braces in other contexts aren't supported yet 663 } 664 #endif 665 if (ch == ')' && fBraceStack.count() > 0) { 666 BraceStyle braceStyle = fBraceStack.top(); 667 if (braceStyle == kFunctionBrace) { 668 fBraceStack.pop(); 669 break; 670 } 671 } 672 if (ch == ',' || ch == ']') { 673 if (ch != ',') { 674 BraceStyle match; 675 fBraceStack.pop(&match); 676 SkASSERT(match == kArrayBrace); 677 } 678 script++; 679 // !!! see if brace or bracket is correct closer 680 break; 681 } 682 char nextChar = script[1]; 683 int advance = logicalOp(ch, nextChar); 684 if (advance == 0) 685 advance = arithmeticOp(ch, nextChar, lastPush); 686 if (advance == 0) // unknown token 687 return false; 688 if (advance > 0) 689 script += advance; 690 lastPush = ch == ']' || ch == ')'; 691 } 692 if (fTokenLength > 0) { 693 success = handleProperty(); 694 SkASSERT(success); 695 } 696 int branchIndex = 0; 697 branchBalance = fBranchStack.count() - branchBalance; 698 fBranchPopAllowed = false; 699 while (branchIndex < branchBalance) { 700 Branch& branch = fBranchStack.index(branchIndex++); 701 if (branch.fPrimed == Branch::kIsPrimed) 702 break; 703 Op branchOp = branch.fOperator; 704 SkOperand2::OpType lastType = fValueStack.top().fType; 705 addTokenValue(fValueStack.top(), kAccumulator); 706 fValueStack.pop(); 707 if (branchOp == kLogicalAnd || branchOp == kLogicalOr) { 708 if (branch.fOperator == kLogicalAnd) 709 branch.prime(); 710 addToken(kToBool); 711 } else { 712 resolveBranch(branch); 713 SkScriptValue2 operand; 714 operand.fType = lastType; 715 // !!! note that many branching expressions could be constant 716 // today, we always evaluate branches as returning variables 717 operand.fIsConstant = SkScriptValue2::kVariable; 718 fValueStack.push(operand); 719 } 720 if (branch.fDone == Branch::kIsNotDone) 721 branch.prime(); 722 } 723 fBranchPopAllowed = true; 724 while (fBranchStack.top().fDone == Branch::kIsDone) 725 fBranchStack.pop(); 726 while (fOpStack.count() > opBalance) { // leave open paren 727 if (processOp() == false) 728 return false; 729 } 730 SkOperand2::OpType topType = fValueStack.count() > 0 ? fValueStack.top().fType : SkOperand2::kNoType; 731 if (topType != fReturnType && 732 topType == SkOperand2::kString && fReturnType != SkOperand2::kNoType) { // if result is a string, give handle property a chance to convert it to the property value 733 SkString* string = fValueStack.top().fOperand.fString; 734 fToken = string->c_str(); 735 fTokenLength = string->size(); 736 fValueStack.pop(); 737 success = handleProperty(); 738 if (success == false) { // if it couldn't convert, return string (error?) 739 SkScriptValue2 operand; 740 operand.fType = SkOperand2::kString; 741 operand.fOperand.fString = string; 742 operand.fIsConstant = SkScriptValue2::kVariable; // !!! ? 743 fValueStack.push(operand); 744 } 745 } 746 if (fStream.getOffset() > 0) { 747 addToken(kEnd); 748 SkAutoDataUnref data(fStream.copyToData()); 749 #ifdef SK_DEBUG 750 decompile(data.bytes(), data.size()); 751 #endif 752 SkScriptRuntime runtime(fCallBackArray); 753 runtime.executeTokens((unsigned char*) data.bytes()); 754 SkScriptValue2 value1; 755 runtime.getResult(&value1.fOperand); 756 value1.fType = fReturnType; 757 fValueStack.push(value1); 758 } 759 if (value) { 760 if (fValueStack.count() == 0) 761 return false; 762 fValueStack.pop(value); 763 if (value->fType != fReturnType && value->fType == SkOperand2::kObject && 764 fReturnType != SkOperand2::kNoType) 765 convertTo(fReturnType, value); 766 } 767 // if (fBranchStack.top().fOpStackDepth > fOpStack.count()) 768 // resolveBranch(); 769 *scriptPtr = script; 770 return true; // no error 771 } 772 773 bool SkScriptEngine2::handleArrayIndexer(const char** scriptPtr) { 774 SkScriptValue2 scriptValue; 775 (*scriptPtr)++; 776 *fOpStack.push() = (Op) kParen; 777 *fBraceStack.push() = kArrayBrace; 778 SkOperand2::OpType saveType = fReturnType; 779 fReturnType = SkOperand2::kS32; 780 bool success = innerScript(scriptPtr, &scriptValue); 781 fReturnType = saveType; 782 SkASSERT(success); 783 success = convertTo(SkOperand2::kS32, &scriptValue); 784 SkASSERT(success); 785 int index = scriptValue.fOperand.fS32; 786 fValueStack.pop(&scriptValue); 787 if (scriptValue.fType == SkOperand2::kObject) { 788 success = handleUnbox(&scriptValue); 789 SkASSERT(success); 790 SkASSERT(scriptValue.fType == SkOperand2::kArray); 791 } 792 scriptValue.fType = scriptValue.fOperand.fArray->getType(); 793 // SkASSERT(index >= 0); 794 if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) { 795 fError = kArrayIndexOutOfBounds; 796 return false; 797 } 798 scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index]; 799 scriptValue.fIsConstant = SkScriptValue2::kVariable; 800 fValueStack.push(scriptValue); 801 fOpStack.pop(); // pop paren 802 return success; 803 } 804 805 bool SkScriptEngine2::handleFunction(const char** scriptPtr) { 806 const char* functionName = fToken; 807 size_t functionNameLen = fTokenLength; 808 fTokenLength = 0; 809 SkTDArray<SkScriptValue2> params; 810 bool success = functionParams(scriptPtr, ¶ms); 811 if (success == false) 812 goto done; 813 { 814 for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { 815 if ((*callBack)->getType() != SkScriptCallBack::kFunction) 816 continue; 817 SkScriptValue2 callbackResult; 818 success = (*callBack)->getReference(functionName, functionNameLen, &callbackResult); 819 if (success) { 820 callbackResult.fType = (*callBack)->getReturnType(callbackResult.fOperand.fReference, NULL); 821 callbackResult.fIsConstant = SkScriptValue2::kVariable; 822 fValueStack.push(callbackResult); 823 goto done; 824 } 825 } 826 } 827 return false; 828 done: 829 fOpStack.pop(); 830 return success; 831 } 832 833 bool SkScriptEngine2::handleMember(const char* field, size_t len, void* object) { 834 bool success = true; 835 for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { 836 if ((*callBack)->getType() != SkScriptCallBack::kMember) 837 continue; 838 SkScriptValue2 callbackResult; 839 success = (*callBack)->getReference(field, len, &callbackResult); 840 if (success) { 841 if (callbackResult.fType == SkOperand2::kString) 842 track(callbackResult.fOperand.fString); 843 callbackResult.fIsConstant = SkScriptValue2::kVariable; 844 fValueStack.push(callbackResult); 845 goto done; 846 } 847 } 848 return false; 849 done: 850 return success; 851 } 852 853 bool SkScriptEngine2::handleMemberFunction(const char* field, size_t len, void* object, 854 SkTDArray<SkScriptValue2>* params) { 855 bool success = true; 856 for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { 857 if ((*callBack)->getType() != SkScriptCallBack::kMemberFunction) 858 continue; 859 SkScriptValue2 callbackResult; 860 success = (*callBack)->getReference(field, len, &callbackResult); 861 if (success) { 862 if (callbackResult.fType == SkOperand2::kString) 863 track(callbackResult.fOperand.fString); 864 callbackResult.fIsConstant = SkScriptValue2::kVariable; 865 fValueStack.push(callbackResult); 866 goto done; 867 } 868 } 869 return false; 870 done: 871 return success; 872 } 873 874 bool SkScriptEngine2::handleProperty() { 875 bool success = true; 876 for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { 877 if ((*callBack)->getType() != SkScriptCallBack::kProperty) 878 continue; 879 SkScriptValue2 callbackResult; 880 success = (*callBack)->getReference(fToken, fTokenLength, &callbackResult); 881 if (success) { 882 if (callbackResult.fType == SkOperand2::kString && callbackResult.fOperand.fString == NULL) { 883 callbackResult.fOperand.fString = new SkString(fToken, fTokenLength); 884 track(callbackResult.fOperand.fString); 885 } 886 callbackResult.fIsConstant = SkScriptValue2::kVariable; 887 fValueStack.push(callbackResult); 888 goto done; 889 } 890 } 891 done: 892 fTokenLength = 0; 893 return success; 894 } 895 896 bool SkScriptEngine2::handleUnbox(SkScriptValue2* scriptValue) { 897 bool success = true; 898 for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { 899 if ((*callBack)->getType() != SkScriptCallBack::kUnbox) 900 continue; 901 SkScriptCallBackConvert* callBackConvert = (SkScriptCallBackConvert*) *callBack; 902 success = callBackConvert->convert(scriptValue->fType, &scriptValue->fOperand); 903 if (success) { 904 if (scriptValue->fType == SkOperand2::kString) 905 track(scriptValue->fOperand.fString); 906 goto done; 907 } 908 } 909 return false; 910 done: 911 return success; 912 } 913 914 // note that entire expression is treated as if it were enclosed in parens 915 // an open paren is always the first thing in the op stack 916 917 int SkScriptEngine2::logicalOp(char ch, char nextChar) { 918 int advance = 1; 919 Op op; 920 signed char precedence; 921 switch (ch) { 922 case ')': 923 op = (Op) kParen; 924 break; 925 case ']': 926 op = (Op) kArrayOp; 927 break; 928 case '?': 929 op = (Op) kIf; 930 break; 931 case ':': 932 op = (Op) kElse; 933 break; 934 case '&': 935 if (nextChar != '&') 936 goto noMatch; 937 op = kLogicalAnd; 938 advance = 2; 939 break; 940 case '|': 941 if (nextChar != '|') 942 goto noMatch; 943 op = kLogicalOr; 944 advance = 2; 945 break; 946 default: 947 noMatch: 948 return 0; 949 } 950 precedence = gPrecedence[op]; 951 int branchIndex = 0; 952 fBranchPopAllowed = false; 953 do { 954 while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence) 955 processOp(); 956 Branch& branch = fBranchStack.index(branchIndex++); 957 Op branchOp = branch.fOperator; 958 if (gPrecedence[branchOp] >= precedence) 959 break; 960 addTokenValue(fValueStack.top(), kAccumulator); 961 fValueStack.pop(); 962 if (branchOp == kLogicalAnd || branchOp == kLogicalOr) { 963 if (branch.fOperator == kLogicalAnd) 964 branch.prime(); 965 addToken(kToBool); 966 } else 967 resolveBranch(branch); 968 if (branch.fDone == Branch::kIsNotDone) 969 branch.prime(); 970 } while (true); 971 fBranchPopAllowed = true; 972 while (fBranchStack.top().fDone == Branch::kIsDone) 973 fBranchStack.pop(); 974 processLogicalOp(op); 975 return advance; 976 } 977 978 void SkScriptEngine2::processLogicalOp(Op op) { 979 switch (op) { 980 case kParen: 981 case kArrayOp: 982 SkASSERT(fOpStack.count() > 1 && fOpStack.top() == op); // !!! add error handling 983 if (op == kParen) 984 fOpStack.pop(); 985 else { 986 SkScriptValue2 value; 987 fValueStack.pop(&value); 988 SkASSERT(value.fType == SkOperand2::kS32 || value.fType == SkOperand2::kScalar); // !!! add error handling (although, could permit strings eventually) 989 int index = value.fType == SkOperand2::kScalar ? SkScalarFloor(value.fOperand.fScalar) : 990 value.fOperand.fS32; 991 SkScriptValue2 arrayValue; 992 fValueStack.pop(&arrayValue); 993 SkASSERT(arrayValue.fType == SkOperand2::kArray); // !!! add error handling 994 SkOpArray* array = arrayValue.fOperand.fArray; 995 SkOperand2 operand; 996 bool success = array->getIndex(index, &operand); 997 SkASSERT(success); // !!! add error handling 998 SkScriptValue2 resultValue; 999 resultValue.fType = array->getType(); 1000 resultValue.fOperand = operand; 1001 resultValue.fIsConstant = SkScriptValue2::kVariable; 1002 fValueStack.push(resultValue); 1003 } 1004 break; 1005 case kIf: { 1006 if (fAccumulatorType == SkOperand2::kNoType) { 1007 addTokenValue(fValueStack.top(), kAccumulator); 1008 fValueStack.pop(); 1009 } 1010 SkASSERT(fAccumulatorType != SkOperand2::kString); // !!! add error handling 1011 addToken(kIfOp); 1012 Branch branch(op, fOpStack.count(), getTokenOffset()); 1013 *fBranchStack.push() = branch; 1014 addTokenInt(0); // placeholder for future branch 1015 fAccumulatorType = SkOperand2::kNoType; 1016 } break; 1017 case kElse: { 1018 addTokenValue(fValueStack.top(), kAccumulator); 1019 fValueStack.pop(); 1020 addToken(kElseOp); 1021 size_t newOffset = getTokenOffset(); 1022 addTokenInt(0); // placeholder for future branch 1023 Branch& branch = fBranchStack.top(); 1024 resolveBranch(branch); 1025 branch.fOperator = op; 1026 branch.fDone = Branch::kIsNotDone; 1027 SkASSERT(branch.fOpStackDepth == fOpStack.count()); 1028 branch.fOffset = newOffset; 1029 fAccumulatorType = SkOperand2::kNoType; 1030 } break; 1031 case kLogicalAnd: 1032 case kLogicalOr: { 1033 Branch& oldTop = fBranchStack.top(); 1034 Branch::Primed wasPrime = oldTop.fPrimed; 1035 Branch::Done wasDone = oldTop.fDone; 1036 oldTop.fPrimed = Branch::kIsNotPrimed; 1037 oldTop.fDone = Branch::kIsNotDone; 1038 if (fAccumulatorType == SkOperand2::kNoType) { 1039 SkASSERT(fValueStack.top().fType == SkOperand2::kS32); // !!! add error handling, and conversion to int? 1040 addTokenValue(fValueStack.top(), kAccumulator); 1041 fValueStack.pop(); 1042 } else { 1043 SkASSERT(fAccumulatorType == SkOperand2::kS32); 1044 } 1045 // if 'and', write beq goto opcode after end of predicate (after to bool) 1046 // if 'or', write bne goto to bool 1047 addToken(op == kLogicalAnd ? kLogicalAndInt : kLogicalOrInt); 1048 Branch branch(op, fOpStack.count(), getTokenOffset()); 1049 addTokenInt(0); // placeholder for future branch 1050 oldTop.fPrimed = wasPrime; 1051 oldTop.fDone = wasDone; 1052 *fBranchStack.push() = branch; 1053 fAccumulatorType = SkOperand2::kNoType; 1054 } break; 1055 default: 1056 SkASSERT(0); 1057 } 1058 } 1059 1060 bool SkScriptEngine2::processOp() { 1061 Op op; 1062 fOpStack.pop(&op); 1063 op = (Op) (op & ~kArtificialOp); 1064 const OperatorAttributes* attributes = &gOpAttributes[op]; 1065 SkScriptValue2 value1; 1066 memset(&value1, 0, sizeof(SkScriptValue2)); 1067 SkScriptValue2 value2; 1068 fValueStack.pop(&value2); 1069 value2.fIsWritten = SkScriptValue2::kUnwritten; 1070 // SkScriptEngine2::SkTypeOp convert1[3]; 1071 // SkScriptEngine2::SkTypeOp convert2[3]; 1072 // SkScriptEngine2::SkTypeOp* convert2Ptr = convert2; 1073 bool constantOperands = value2.fIsConstant == SkScriptValue2::kConstant; 1074 if (attributes->fLeftType != SkOperand2::kNoType) { 1075 fValueStack.pop(&value1); 1076 constantOperands &= value1.fIsConstant == SkScriptValue2::kConstant; 1077 value1.fIsWritten = SkScriptValue2::kUnwritten; 1078 if (op == kFlipOps) { 1079 SkTSwap(value1, value2); 1080 fOpStack.pop(&op); 1081 op = (Op) (op & ~kArtificialOp); 1082 attributes = &gOpAttributes[op]; 1083 if (constantOperands == false) 1084 addToken(kFlipOpsOp); 1085 } 1086 if (value1.fType == SkOperand2::kObject && (value1.fType & attributes->fLeftType) == 0) { 1087 value1.fType = getUnboxType(value1.fOperand); 1088 addToken(kUnboxToken); 1089 } 1090 } 1091 if (value2.fType == SkOperand2::kObject && (value2.fType & attributes->fLeftType) == 0) { 1092 value1.fType = getUnboxType(value2.fOperand); 1093 addToken(kUnboxToken2); 1094 } 1095 if (attributes->fLeftType != SkOperand2::kNoType) { 1096 if (value1.fType != value2.fType) { 1097 if ((attributes->fLeftType & SkOperand2::kString) && attributes->fBias & kTowardsString && 1098 ((value1.fType | value2.fType) & SkOperand2::kString)) { 1099 if (value1.fType == SkOperand2::kS32 || value1.fType == SkOperand2::kScalar) { 1100 addTokenConst(&value1, kAccumulator, SkOperand2::kString, 1101 value1.fType == SkOperand2::kS32 ? kIntToString : kScalarToString); 1102 } 1103 if (value2.fType == SkOperand2::kS32 || value2.fType == SkOperand2::kScalar) { 1104 addTokenConst(&value2, kOperand, SkOperand2::kString, 1105 value2.fType == SkOperand2::kS32 ? kIntToString2 : kScalarToString2); 1106 } 1107 } else if (attributes->fLeftType & SkOperand2::kScalar && ((value1.fType | value2.fType) & 1108 SkOperand2::kScalar)) { 1109 if (value1.fType == SkOperand2::kS32) 1110 addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kIntToScalar); 1111 if (value2.fType == SkOperand2::kS32) 1112 addTokenConst(&value2, kOperand, SkOperand2::kScalar, kIntToScalar2); 1113 } 1114 } 1115 if ((value1.fType & attributes->fLeftType) == 0 || value1.fType != value2.fType) { 1116 if (value1.fType == SkOperand2::kString) 1117 addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kStringToScalar); 1118 if (value1.fType == SkOperand2::kScalar && (attributes->fLeftType == SkOperand2::kS32 || 1119 value2.fType == SkOperand2::kS32)) 1120 addTokenConst(&value1, kAccumulator, SkOperand2::kS32, kScalarToInt); 1121 } 1122 } 1123 AddTokenRegister rhRegister = attributes->fLeftType != SkOperand2::kNoType ? 1124 kOperand : kAccumulator; 1125 if ((value2.fType & attributes->fRightType) == 0 || value1.fType != value2.fType) { 1126 if (value2.fType == SkOperand2::kString) 1127 addTokenConst(&value2, rhRegister, SkOperand2::kScalar, kStringToScalar2); 1128 if (value2.fType == SkOperand2::kScalar && (attributes->fRightType == SkOperand2::kS32 || 1129 value1.fType == SkOperand2::kS32)) 1130 addTokenConst(&value2, rhRegister, SkOperand2::kS32, kScalarToInt2); 1131 } 1132 TypeOp typeOp = gTokens[op]; 1133 if (value2.fType == SkOperand2::kScalar) 1134 typeOp = (TypeOp) (typeOp + 1); 1135 else if (value2.fType == SkOperand2::kString) 1136 typeOp = (TypeOp) (typeOp + 2); 1137 SkDynamicMemoryWStream stream; 1138 SkOperand2::OpType saveType = SkOperand2::kNoType; 1139 SkBool saveOperand = false; 1140 if (constantOperands) { 1141 fActiveStream = &stream; 1142 saveType = fAccumulatorType; 1143 saveOperand = fOperandInUse; 1144 fAccumulatorType = SkOperand2::kNoType; 1145 fOperandInUse = false; 1146 } 1147 if (attributes->fLeftType != SkOperand2::kNoType) { // two operands 1148 if (value1.fIsWritten == SkScriptValue2::kUnwritten) 1149 addTokenValue(value1, kAccumulator); 1150 } 1151 if (value2.fIsWritten == SkScriptValue2::kUnwritten) 1152 addTokenValue(value2, rhRegister); 1153 addToken(typeOp); 1154 if (constantOperands) { 1155 addToken(kEnd); 1156 SkAutoDataUnref data(fStream.copyToData()); 1157 #ifdef SK_DEBUG 1158 decompile(data.bytes(), data.size()); 1159 #endif 1160 SkScriptRuntime runtime(fCallBackArray); 1161 runtime.executeTokens((unsigned char*)data.bytes()); 1162 runtime.getResult(&value1.fOperand); 1163 if (attributes->fResultIsBoolean == kResultIsBoolean) 1164 value1.fType = SkOperand2::kS32; 1165 else if (attributes->fLeftType == SkOperand2::kNoType) // unary operand 1166 value1.fType = value2.fType; 1167 fValueStack.push(value1); 1168 if (value1.fType == SkOperand2::kString) 1169 runtime.untrack(value1.fOperand.fString); 1170 else if (value1.fType == SkOperand2::kArray) 1171 runtime.untrack(value1.fOperand.fArray); 1172 fActiveStream = &fStream; 1173 fAccumulatorType = saveType; 1174 fOperandInUse = saveOperand; 1175 return true; 1176 } 1177 value2.fIsConstant = SkScriptValue2::kVariable; 1178 fValueStack.push(value2); 1179 return true; 1180 } 1181 1182 void SkScriptEngine2::Branch::resolve(SkDynamicMemoryWStream* stream, size_t off) { 1183 SkASSERT(fDone == kIsNotDone); 1184 fPrimed = kIsNotPrimed; 1185 fDone = kIsDone; 1186 SkASSERT(off > fOffset + sizeof(size_t)); 1187 size_t offset = off - fOffset - sizeof(offset); 1188 stream->write(&offset, fOffset, sizeof(offset)); 1189 } 1190 1191 void SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) { 1192 branch.resolve(fActiveStream, getTokenOffset()); 1193 } 1194 1195 bool SkScriptEngine2::ConvertTo(SkScriptEngine2* engine, SkOperand2::OpType toType, SkScriptValue2* value ) { 1196 SkASSERT(value); 1197 SkOperand2::OpType type = value->fType; 1198 if (type == toType) 1199 return true; 1200 SkOperand2& operand = value->fOperand; 1201 bool success = true; 1202 switch (toType) { 1203 case SkOperand2::kS32: 1204 if (type == SkOperand2::kScalar) 1205 operand.fS32 = SkScalarFloor(operand.fScalar); 1206 else { 1207 SkASSERT(type == SkOperand2::kString); 1208 success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != NULL; 1209 } 1210 break; 1211 case SkOperand2::kScalar: 1212 if (type == SkOperand2::kS32) 1213 operand.fScalar = IntToScalar(operand.fS32); 1214 else { 1215 SkASSERT(type == SkOperand2::kString); 1216 success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != NULL; 1217 } 1218 break; 1219 case SkOperand2::kString: { 1220 SkString* strPtr = new SkString(); 1221 SkASSERT(engine); 1222 engine->track(strPtr); 1223 if (type == SkOperand2::kS32) 1224 strPtr->appendS32(operand.fS32); 1225 else { 1226 SkASSERT(type == SkOperand2::kScalar); 1227 strPtr->appendScalar(operand.fScalar); 1228 } 1229 operand.fString = strPtr; 1230 } break; 1231 case SkOperand2::kArray: { 1232 SkOpArray* array = new SkOpArray(type); 1233 *array->append() = operand; 1234 engine->track(array); 1235 operand.fArray = array; 1236 } break; 1237 default: 1238 SkASSERT(0); 1239 } 1240 value->fType = toType; 1241 return success; 1242 } 1243 1244 SkScalar SkScriptEngine2::IntToScalar(int32_t s32) { 1245 SkScalar scalar; 1246 if (s32 == (int32_t) SK_NaN32) 1247 scalar = SK_ScalarNaN; 1248 else if (SkAbs32(s32) == SK_MaxS32) 1249 scalar = SkSign32(s32) * SK_ScalarMax; 1250 else 1251 scalar = SkIntToScalar(s32); 1252 return scalar; 1253 } 1254 1255 bool SkScriptEngine2::ValueToString(const SkScriptValue2& value, SkString* string) { 1256 switch (value.fType) { 1257 case SkOperand2::kS32: 1258 string->reset(); 1259 string->appendS32(value.fOperand.fS32); 1260 break; 1261 case SkOperand2::kScalar: 1262 string->reset(); 1263 string->appendScalar(value.fOperand.fScalar); 1264 break; 1265 case SkOperand2::kString: 1266 string->set(*value.fOperand.fString); 1267 break; 1268 default: 1269 SkASSERT(0); 1270 return false; 1271 } 1272 return true; // no error 1273 } 1274 1275 #ifdef SK_DEBUG 1276 1277 #define testInt(expression) { #expression, SkOperand2::kS32, expression, 0, NULL } 1278 #ifdef SK_SCALAR_IS_FLOAT 1279 #define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (float) expression, NULL } 1280 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmodf(exp1, exp2), NULL } 1281 #else 1282 #ifdef SK_CAN_USE_FLOAT 1283 #define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (int) ((expression) * 65536.0f), NULL } 1284 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, (int) (fmod(exp1, exp2) * 65536.0f), NULL } 1285 #endif 1286 #endif 1287 #define testTrue(expression) { #expression, SkOperand2::kS32, 1, 0, NULL } 1288 #define testFalse(expression) { #expression, SkOperand2::kS32, 0, 0, NULL } 1289 1290 static const SkScriptNAnswer2 scriptTests[] = { 1291 testInt(1||(0&&3)), 1292 #ifdef SK_CAN_USE_FLOAT 1293 testScalar(- -5.5- -1.5), 1294 testScalar(1.0+5), 1295 #endif 1296 testInt((6+7)*8), 1297 testInt(3*(4+5)), 1298 #ifdef SK_CAN_USE_FLOAT 1299 testScalar(1.0+2.0), 1300 testScalar(3.0-1.0), 1301 testScalar(6-1.0), 1302 testScalar(2.5*6.), 1303 testScalar(0.5*4), 1304 testScalar(4.5/.5), 1305 testScalar(9.5/19), 1306 testRemainder(9.5, 0.5), 1307 testRemainder(9.,2), 1308 testRemainder(9,2.5), 1309 testRemainder(-9,2.5), 1310 testTrue(-9==-9.0), 1311 testTrue(-9.==-4.0-5), 1312 testTrue(-9.*1==-4-5), 1313 testFalse(-9!=-9.0), 1314 testFalse(-9.!=-4.0-5), 1315 testFalse(-9.*1!=-4-5), 1316 #endif 1317 testInt(0x123), 1318 testInt(0XABC), 1319 testInt(0xdeadBEEF), 1320 { "'123'+\"456\"", SkOperand2::kString, 0, 0, "123456" }, 1321 { "123+\"456\"", SkOperand2::kString, 0, 0, "123456" }, 1322 { "'123'+456", SkOperand2::kString, 0, 0, "123456" }, 1323 { "'123'|\"456\"", SkOperand2::kS32, 123|456, 0, NULL }, 1324 { "123|\"456\"", SkOperand2::kS32, 123|456, 0, NULL }, 1325 { "'123'|456", SkOperand2::kS32, 123|456, 0, NULL }, 1326 { "'2'<11", SkOperand2::kS32, 1, 0, NULL }, 1327 { "2<'11'", SkOperand2::kS32, 1, 0, NULL }, 1328 { "'2'<'11'", SkOperand2::kS32, 0, 0, NULL }, 1329 testInt(123), 1330 testInt(-345), 1331 testInt(+678), 1332 testInt(1+2+3), 1333 testInt(3*4+5), 1334 testInt(6+7*8), 1335 testInt(-1-2-8/4), 1336 testInt(-9%4), 1337 testInt(9%-4), 1338 testInt(-9%-4), 1339 testInt(123|978), 1340 testInt(123&978), 1341 testInt(123^978), 1342 testInt(2<<4), 1343 testInt(99>>3), 1344 testInt(~55), 1345 testInt(~~55), 1346 testInt(!55), 1347 testInt(!!55), 1348 // both int 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 testInt(2>2), 1356 testInt(2>11), 1357 testInt(20>11), 1358 testInt(2>=2), 1359 testInt(2>=11), 1360 testInt(20>=11), 1361 testInt(2==2), 1362 testInt(2==11), 1363 testInt(20==11), 1364 testInt(2!=2), 1365 testInt(2!=11), 1366 testInt(20!=11), 1367 #ifdef SK_CAN_USE_FLOAT 1368 // left int, right scalar 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 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 // left scalar, right int 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 testInt(2.>2), 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 // both scalar 1407 testInt(2.<11.), 1408 testInt(20.<11.), 1409 testInt(2.<=2.), 1410 testInt(2.<=11.), 1411 testInt(20.<=11.), 1412 testInt(2.>2.), 1413 testInt(2.>11.), 1414 testInt(20.>11.), 1415 testInt(2.>=2.), 1416 testInt(2.>=11.), 1417 testInt(20.>=11.), 1418 testInt(2.==2.), 1419 testInt(2.==11.), 1420 testInt(20.==11.), 1421 testInt(2.!=2.), 1422 testInt(2.!=11.), 1423 testInt(20.!=11.), 1424 #endif 1425 // int, string (string is int) 1426 testFalse(2<'2'), 1427 testTrue(2<'11'), 1428 testFalse(20<'11'), 1429 testTrue(2<='2'), 1430 testTrue(2<='11'), 1431 testFalse(20<='11'), 1432 testFalse(2>'2'), 1433 testFalse(2>'11'), 1434 testTrue(20>'11'), 1435 testTrue(2>='2'), 1436 testFalse(2>='11'), 1437 testTrue(20>='11'), 1438 testTrue(2=='2'), 1439 testFalse(2=='11'), 1440 testFalse(2!='2'), 1441 testTrue(2!='11'), 1442 // int, string (string is scalar) 1443 testFalse(2<'2.'), 1444 testTrue(2<'11.'), 1445 testFalse(20<'11.'), 1446 testTrue(2=='2.'), 1447 testFalse(2=='11.'), 1448 #ifdef SK_CAN_USE_FLOAT 1449 // scalar, string 1450 testFalse(2.<'2.'), 1451 testTrue(2.<'11.'), 1452 testFalse(20.<'11.'), 1453 testTrue(2.=='2.'), 1454 testFalse(2.=='11.'), 1455 // string, int 1456 testFalse('2'<2), 1457 testTrue('2'<11), 1458 testFalse('20'<11), 1459 testTrue('2'==2), 1460 testFalse('2'==11), 1461 // string, scalar 1462 testFalse('2'<2.), 1463 testTrue('2'<11.), 1464 testFalse('20'<11.), 1465 testTrue('2'==2.), 1466 testFalse('2'==11.), 1467 #endif 1468 // string, string 1469 testFalse('2'<'2'), 1470 testFalse('2'<'11'), 1471 testFalse('20'<'11'), 1472 testTrue('2'=='2'), 1473 testFalse('2'=='11'), 1474 // logic 1475 testInt(1?2:3), 1476 testInt(0?2:3), 1477 testInt((1&&2)||3), 1478 testInt((1&&0)||3), 1479 testInt((1&&0)||0), 1480 testInt(1||(0&&3)), 1481 testInt(0||(0&&3)), 1482 testInt(0||(1&&3)), 1483 testInt(0&&1?2:3) 1484 #ifdef SK_CAN_USE_FLOAT 1485 , { "123.5", SkOperand2::kScalar, 0, SkIntToScalar(123) + SK_Scalar1/2, NULL } 1486 #endif 1487 }; 1488 1489 #define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) 1490 1491 void SkScriptEngine2::UnitTest() { 1492 #if defined(SK_SUPPORT_UNITTEST) 1493 ValidateDecompileTable(); 1494 for (int index = 0; index < SkScriptNAnswer_testCount; index++) { 1495 SkScriptEngine2 engine(scriptTests[index].fType); 1496 SkScriptValue2 value; 1497 const char* script = scriptTests[index].fScript; 1498 const char* scriptPtr = script; 1499 SkASSERT(engine.evaluateScript(&scriptPtr, &value) == true); 1500 SkASSERT(value.fType == scriptTests[index].fType); 1501 SkScalar error; 1502 switch (value.fType) { 1503 case SkOperand2::kS32: 1504 if (value.fOperand.fS32 != scriptTests[index].fIntAnswer) 1505 SkDEBUGF(("script '%s' == value %d != expected answer %d\n", script, value.fOperand.fS32, scriptTests[index].fIntAnswer)); 1506 SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); 1507 break; 1508 case SkOperand2::kScalar: 1509 error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); 1510 #ifdef SK_CAN_USE_FLOAT 1511 if (error >= SK_Scalar1 / 10000) 1512 SkDEBUGF(("script '%s' == value %g != expected answer %g\n", script, value.fOperand.fScalar / (1.0f * SK_Scalar1), scriptTests[index].fScalarAnswer / (1.0f * SK_Scalar1))); 1513 #endif 1514 SkASSERT(error < SK_Scalar1 / 10000); 1515 break; 1516 case SkOperand2::kString: 1517 SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer)); 1518 break; 1519 default: 1520 SkASSERT(0); 1521 } 1522 } 1523 #endif 1524 } 1525 #endif 1526