|  |  | 
|  | /* | 
|  | * Copyright 2011 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  | #ifndef SkScript2_DEFINED | 
|  | #define SkScript2_DEFINED | 
|  |  | 
|  | #include "SkOperand2.h" | 
|  | #include "SkStream.h" | 
|  | #include "SkTDArray.h" | 
|  | #include "SkTDArray_Experimental.h" | 
|  | #include "SkTDict.h" | 
|  | #include "SkTDStack.h" | 
|  |  | 
|  | typedef SkLongArray(SkString*) SkTDStringArray; | 
|  |  | 
|  | class SkAnimateMaker; | 
|  | class SkScriptCallBack; | 
|  |  | 
|  | class SkScriptEngine2 { | 
|  | public: | 
|  | enum Error { | 
|  | kNoError, | 
|  | kArrayIndexOutOfBounds, | 
|  | kCouldNotFindReferencedID, | 
|  | kFunctionCallFailed, | 
|  | kMemberOpFailed, | 
|  | kPropertyOpFailed | 
|  | }; | 
|  |  | 
|  | enum Attrs { | 
|  | kConstant, | 
|  | kVariable | 
|  | }; | 
|  |  | 
|  | SkScriptEngine2(SkOperand2::OpType returnType); | 
|  | ~SkScriptEngine2(); | 
|  | bool convertTo(SkOperand2::OpType , SkScriptValue2* ); | 
|  | bool evaluateScript(const char** script, SkScriptValue2* value); | 
|  | void forget(SkOpArray* array); | 
|  | Error getError() { return fError; } | 
|  | SkOperand2::OpType getReturnType() { return fReturnType; } | 
|  | void track(SkOpArray* array) { | 
|  | SkASSERT(fTrackArray.find(array) < 0); | 
|  | *fTrackArray.append() = array; } | 
|  | void track(SkString* string) { | 
|  | SkASSERT(fTrackString.find(string) < 0); | 
|  | *fTrackString.append() = string; | 
|  | } | 
|  | static bool ConvertTo(SkScriptEngine2* , SkOperand2::OpType toType, SkScriptValue2* value); | 
|  | static SkScalar IntToScalar(int32_t ); | 
|  | static bool ValueToString(const SkScriptValue2& value, SkString* string); | 
|  |  | 
|  | enum Op {        // used by tokenizer attribute table | 
|  | kUnassigned, | 
|  | kAdd, | 
|  | kBitAnd, | 
|  | kBitNot, | 
|  | kBitOr, | 
|  | kDivide, | 
|  | kEqual, | 
|  | kFlipOps, | 
|  | kGreaterEqual, | 
|  | kLogicalAnd, | 
|  | kLogicalNot, | 
|  | kLogicalOr, | 
|  | kMinus, | 
|  | kModulo, | 
|  | kMultiply, | 
|  | kShiftLeft, | 
|  | kShiftRight,    // signed | 
|  | kSubtract, | 
|  | kXor, | 
|  | // following not in attribute table | 
|  | kArrayOp, | 
|  | kElse, | 
|  | kIf, | 
|  | kParen, | 
|  | kLastLogicalOp, | 
|  | kArtificialOp = 0x20 | 
|  | }; | 
|  |  | 
|  | enum TypeOp {    // generated by tokenizer | 
|  | kNop, // should never get generated | 
|  | kAccumulatorPop, | 
|  | kAccumulatorPush, | 
|  | kAddInt, | 
|  | kAddScalar, | 
|  | kAddString,    // string concat | 
|  | kArrayIndex, | 
|  | kArrayParam, | 
|  | kArrayToken, | 
|  | kBitAndInt, | 
|  | kBitNotInt, | 
|  | kBitOrInt, | 
|  | kBoxToken, | 
|  | kCallback, | 
|  | kDivideInt, | 
|  | kDivideScalar, | 
|  | kDotOperator, | 
|  | kElseOp, | 
|  | kEnd, | 
|  | kEqualInt, | 
|  | kEqualScalar, | 
|  | kEqualString, | 
|  | kFunctionCall, | 
|  | kFlipOpsOp, | 
|  | kFunctionToken, | 
|  | kGreaterEqualInt, | 
|  | kGreaterEqualScalar, | 
|  | kGreaterEqualString, | 
|  | kIfOp, | 
|  | kIntToScalar, | 
|  | kIntToScalar2, | 
|  | kIntToString, | 
|  | kIntToString2, | 
|  | kIntegerAccumulator, | 
|  | kIntegerOperand, | 
|  | kLogicalAndInt, | 
|  | kLogicalNotInt, | 
|  | kLogicalOrInt, | 
|  | kMemberOp, | 
|  | kMinusInt, | 
|  | kMinusScalar, | 
|  | kModuloInt, | 
|  | kModuloScalar, | 
|  | kMultiplyInt, | 
|  | kMultiplyScalar, | 
|  | kPropertyOp, | 
|  | kScalarAccumulator, | 
|  | kScalarOperand, | 
|  | kScalarToInt, | 
|  | kScalarToInt2, | 
|  | kScalarToString, | 
|  | kScalarToString2, | 
|  | kShiftLeftInt, | 
|  | kShiftRightInt,    // signed | 
|  | kStringAccumulator, | 
|  | kStringOperand, | 
|  | kStringToInt, | 
|  | kStringToScalar, | 
|  | kStringToScalar2, | 
|  | kStringTrack, | 
|  | kSubtractInt, | 
|  | kSubtractScalar, | 
|  | kToBool, | 
|  | kUnboxToken, | 
|  | kUnboxToken2, | 
|  | kXorInt, | 
|  | kLastTypeOp | 
|  | }; | 
|  |  | 
|  | enum OpBias { | 
|  | kNoBias, | 
|  | kTowardsNumber = 0, | 
|  | kTowardsString | 
|  | }; | 
|  |  | 
|  | protected: | 
|  |  | 
|  | enum BraceStyle { | 
|  | //    kStructBrace, | 
|  | kArrayBrace, | 
|  | kFunctionBrace | 
|  | }; | 
|  |  | 
|  | enum AddTokenRegister { | 
|  | kAccumulator, | 
|  | kOperand | 
|  | }; | 
|  |  | 
|  | enum ResultIsBoolean { | 
|  | kResultIsNotBoolean, | 
|  | kResultIsBoolean | 
|  | }; | 
|  |  | 
|  | struct OperatorAttributes { | 
|  | unsigned int fLeftType : 3;    // SkOpType union, but only lower values | 
|  | unsigned int fRightType : 3;     // SkOpType union, but only lower values | 
|  | OpBias fBias : 1; | 
|  | ResultIsBoolean fResultIsBoolean : 1; | 
|  | }; | 
|  |  | 
|  | struct Branch { | 
|  | Branch() { | 
|  | } | 
|  |  | 
|  | Branch(Op op, int depth, size_t offset) | 
|  | : fOffset(SkToU16(offset)), fOpStackDepth(depth), fOperator(op) | 
|  | , fPrimed(kIsNotPrimed), fDone(kIsNotDone) { | 
|  | } | 
|  |  | 
|  | enum Primed { | 
|  | kIsNotPrimed, | 
|  | kIsPrimed | 
|  | }; | 
|  |  | 
|  | enum Done { | 
|  | kIsNotDone, | 
|  | kIsDone, | 
|  | }; | 
|  |  | 
|  | unsigned fOffset : 16; // offset in generated stream where branch needs to go | 
|  | int fOpStackDepth : 7; // depth when operator was found | 
|  | Op fOperator : 6; // operand which generated branch | 
|  | mutable Primed fPrimed : 1;    // mark when next instruction generates branch | 
|  | Done fDone : 1;    // mark when branch is complete | 
|  | void prime() { fPrimed = kIsPrimed; } | 
|  | void resolve(SkDynamicMemoryWStream* , size_t offset); | 
|  | }; | 
|  |  | 
|  | static const OperatorAttributes gOpAttributes[]; | 
|  | static const signed char gPrecedence[]; | 
|  | static const TypeOp gTokens[]; | 
|  | void addToken(TypeOp ); | 
|  | void addTokenConst(SkScriptValue2* , AddTokenRegister , SkOperand2::OpType , TypeOp ); | 
|  | void addTokenInt(int ); | 
|  | void addTokenScalar(SkScalar ); | 
|  | void addTokenString(const SkString& ); | 
|  | void addTokenValue(const SkScriptValue2& , AddTokenRegister ); | 
|  | int arithmeticOp(char ch, char nextChar, bool lastPush); | 
|  | bool convertParams(SkTDArray<SkScriptValue2>* , | 
|  | const SkOperand2::OpType* paramTypes, int paramTypeCount); | 
|  | void convertToString(SkOperand2* operand, SkOperand2::OpType type) { | 
|  | SkScriptValue2 scriptValue; | 
|  | scriptValue.fOperand = *operand; | 
|  | scriptValue.fType = type; | 
|  | convertTo(SkOperand2::kString, &scriptValue); | 
|  | *operand = scriptValue.fOperand; | 
|  | } | 
|  | bool evaluateDot(const char*& script); | 
|  | bool evaluateDotParam(const char*& script, const char* field, size_t fieldLength); | 
|  | bool functionParams(const char** scriptPtr, SkTDArray<SkScriptValue2>* params); | 
|  | size_t getTokenOffset(); | 
|  | SkOperand2::OpType getUnboxType(SkOperand2 scriptValue); | 
|  | bool handleArrayIndexer(const char** scriptPtr); | 
|  | bool handleFunction(const char** scriptPtr); | 
|  | bool handleMember(const char* field, size_t len, void* object); | 
|  | bool handleMemberFunction(const char* field, size_t len, void* object, | 
|  | SkTDArray<SkScriptValue2>* params); | 
|  | bool handleProperty(); | 
|  | bool handleUnbox(SkScriptValue2* scriptValue); | 
|  | bool innerScript(const char** scriptPtr, SkScriptValue2* value); | 
|  | int logicalOp(char ch, char nextChar); | 
|  | void processLogicalOp(Op op); | 
|  | bool processOp(); | 
|  | void resolveBranch(Branch& ); | 
|  | //    void setAnimateMaker(SkAnimateMaker* maker) { fMaker = maker; } | 
|  | SkDynamicMemoryWStream fStream; | 
|  | SkDynamicMemoryWStream* fActiveStream; | 
|  | SkTDStack<BraceStyle> fBraceStack;        // curly, square, function paren | 
|  | SkTDStack<Branch> fBranchStack;  // logical operators, slot to store forward branch | 
|  | SkLongArray(SkScriptCallBack*) fCallBackArray; | 
|  | SkTDStack<Op> fOpStack; | 
|  | SkTDStack<SkScriptValue2> fValueStack; | 
|  | //    SkAnimateMaker* fMaker; | 
|  | SkLongArray(SkOpArray*) fTrackArray; | 
|  | SkTDStringArray fTrackString; | 
|  | const char* fToken; // one-deep stack | 
|  | size_t fTokenLength; | 
|  | SkOperand2::OpType fReturnType; | 
|  | Error fError; | 
|  | SkOperand2::OpType fAccumulatorType;    // tracking for code generation | 
|  | SkBool fBranchPopAllowed; | 
|  | SkBool fConstExpression; | 
|  | SkBool fOperandInUse; | 
|  | private: | 
|  | #ifdef SK_DEBUG | 
|  | public: | 
|  | void decompile(const unsigned char* , size_t ); | 
|  | static void UnitTest(); | 
|  | static void ValidateDecompileTable(); | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | #ifdef SK_DEBUG | 
|  |  | 
|  | struct SkScriptNAnswer2 { | 
|  | const char* fScript; | 
|  | SkOperand2::OpType fType; | 
|  | int32_t fIntAnswer; | 
|  | SkScalar fScalarAnswer; | 
|  | const char* fStringAnswer; | 
|  | }; | 
|  |  | 
|  | #endif | 
|  |  | 
|  |  | 
|  | #endif // SkScript2_DEFINED |