epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 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 | */ |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 8 | #ifndef SkScript2_DEFINED |
| 9 | #define SkScript2_DEFINED |
| 10 | |
| 11 | #include "SkOperand2.h" |
| 12 | #include "SkStream.h" |
| 13 | #include "SkTDArray.h" |
| 14 | #include "SkTDArray_Experimental.h" |
| 15 | #include "SkTDict.h" |
| 16 | #include "SkTDStack.h" |
| 17 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 18 | typedef SkLongArray(SkString*) SkTDStringArray; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 19 | |
| 20 | class SkAnimateMaker; |
| 21 | class SkScriptCallBack; |
| 22 | |
| 23 | class SkScriptEngine2 { |
| 24 | public: |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 25 | enum Error { |
| 26 | kNoError, |
| 27 | kArrayIndexOutOfBounds, |
| 28 | kCouldNotFindReferencedID, |
| 29 | kFunctionCallFailed, |
| 30 | kMemberOpFailed, |
| 31 | kPropertyOpFailed |
| 32 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 33 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 34 | enum Attrs { |
| 35 | kConstant, |
| 36 | kVariable |
| 37 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 38 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 39 | SkScriptEngine2(SkOperand2::OpType returnType); |
| 40 | ~SkScriptEngine2(); |
| 41 | bool convertTo(SkOperand2::OpType , SkScriptValue2* ); |
| 42 | bool evaluateScript(const char** script, SkScriptValue2* value); |
| 43 | void forget(SkOpArray* array); |
| 44 | Error getError() { return fError; } |
| 45 | SkOperand2::OpType getReturnType() { return fReturnType; } |
| 46 | void track(SkOpArray* array) { |
| 47 | SkASSERT(fTrackArray.find(array) < 0); |
| 48 | *fTrackArray.append() = array; } |
| 49 | void track(SkString* string) { |
| 50 | SkASSERT(fTrackString.find(string) < 0); |
| 51 | *fTrackString.append() = string; |
| 52 | } |
| 53 | static bool ConvertTo(SkScriptEngine2* , SkOperand2::OpType toType, SkScriptValue2* value); |
| 54 | static SkScalar IntToScalar(int32_t ); |
| 55 | static bool ValueToString(const SkScriptValue2& value, SkString* string); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 56 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 57 | enum Op { // used by tokenizer attribute table |
| 58 | kUnassigned, |
| 59 | kAdd, |
| 60 | kBitAnd, |
| 61 | kBitNot, |
| 62 | kBitOr, |
| 63 | kDivide, |
| 64 | kEqual, |
| 65 | kFlipOps, |
| 66 | kGreaterEqual, |
| 67 | kLogicalAnd, |
| 68 | kLogicalNot, |
| 69 | kLogicalOr, |
| 70 | kMinus, |
| 71 | kModulo, |
| 72 | kMultiply, |
| 73 | kShiftLeft, |
| 74 | kShiftRight, // signed |
| 75 | kSubtract, |
| 76 | kXor, |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 77 | // following not in attribute table |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 78 | kArrayOp, |
| 79 | kElse, |
| 80 | kIf, |
| 81 | kParen, |
| 82 | kLastLogicalOp, |
| 83 | kArtificialOp = 0x20 |
| 84 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 85 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 86 | enum TypeOp { // generated by tokenizer |
| 87 | kNop, // should never get generated |
| 88 | kAccumulatorPop, |
| 89 | kAccumulatorPush, |
| 90 | kAddInt, |
| 91 | kAddScalar, |
| 92 | kAddString, // string concat |
| 93 | kArrayIndex, |
| 94 | kArrayParam, |
| 95 | kArrayToken, |
| 96 | kBitAndInt, |
| 97 | kBitNotInt, |
| 98 | kBitOrInt, |
| 99 | kBoxToken, |
| 100 | kCallback, |
| 101 | kDivideInt, |
| 102 | kDivideScalar, |
| 103 | kDotOperator, |
| 104 | kElseOp, |
| 105 | kEnd, |
| 106 | kEqualInt, |
| 107 | kEqualScalar, |
| 108 | kEqualString, |
| 109 | kFunctionCall, |
| 110 | kFlipOpsOp, |
| 111 | kFunctionToken, |
| 112 | kGreaterEqualInt, |
| 113 | kGreaterEqualScalar, |
| 114 | kGreaterEqualString, |
| 115 | kIfOp, |
| 116 | kIntToScalar, |
| 117 | kIntToScalar2, |
| 118 | kIntToString, |
| 119 | kIntToString2, |
| 120 | kIntegerAccumulator, |
| 121 | kIntegerOperand, |
| 122 | kLogicalAndInt, |
| 123 | kLogicalNotInt, |
| 124 | kLogicalOrInt, |
| 125 | kMemberOp, |
| 126 | kMinusInt, |
| 127 | kMinusScalar, |
| 128 | kModuloInt, |
| 129 | kModuloScalar, |
| 130 | kMultiplyInt, |
| 131 | kMultiplyScalar, |
| 132 | kPropertyOp, |
| 133 | kScalarAccumulator, |
| 134 | kScalarOperand, |
| 135 | kScalarToInt, |
| 136 | kScalarToInt2, |
| 137 | kScalarToString, |
| 138 | kScalarToString2, |
| 139 | kShiftLeftInt, |
| 140 | kShiftRightInt, // signed |
| 141 | kStringAccumulator, |
| 142 | kStringOperand, |
| 143 | kStringToInt, |
| 144 | kStringToScalar, |
| 145 | kStringToScalar2, |
| 146 | kStringTrack, |
| 147 | kSubtractInt, |
| 148 | kSubtractScalar, |
| 149 | kToBool, |
| 150 | kUnboxToken, |
| 151 | kUnboxToken2, |
| 152 | kXorInt, |
| 153 | kLastTypeOp |
| 154 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 155 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 156 | enum OpBias { |
| 157 | kNoBias, |
| 158 | kTowardsNumber = 0, |
| 159 | kTowardsString |
| 160 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 161 | |
| 162 | protected: |
| 163 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 164 | enum BraceStyle { |
| 165 | // kStructBrace, |
| 166 | kArrayBrace, |
| 167 | kFunctionBrace |
| 168 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 169 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 170 | enum AddTokenRegister { |
| 171 | kAccumulator, |
| 172 | kOperand |
| 173 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 174 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 175 | enum ResultIsBoolean { |
| 176 | kResultIsNotBoolean, |
| 177 | kResultIsBoolean |
| 178 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 179 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 180 | struct OperatorAttributes { |
| 181 | unsigned int fLeftType : 3; // SkOpType union, but only lower values |
| 182 | unsigned int fRightType : 3; // SkOpType union, but only lower values |
| 183 | OpBias fBias : 1; |
| 184 | ResultIsBoolean fResultIsBoolean : 1; |
| 185 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 186 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 187 | struct Branch { |
| 188 | Branch() { |
| 189 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 190 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 191 | Branch(Op op, int depth, unsigned offset) : fOffset(offset), fOpStackDepth(depth), fOperator(op), |
| 192 | fPrimed(kIsNotPrimed), fDone(kIsNotDone) { |
| 193 | } |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 194 | |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 195 | enum Primed { |
| 196 | kIsNotPrimed, |
| 197 | kIsPrimed |
| 198 | }; |
| 199 | |
| 200 | enum Done { |
| 201 | kIsNotDone, |
| 202 | kIsDone, |
| 203 | }; |
| 204 | |
| 205 | unsigned fOffset : 16; // offset in generated stream where branch needs to go |
| 206 | int fOpStackDepth : 7; // depth when operator was found |
| 207 | Op fOperator : 6; // operand which generated branch |
| 208 | mutable Primed fPrimed : 1; // mark when next instruction generates branch |
| 209 | Done fDone : 1; // mark when branch is complete |
| 210 | void prime() { fPrimed = kIsPrimed; } |
| 211 | void resolve(SkDynamicMemoryWStream* , size_t offset); |
| 212 | }; |
| 213 | |
| 214 | static const OperatorAttributes gOpAttributes[]; |
| 215 | static const signed char gPrecedence[]; |
| 216 | static const TypeOp gTokens[]; |
| 217 | void addToken(TypeOp ); |
| 218 | void addTokenConst(SkScriptValue2* , AddTokenRegister , SkOperand2::OpType , TypeOp ); |
| 219 | void addTokenInt(int ); |
| 220 | void addTokenScalar(SkScalar ); |
| 221 | void addTokenString(const SkString& ); |
| 222 | void addTokenValue(const SkScriptValue2& , AddTokenRegister ); |
| 223 | int arithmeticOp(char ch, char nextChar, bool lastPush); |
| 224 | bool convertParams(SkTDArray<SkScriptValue2>* , |
| 225 | const SkOperand2::OpType* paramTypes, int paramTypeCount); |
| 226 | void convertToString(SkOperand2* operand, SkOperand2::OpType type) { |
| 227 | SkScriptValue2 scriptValue; |
| 228 | scriptValue.fOperand = *operand; |
| 229 | scriptValue.fType = type; |
| 230 | convertTo(SkOperand2::kString, &scriptValue); |
| 231 | *operand = scriptValue.fOperand; |
| 232 | } |
| 233 | bool evaluateDot(const char*& script); |
| 234 | bool evaluateDotParam(const char*& script, const char* field, size_t fieldLength); |
| 235 | bool functionParams(const char** scriptPtr, SkTDArray<SkScriptValue2>* params); |
| 236 | size_t getTokenOffset(); |
| 237 | SkOperand2::OpType getUnboxType(SkOperand2 scriptValue); |
| 238 | bool handleArrayIndexer(const char** scriptPtr); |
| 239 | bool handleFunction(const char** scriptPtr); |
| 240 | bool handleMember(const char* field, size_t len, void* object); |
| 241 | bool handleMemberFunction(const char* field, size_t len, void* object, |
| 242 | SkTDArray<SkScriptValue2>* params); |
| 243 | bool handleProperty(); |
| 244 | bool handleUnbox(SkScriptValue2* scriptValue); |
| 245 | bool innerScript(const char** scriptPtr, SkScriptValue2* value); |
| 246 | int logicalOp(char ch, char nextChar); |
| 247 | void processLogicalOp(Op op); |
| 248 | bool processOp(); |
| 249 | void resolveBranch(Branch& ); |
| 250 | // void setAnimateMaker(SkAnimateMaker* maker) { fMaker = maker; } |
| 251 | SkDynamicMemoryWStream fStream; |
| 252 | SkDynamicMemoryWStream* fActiveStream; |
| 253 | SkTDStack<BraceStyle> fBraceStack; // curly, square, function paren |
| 254 | SkTDStack<Branch> fBranchStack; // logical operators, slot to store forward branch |
| 255 | SkLongArray(SkScriptCallBack*) fCallBackArray; |
| 256 | SkTDStack<Op> fOpStack; |
| 257 | SkTDStack<SkScriptValue2> fValueStack; |
| 258 | // SkAnimateMaker* fMaker; |
| 259 | SkLongArray(SkOpArray*) fTrackArray; |
| 260 | SkTDStringArray fTrackString; |
| 261 | const char* fToken; // one-deep stack |
| 262 | size_t fTokenLength; |
| 263 | SkOperand2::OpType fReturnType; |
| 264 | Error fError; |
| 265 | SkOperand2::OpType fAccumulatorType; // tracking for code generation |
| 266 | SkBool fBranchPopAllowed; |
| 267 | SkBool fConstExpression; |
| 268 | SkBool fOperandInUse; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 269 | private: |
| 270 | #ifdef SK_DEBUG |
| 271 | public: |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 272 | void decompile(const unsigned char* , size_t ); |
| 273 | static void UnitTest(); |
| 274 | static void ValidateDecompileTable(); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 275 | #endif |
| 276 | }; |
| 277 | |
| 278 | #ifdef SK_DEBUG |
| 279 | |
| 280 | struct SkScriptNAnswer2 { |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 281 | const char* fScript; |
| 282 | SkOperand2::OpType fType; |
| 283 | int32_t fIntAnswer; |
| 284 | SkScalar fScalarAnswer; |
| 285 | const char* fStringAnswer; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 286 | }; |
| 287 | |
| 288 | #endif |
| 289 | |
| 290 | |
| 291 | #endif // SkScript2_DEFINED |