OLD | NEW |
| (Empty) |
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 }, | |
12 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kStrin
g), | |
13 SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kStr
ing), kTowardsString }, // kAdd | |
14 { SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kBitAnd | |
15 { SkOperand2::kNoType, SkOperand2::kS32, kNoBias }, // kBitNot | |
16 { SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kBitOr | |
17 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), | |
18 SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kD
ivide | |
19 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kStrin
g), | |
20 SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar |SkOperand2:: kStr
ing), kTowardsNumber, | |
21 kResultIsBoolean }, // kEqual | |
22 { SkOperand2::kS32 }, // kFlipOps | |
23 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kStrin
g), | |
24 SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kStr
ing), kTowardsNumber, | |
25 kResultIsBoolean }, // kGreaterEqual | |
26 { SkOperand2::kNoType, SkOperand2::kS32, kNoBias }, // kLogicalAnd (really, T
oBool) | |
27 { SkOperand2::kNoType, SkOperand2::kS32, kNoBias }, // kLogicalNot | |
28 { SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kLogicalOr | |
29 { SkOperand2::kNoType, SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar
), kNoBias }, // kMinus | |
30 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), | |
31 SkOperand2::OpType(SkOperand2::kS32 |SkOperand2:: kScalar), kNoBias }, // kM
odulo | |
32 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), | |
33 SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kM
ultiply | |
34 { SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kShiftLeft | |
35 { SkOperand2::kS32, SkOperand2::kS32, kNoBias }, // kShiftRight | |
36 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), | |
37 SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kS
ubtract | |
38 { SkOperand2::kS32, SkOperand2::kS32, kNoBias } // 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(c
h, '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.e
nd(); 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, val
ue)) | |
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, AddTokenRegiste
r 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 o
f | |
220 // suppressing errors like +"hi" | |
221 if (lastPush == false) // unary plus, don't push an operator | |
222 goto returnAdv; | |
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 goto returnAdv; | |
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 returnAdv: | |
323 return advance; | |
324 } | |
325 | |
326 bool SkScriptEngine2::convertParams(SkTDArray<SkScriptValue2>* params, | |
327 const SkOperand2::OpType* paramTypes, int pa
ramCount) { | |
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, s
ize_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* val
ue) { | |
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::kSt
ring) { | |
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 wri
tten 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<SkScriptV
alue2>* 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 < fCallB
ackArray.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 conversion
s | |
489 if (value->fOperand.fArray->count() == 0) | |
490 value->fOperand.fArray->setType(type = tokenValue.fT
ype); | |
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().fTy
pe : 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 pro
perty 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 (err
or?) | |
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 < fC
allBackArray.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 < fCallB
ackArray.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 < fCallB
ackArray.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 < fCallB
ackArray.end(); callBack++) { | |
867 if ((*callBack)->getType() != SkScriptCallBack::kProperty) | |
868 continue; | |
869 SkScriptValue2 callbackResult; | |
870 success = (*callBack)->getReference(fToken, fTokenLength, &callbackResul
t); | |
871 if (success) { | |
872 if (callbackResult.fType == SkOperand2::kString && callbackResult.fO
perand.fString == NULL) { | |
873 callbackResult.fOperand.fString = new SkString(fToken, fTokenLen
gth); | |
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 < fCallB
ackArray.end(); callBack++) { | |
889 if ((*callBack)->getType() != SkScriptCallBack::kUnbox) | |
890 continue; | |
891 SkScriptCallBackConvert* callBackConvert = (SkScriptCallBackConvert*) *c
allBack; | |
892 success = callBackConvert->convert(scriptValue->fType, &scriptValue->fOp
erand); | |
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); // !!! ad
d 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 == SkOpe
rand2::kScalar); // !!! add error handling (although, could permit strings event
ually) | |
979 int index = value.fType == SkOperand2::kScalar ? SkScalarFloor(v
alue.fOperand.fScalar) : | |
980 value.fOperand.fS32; | |
981 SkScriptValue2 arrayValue; | |
982 fValueStack.pop(&arrayValue); | |
983 SkASSERT(arrayValue.fType == SkOperand2::kArray); // !!! add er
ror 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); // !!! ad
d 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 = { 0 }; | |
1055 SkScriptValue2 value2; | |
1056 fValueStack.pop(&value2); | |
1057 value2.fIsWritten = SkScriptValue2::kUnwritten; | |
1058 // SkScriptEngine2::SkTypeOp convert1[3]; | |
1059 // SkScriptEngine2::SkTypeOp convert2[3]; | |
1060 // SkScriptEngine2::SkTypeOp* convert2Ptr = convert2; | |
1061 bool constantOperands = value2.fIsConstant == SkScriptValue2::kConstant; | |
1062 if (attributes->fLeftType != SkOperand2::kNoType) { | |
1063 fValueStack.pop(&value1); | |
1064 constantOperands &= value1.fIsConstant == SkScriptValue2::kConstant; | |
1065 value1.fIsWritten = SkScriptValue2::kUnwritten; | |
1066 if (op == kFlipOps) { | |
1067 SkTSwap(value1, value2); | |
1068 fOpStack.pop(&op); | |
1069 op = (Op) (op & ~kArtificialOp); | |
1070 attributes = &gOpAttributes[op]; | |
1071 if (constantOperands == false) | |
1072 addToken(kFlipOpsOp); | |
1073 } | |
1074 if (value1.fType == SkOperand2::kObject && (value1.fType & attributes->f
LeftType) == 0) { | |
1075 value1.fType = getUnboxType(value1.fOperand); | |
1076 addToken(kUnboxToken); | |
1077 } | |
1078 } | |
1079 if (value2.fType == SkOperand2::kObject && (value2.fType & attributes->fLeft
Type) == 0) { | |
1080 value1.fType = getUnboxType(value2.fOperand); | |
1081 addToken(kUnboxToken2); | |
1082 } | |
1083 if (attributes->fLeftType != SkOperand2::kNoType) { | |
1084 if (value1.fType != value2.fType) { | |
1085 if ((attributes->fLeftType & SkOperand2::kString) && attributes->fBi
as & kTowardsString && | |
1086 ((value1.fType | value2.fType) & SkOperand2::kString)) { | |
1087 if (value1.fType == SkOperand2::kS32 || value1.fType == SkOperan
d2::kScalar) { | |
1088 addTokenConst(&value1, kAccumulator, SkOperand2::kString, | |
1089 value1.fType == SkOperand2::kS32 ? kIntToStrin
g : kScalarToString); | |
1090 } | |
1091 if (value2.fType == SkOperand2::kS32 || value2.fType == SkOperan
d2::kScalar) { | |
1092 addTokenConst(&value2, kOperand, SkOperand2::kString, | |
1093 value2.fType == SkOperand2::kS32 ? kIntToStrin
g2 : kScalarToString2); | |
1094 } | |
1095 } else if (attributes->fLeftType & SkOperand2::kScalar && ((value1.f
Type | value2.fType) & | |
1096 SkOperand
2::kScalar)) { | |
1097 if (value1.fType == SkOperand2::kS32) | |
1098 addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kI
ntToScalar); | |
1099 if (value2.fType == SkOperand2::kS32) | |
1100 addTokenConst(&value2, kOperand, SkOperand2::kScalar, kIntTo
Scalar2); | |
1101 } | |
1102 } | |
1103 if ((value1.fType & attributes->fLeftType) == 0 || value1.fType != value
2.fType) { | |
1104 if (value1.fType == SkOperand2::kString) | |
1105 addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kStrin
gToScalar); | |
1106 if (value1.fType == SkOperand2::kScalar && (attributes->fLeftType ==
SkOperand2::kS32 || | |
1107 value2.fType == SkOperan
d2::kS32)) | |
1108 addTokenConst(&value1, kAccumulator, SkOperand2::kS32, kScalarTo
Int); | |
1109 } | |
1110 } | |
1111 AddTokenRegister rhRegister = attributes->fLeftType != SkOperand2::kNoType ? | |
1112 kOperand : kAccumulator; | |
1113 if ((value2.fType & attributes->fRightType) == 0 || value1.fType != value2.f
Type) { | |
1114 if (value2.fType == SkOperand2::kString) | |
1115 addTokenConst(&value2, rhRegister, SkOperand2::kScalar, kStringToSca
lar2); | |
1116 if (value2.fType == SkOperand2::kScalar && (attributes->fRightType == Sk
Operand2::kS32 || | |
1117 value1.fType == SkOperand2::
kS32)) | |
1118 addTokenConst(&value2, rhRegister, SkOperand2::kS32, kScalarToInt2); | |
1119 } | |
1120 TypeOp typeOp = gTokens[op]; | |
1121 if (value2.fType == SkOperand2::kScalar) | |
1122 typeOp = (TypeOp) (typeOp + 1); | |
1123 else if (value2.fType == SkOperand2::kString) | |
1124 typeOp = (TypeOp) (typeOp + 2); | |
1125 SkDynamicMemoryWStream stream; | |
1126 SkOperand2::OpType saveType; | |
1127 SkBool saveOperand; | |
1128 if (constantOperands) { | |
1129 fActiveStream = &stream; | |
1130 saveType = fAccumulatorType; | |
1131 saveOperand = fOperandInUse; | |
1132 fAccumulatorType = SkOperand2::kNoType; | |
1133 fOperandInUse = false; | |
1134 } | |
1135 if (attributes->fLeftType != SkOperand2::kNoType) { // two operands | |
1136 if (value1.fIsWritten == SkScriptValue2::kUnwritten) | |
1137 addTokenValue(value1, kAccumulator); | |
1138 } | |
1139 if (value2.fIsWritten == SkScriptValue2::kUnwritten) | |
1140 addTokenValue(value2, rhRegister); | |
1141 addToken(typeOp); | |
1142 if (constantOperands) { | |
1143 addToken(kEnd); | |
1144 #ifdef SK_DEBUG | |
1145 decompile((const unsigned char*) stream.getStream(), stream.getOffset())
; | |
1146 #endif | |
1147 SkScriptRuntime runtime(fCallBackArray); | |
1148 runtime.executeTokens((unsigned char*) stream.getStream()); | |
1149 runtime.getResult(&value1.fOperand); | |
1150 if (attributes->fResultIsBoolean == kResultIsBoolean) | |
1151 value1.fType = SkOperand2::kS32; | |
1152 else if (attributes->fLeftType == SkOperand2::kNoType) // unary operand | |
1153 value1.fType = value2.fType; | |
1154 fValueStack.push(value1); | |
1155 if (value1.fType == SkOperand2::kString) | |
1156 runtime.untrack(value1.fOperand.fString); | |
1157 else if (value1.fType == SkOperand2::kArray) | |
1158 runtime.untrack(value1.fOperand.fArray); | |
1159 fActiveStream = &fStream; | |
1160 fAccumulatorType = saveType; | |
1161 fOperandInUse = saveOperand; | |
1162 return true; | |
1163 } | |
1164 value2.fIsConstant = SkScriptValue2::kVariable; | |
1165 fValueStack.push(value2); | |
1166 return true; | |
1167 } | |
1168 | |
1169 void SkScriptEngine2::Branch::resolve(SkDynamicMemoryWStream* stream, size_t off
) { | |
1170 SkASSERT(fDone == kIsNotDone); | |
1171 fPrimed = kIsNotPrimed; | |
1172 fDone = kIsDone; | |
1173 SkASSERT(off > fOffset + sizeof(size_t)); | |
1174 size_t offset = off - fOffset - sizeof(offset); | |
1175 stream->write(&offset, fOffset, sizeof(offset)); | |
1176 } | |
1177 | |
1178 void SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) { | |
1179 branch.resolve(fActiveStream, getTokenOffset()); | |
1180 } | |
1181 | |
1182 bool SkScriptEngine2::ConvertTo(SkScriptEngine2* engine, SkOperand2::OpType toTy
pe, SkScriptValue2* value ) { | |
1183 SkASSERT(value); | |
1184 SkOperand2::OpType type = value->fType; | |
1185 if (type == toType) | |
1186 return true; | |
1187 SkOperand2& operand = value->fOperand; | |
1188 bool success = true; | |
1189 switch (toType) { | |
1190 case SkOperand2::kS32: | |
1191 if (type == SkOperand2::kScalar) | |
1192 operand.fS32 = SkScalarFloor(operand.fScalar); | |
1193 else { | |
1194 SkASSERT(type == SkOperand2::kString); | |
1195 success = SkParse::FindS32(operand.fString->c_str(), &operand.fS
32) != NULL; | |
1196 } | |
1197 break; | |
1198 case SkOperand2::kScalar: | |
1199 if (type == SkOperand2::kS32) | |
1200 operand.fScalar = IntToScalar(operand.fS32); | |
1201 else { | |
1202 SkASSERT(type == SkOperand2::kString); | |
1203 success = SkParse::FindScalar(operand.fString->c_str(), &operand
.fScalar) != NULL; | |
1204 } | |
1205 break; | |
1206 case SkOperand2::kString: { | |
1207 SkString* strPtr = new SkString(); | |
1208 SkASSERT(engine); | |
1209 engine->track(strPtr); | |
1210 if (type == SkOperand2::kS32) | |
1211 strPtr->appendS32(operand.fS32); | |
1212 else { | |
1213 SkASSERT(type == SkOperand2::kScalar); | |
1214 strPtr->appendScalar(operand.fScalar); | |
1215 } | |
1216 operand.fString = strPtr; | |
1217 } break; | |
1218 case SkOperand2::kArray: { | |
1219 SkOpArray* array = new SkOpArray(type); | |
1220 *array->append() = operand; | |
1221 engine->track(array); | |
1222 operand.fArray = array; | |
1223 } break; | |
1224 default: | |
1225 SkASSERT(0); | |
1226 } | |
1227 value->fType = toType; | |
1228 return success; | |
1229 } | |
1230 | |
1231 SkScalar SkScriptEngine2::IntToScalar(int32_t s32) { | |
1232 SkScalar scalar; | |
1233 if (s32 == SK_NaN32) | |
1234 scalar = SK_ScalarNaN; | |
1235 else if (SkAbs32(s32) == SK_MaxS32) | |
1236 scalar = SkSign32(s32) * SK_ScalarMax; | |
1237 else | |
1238 scalar = SkIntToScalar(s32); | |
1239 return scalar; | |
1240 } | |
1241 | |
1242 bool SkScriptEngine2::ValueToString(const SkScriptValue2& value, SkString* strin
g) { | |
1243 switch (value.fType) { | |
1244 case SkOperand2::kS32: | |
1245 string->reset(); | |
1246 string->appendS32(value.fOperand.fS32); | |
1247 break; | |
1248 case SkOperand2::kScalar: | |
1249 string->reset(); | |
1250 string->appendScalar(value.fOperand.fScalar); | |
1251 break; | |
1252 case SkOperand2::kString: | |
1253 string->set(*value.fOperand.fString); | |
1254 break; | |
1255 default: | |
1256 SkASSERT(0); | |
1257 return false; | |
1258 } | |
1259 return true; // no error | |
1260 } | |
1261 | |
1262 #ifdef SK_DEBUG | |
1263 | |
1264 #define testInt(expression) { #expression, SkOperand2::kS32, expression } | |
1265 #ifdef SK_SCALAR_IS_FLOAT | |
1266 #define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (float) ex
pression } | |
1267 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmo
df(exp1, exp2) } | |
1268 #else | |
1269 #ifdef SK_CAN_USE_FLOAT | |
1270 #define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (int) ((ex
pression) * 65536.0f) } | |
1271 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, (in
t) (fmod(exp1, exp2) * 65536.0f) } | |
1272 #endif | |
1273 #endif | |
1274 #define testTrue(expression) { #expression, SkOperand2::kS32, 1 } | |
1275 #define testFalse(expression) { #expression, SkOperand2::kS32, 0 } | |
1276 | |
1277 #if !defined(SK_BUILD_FOR_BREW) | |
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 }, | |
1312 { "123|\"456\"", SkOperand2::kS32, 123|456 }, | |
1313 { "'123'|456", SkOperand2::kS32, 123|456 }, | |
1314 { "'2'<11", SkOperand2::kS32, 1 }, | |
1315 { "2<'11'", SkOperand2::kS32, 1 }, | |
1316 { "'2'<'11'", SkOperand2::kS32, 0 }, | |
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 } | |
1474 #endif | |
1475 }; | |
1476 #endif // build for brew | |
1477 | |
1478 #define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) | |
1479 | |
1480 void SkScriptEngine2::UnitTest() { | |
1481 #if !defined(SK_BUILD_FOR_BREW) && defined(SK_SUPPORT_UNITTEST) | |
1482 ValidateDecompileTable(); | |
1483 for (int index = 0; index < SkScriptNAnswer_testCount; index++) { | |
1484 SkScriptEngine2 engine(scriptTests[index].fType); | |
1485 SkScriptValue2 value; | |
1486 const char* script = scriptTests[index].fScript; | |
1487 const char* scriptPtr = script; | |
1488 SkASSERT(engine.evaluateScript(&scriptPtr, &value) == true); | |
1489 SkASSERT(value.fType == scriptTests[index].fType); | |
1490 SkScalar error; | |
1491 switch (value.fType) { | |
1492 case SkOperand2::kS32: | |
1493 if (value.fOperand.fS32 != scriptTests[index].fIntAnswer) | |
1494 SkDEBUGF(("script '%s' == value %d != expected answer %d\n",
script, value.fOperand.fS32, scriptTests[index].fIntAnswer)); | |
1495 SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); | |
1496 break; | |
1497 case SkOperand2::kScalar: | |
1498 error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].
fScalarAnswer); | |
1499 #ifdef SK_CAN_USE_FLOAT | |
1500 if (error >= SK_Scalar1 / 10000) | |
1501 SkDEBUGF(("script '%s' == value %g != expected answer %g\n",
script, value.fOperand.fScalar / (1.0f * SK_Scalar1), scriptTests[index].fScala
rAnswer / (1.0f * SK_Scalar1))); | |
1502 #endif | |
1503 SkASSERT(error < SK_Scalar1 / 10000); | |
1504 break; | |
1505 case SkOperand2::kString: | |
1506 SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStri
ngAnswer)); | |
1507 break; | |
1508 default: | |
1509 SkASSERT(0); | |
1510 } | |
1511 } | |
1512 #endif | |
1513 } | |
1514 #endif | |
OLD | NEW |