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