| 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 |