blob: 6d8c208d2d7354281015b3f60fb5eefddf6b85af [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SkScriptRuntime.h"
2#include "SkScript2.h"
3#include "SkParse.h"
4#include "SkScriptCallBack.h"
5#include "SkString.h"
6#include "SkOpArray.h"
7
8// script tokenizer
9
10// turn text into token string
11// turn number literals into inline UTF8-style values
12// process operators to turn standard notation into stack notation
13
14// defer processing until the tokens can all be resolved
15// then, turn token strings into indices into the appropriate tables / dictionaries
16
17// consider: const evaluation?
18
19// replace script string with script tokens preceeded by special value
20
21// need second version of script plugins that return private index of found value?
22 // then would need in script index of plugin, private index
23
24// encode brace stack push/pop as opcodes
25
26// should token script enocde type where possible?
27
28// current flow:
29 // strip whitespace
30 // if in array brace [ recurse, continue
31 // if token, handle function, or array, or property (continue)
32 // parse number, continue
33 // parse token, continue
34 // parse string literal, continue
35 // if dot operator, handle dot, continue
36 // if [ , handle array literal or accessor, continue
37 // if ), pop (if function, break)
38 // if ], pop ; if ',' break
39 // handle logical ops
40 // or, handle arithmetic ops
41 // loop
42
43// !!! things to do
44 // add separate processing loop to advance while suppressed
45 // or, include jump offset to skip suppressed code?
46
47SkScriptRuntime::~SkScriptRuntime() {
48 for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
49 delete *stringPtr;
50 for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
51 delete *arrayPtr;
52}
53
54bool SkScriptRuntime::executeTokens(unsigned char* opCode) {
55 SkOperand2 operand[2]; // 1=accumulator and 2=operand
56 SkScriptEngine2::TypeOp op;
57 size_t ref;
58 int index, size;
59 int registerLoad;
60 SkScriptCallBack* callBack SK_INIT_TO_AVOID_WARNING;
61 do {
62 switch ((op = (SkScriptEngine2::TypeOp) *opCode++)) {
63 case SkScriptEngine2::kArrayToken: // create an array
64 operand[0].fArray = new SkOpArray(SkOperand2::kNoType /*fReturnType*/);
65 break;
66 case SkScriptEngine2::kArrayIndex: // array accessor
67 index = operand[1].fS32;
68 if (index >= operand[0].fArray->count()) {
69 fError = kArrayIndexOutOfBounds;
70 return false;
71 }
72 operand[0] = operand[0].fArray->begin()[index];
73 break;
74 case SkScriptEngine2::kArrayParam: // array initializer, or function param
75 *operand[0].fArray->append() = operand[1];
76 break;
77 case SkScriptEngine2::kCallback:
78 memcpy(&index, opCode, sizeof(index));
79 opCode += sizeof(index);
80 callBack = fCallBackArray[index];
81 break;
82 case SkScriptEngine2::kFunctionCall: {
83 memcpy(&ref, opCode, sizeof(ref));
84 opCode += sizeof(ref);
85 SkScriptCallBackFunction* callBackFunction = (SkScriptCallBackFunction*) callBack;
86 if (callBackFunction->invoke(ref, operand[0].fArray, /* params */
87 &operand[0] /* result */) == false) {
88 fError = kFunctionCallFailed;
89 return false;
90 }
91 } break;
92 case SkScriptEngine2::kMemberOp: {
93 memcpy(&ref, opCode, sizeof(ref));
94 opCode += sizeof(ref);
95 SkScriptCallBackMember* callBackMember = (SkScriptCallBackMember*) callBack;
96 if (callBackMember->invoke(ref, operand[0].fObject, &operand[0]) == false) {
97 fError = kMemberOpFailed;
98 return false;
99 }
100 } break;
101 case SkScriptEngine2::kPropertyOp: {
102 memcpy(&ref, opCode, sizeof(ref));
103 opCode += sizeof(ref);
104 SkScriptCallBackProperty* callBackProperty = (SkScriptCallBackProperty*) callBack;
105 if (callBackProperty->getResult(ref, &operand[0])== false) {
106 fError = kPropertyOpFailed;
107 return false;
108 }
109 } break;
110 case SkScriptEngine2::kAccumulatorPop:
111 fRunStack.pop(&operand[0]);
112 break;
113 case SkScriptEngine2::kAccumulatorPush:
114 *fRunStack.push() = operand[0];
115 break;
116 case SkScriptEngine2::kIntegerAccumulator:
117 case SkScriptEngine2::kIntegerOperand:
118 registerLoad = op - SkScriptEngine2::kIntegerAccumulator;
119 memcpy(&operand[registerLoad].fS32, opCode, sizeof(int32_t));
120 opCode += sizeof(int32_t);
121 break;
122 case SkScriptEngine2::kScalarAccumulator:
123 case SkScriptEngine2::kScalarOperand:
124 registerLoad = op - SkScriptEngine2::kScalarAccumulator;
125 memcpy(&operand[registerLoad].fScalar, opCode, sizeof(SkScalar));
126 opCode += sizeof(SkScalar);
127 break;
128 case SkScriptEngine2::kStringAccumulator:
129 case SkScriptEngine2::kStringOperand: {
130 SkString* strPtr = new SkString();
131 track(strPtr);
132 registerLoad = op - SkScriptEngine2::kStringAccumulator;
133 memcpy(&size, opCode, sizeof(size));
134 opCode += sizeof(size);
135 strPtr->set((char*) opCode, size);
136 opCode += size;
137 operand[registerLoad].fString = strPtr;
138 } break;
139 case SkScriptEngine2::kStringTrack: // call after kObjectToValue
140 track(operand[0].fString);
141 break;
142 case SkScriptEngine2::kBoxToken: {
143 SkOperand2::OpType type;
144 memcpy(&type, opCode, sizeof(type));
145 opCode += sizeof(type);
146 SkScriptCallBackConvert* callBackBox = (SkScriptCallBackConvert*) callBack;
147 if (callBackBox->convert(type, &operand[0]) == false)
148 return false;
149 } break;
150 case SkScriptEngine2::kUnboxToken:
151 case SkScriptEngine2::kUnboxToken2: {
152 SkScriptCallBackConvert* callBackUnbox = (SkScriptCallBackConvert*) callBack;
153 if (callBackUnbox->convert(SkOperand2::kObject, &operand[0]) == false)
154 return false;
155 } break;
156 case SkScriptEngine2::kIfOp:
157 case SkScriptEngine2::kLogicalAndInt:
158 memcpy(&size, opCode, sizeof(size));
159 opCode += sizeof(size);
160 if (operand[0].fS32 == 0)
161 opCode += size; // skip to else (or end of if predicate)
162 break;
163 case SkScriptEngine2::kElseOp:
164 memcpy(&size, opCode, sizeof(size));
165 opCode += sizeof(size);
166 opCode += size; // if true: after predicate, always skip to end of else
167 break;
168 case SkScriptEngine2::kLogicalOrInt:
169 memcpy(&size, opCode, sizeof(size));
170 opCode += sizeof(size);
171 if (operand[0].fS32 != 0)
172 opCode += size; // skip to kToBool opcode after || predicate
173 break;
174 // arithmetic conversion ops
175 case SkScriptEngine2::kFlipOpsOp:
176 SkTSwap(operand[0], operand[1]);
177 break;
178 case SkScriptEngine2::kIntToString:
179 case SkScriptEngine2::kIntToString2:
180 case SkScriptEngine2::kScalarToString:
181 case SkScriptEngine2::kScalarToString2:{
182 SkString* strPtr = new SkString();
183 track(strPtr);
184 if (op == SkScriptEngine2::kIntToString || op == SkScriptEngine2::kIntToString2)
185 strPtr->appendS32(operand[op - SkScriptEngine2::kIntToString].fS32);
186 else
187 strPtr->appendScalar(operand[op - SkScriptEngine2::kScalarToString].fScalar);
188 operand[0].fString = strPtr;
189 } break;
190 case SkScriptEngine2::kIntToScalar:
191 case SkScriptEngine2::kIntToScalar2:
192 operand[0].fScalar = SkScriptEngine2::IntToScalar(operand[op - SkScriptEngine2::kIntToScalar].fS32);
193 break;
194 case SkScriptEngine2::kStringToInt:
195 if (SkParse::FindS32(operand[0].fString->c_str(), &operand[0].fS32) == false)
196 return false;
197 break;
198 case SkScriptEngine2::kStringToScalar:
199 case SkScriptEngine2::kStringToScalar2:
200 if (SkParse::FindScalar(operand[0].fString->c_str(),
201 &operand[op - SkScriptEngine2::kStringToScalar].fScalar) == false)
202 return false;
203 break;
204 case SkScriptEngine2::kScalarToInt:
205 operand[0].fS32 = SkScalarFloor(operand[0].fScalar);
206 break;
207 // arithmetic ops
208 case SkScriptEngine2::kAddInt:
209 operand[0].fS32 += operand[1].fS32;
210 break;
211 case SkScriptEngine2::kAddScalar:
212 operand[0].fScalar += operand[1].fScalar;
213 break;
214 case SkScriptEngine2::kAddString:
215// if (fTrackString.find(operand[1].fString) < 0) {
216// operand[1].fString = SkNEW_ARGS(SkString, (*operand[1].fString));
217// track(operand[1].fString);
218// }
219 operand[0].fString->append(*operand[1].fString);
220 break;
221 case SkScriptEngine2::kBitAndInt:
222 operand[0].fS32 &= operand[1].fS32;
223 break;
224 case SkScriptEngine2::kBitNotInt:
225 operand[0].fS32 = ~operand[0].fS32;
226 break;
227 case SkScriptEngine2::kBitOrInt:
228 operand[0].fS32 |= operand[1].fS32;
229 break;
230 case SkScriptEngine2::kDivideInt:
231 SkASSERT(operand[1].fS32 != 0);
232 if (operand[1].fS32 == 0)
233 operand[0].fS32 = operand[0].fS32 == 0 ? SK_NaN32 :
234 operand[0].fS32 > 0 ? SK_MaxS32 : -SK_MaxS32;
235 else
236 if (operand[1].fS32 != 0) // throw error on divide by zero?
237 operand[0].fS32 /= operand[1].fS32;
238 break;
239 case SkScriptEngine2::kDivideScalar:
240 if (operand[1].fScalar == 0)
241 operand[0].fScalar = operand[0].fScalar == 0 ? SK_ScalarNaN :
242 operand[0].fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax;
243 else
244 operand[0].fScalar = SkScalarDiv(operand[0].fScalar, operand[1].fScalar);
245 break;
246 case SkScriptEngine2::kEqualInt:
247 operand[0].fS32 = operand[0].fS32 == operand[1].fS32;
248 break;
249 case SkScriptEngine2::kEqualScalar:
250 operand[0].fS32 = operand[0].fScalar == operand[1].fScalar;
251 break;
252 case SkScriptEngine2::kEqualString:
253 operand[0].fS32 = *operand[0].fString == *operand[1].fString;
254 break;
255 case SkScriptEngine2::kGreaterEqualInt:
256 operand[0].fS32 = operand[0].fS32 >= operand[1].fS32;
257 break;
258 case SkScriptEngine2::kGreaterEqualScalar:
259 operand[0].fS32 = operand[0].fScalar >= operand[1].fScalar;
260 break;
261 case SkScriptEngine2::kGreaterEqualString:
262 operand[0].fS32 = strcmp(operand[0].fString->c_str(), operand[1].fString->c_str()) >= 0;
263 break;
264 case SkScriptEngine2::kToBool:
265 operand[0].fS32 = !! operand[0].fS32;
266 break;
267 case SkScriptEngine2::kLogicalNotInt:
268 operand[0].fS32 = ! operand[0].fS32;
269 break;
270 case SkScriptEngine2::kMinusInt:
271 operand[0].fS32 = -operand[0].fS32;
272 break;
273 case SkScriptEngine2::kMinusScalar:
274 operand[0].fScalar = -operand[0].fScalar;
275 break;
276 case SkScriptEngine2::kModuloInt:
277 operand[0].fS32 %= operand[1].fS32;
278 break;
279 case SkScriptEngine2::kModuloScalar:
280 operand[0].fScalar = SkScalarMod(operand[0].fScalar, operand[1].fScalar);
281 break;
282 case SkScriptEngine2::kMultiplyInt:
283 operand[0].fS32 *= operand[1].fS32;
284 break;
285 case SkScriptEngine2::kMultiplyScalar:
286 operand[0].fScalar = SkScalarMul(operand[0].fScalar, operand[1].fScalar);
287 break;
288 case SkScriptEngine2::kShiftLeftInt:
289 operand[0].fS32 <<= operand[1].fS32;
290 break;
291 case SkScriptEngine2::kShiftRightInt:
292 operand[0].fS32 >>= operand[1].fS32;
293 break;
294 case SkScriptEngine2::kSubtractInt:
295 operand[0].fS32 -= operand[1].fS32;
296 break;
297 case SkScriptEngine2::kSubtractScalar:
298 operand[0].fScalar -= operand[1].fScalar;
299 break;
300 case SkScriptEngine2::kXorInt:
301 operand[0].fS32 ^= operand[1].fS32;
302 break;
303 case SkScriptEngine2::kEnd:
304 goto done;
305 case SkScriptEngine2::kNop:
306 SkASSERT(0);
307 }
308 } while (true);
309done:
310 fRunStack.push(operand[0]);
311 return true;
312}
313
314bool SkScriptRuntime::getResult(SkOperand2* result) {
315 if (fRunStack.count() == 0)
316 return false;
317 fRunStack.pop(result);
318 return true;
319}
320
321void SkScriptRuntime::track(SkOpArray* array) {
322 SkASSERT(fTrackArray.find(array) < 0);
323 *fTrackArray.append() = array;
324}
325
326void SkScriptRuntime::track(SkString* string) {
327 SkASSERT(fTrackString.find(string) < 0);
328 *fTrackString.append() = string;
329}
330
331void SkScriptRuntime::untrack(SkOpArray* array) {
332 int index = fTrackArray.find(array);
333 SkASSERT(index >= 0);
334 fTrackArray.begin()[index] = NULL;
335}
336
337void SkScriptRuntime::untrack(SkString* string) {
338 int index = fTrackString.find(string);
339 SkASSERT(index >= 0);
340 fTrackString.begin()[index] = NULL;
341}
342