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