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