1 /* 2 AngelCode Scripting Library 3 Copyright (c) 2003-2016 Andreas Jonsson 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any 7 damages arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any 10 purpose, including commercial applications, and to alter it and 11 redistribute it freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you 14 must not claim that you wrote the original software. If you use 15 this software in a product, an acknowledgment in the product 16 documentation would be appreciated but is not required. 17 18 2. Altered source versions must be plainly marked as such, and 19 must not be misrepresented as being the original software. 20 21 3. This notice may not be removed or altered from any source 22 distribution. 23 24 The original version of this library can be located at: 25 http://www.angelcode.com/angelscript/ 26 27 Andreas Jonsson 28 andreas@angelcode.com 29 */ 30 31 32 // 33 // as_compiler.h 34 // 35 // The class that does the actual compilation of the functions 36 // 37 38 39 40 #ifndef AS_COMPILER_H 41 #define AS_COMPILER_H 42 43 #include "as_config.h" 44 45 #ifndef AS_NO_COMPILER 46 47 #include "as_builder.h" 48 #include "as_scriptfunction.h" 49 #include "as_variablescope.h" 50 #include "as_bytecode.h" 51 #include "as_array.h" 52 #include "as_datatype.h" 53 54 BEGIN_AS_NAMESPACE 55 56 // This class represents the value of an expression as evaluated by the compiler. 57 // It holds information such as the type of the value, stack offset for a local 58 // variable, value of constants, whether the value can be modified (i.e. lvalue), etc. 59 struct asCExprValue 60 { 61 asCExprValue(); 62 void Set(const asCDataType &dataType); 63 64 void SetVariable(const asCDataType &dataType, int stackOffset, bool isTemporary); 65 void SetConstantB(const asCDataType &dataType, asBYTE value); 66 void SetConstantQW(const asCDataType &dataType, asQWORD value); 67 void SetConstantDW(const asCDataType &dataType, asDWORD value); 68 void SetConstantW(const asCDataType &dataType, asWORD value); 69 void SetConstantF(const asCDataType &dataType, float value); 70 void SetConstantD(const asCDataType &dataType, double value); 71 void SetConstantB(asBYTE value); 72 void SetConstantW(asWORD value); 73 void SetConstantQW(asQWORD value); 74 void SetConstantDW(asDWORD value); 75 void SetConstantF(float value); 76 void SetConstantD(double value); 77 asBYTE GetConstantB(); 78 asWORD GetConstantW(); 79 asQWORD GetConstantQW(); 80 asDWORD GetConstantDW(); 81 float GetConstantF(); 82 double GetConstantD(); 83 84 void SetConstantData(const asCDataType &dataType, asQWORD value); 85 asQWORD GetConstantData(); 86 87 void SetNullConstant(); 88 void SetUndefinedFuncHandle(asCScriptEngine *engine); 89 void SetVoid(); 90 void SetDummy(); 91 92 bool IsUndefinedFuncHandle() const; 93 bool IsNullConstant() const; 94 bool IsVoid() const; 95 96 asCDataType dataType; 97 bool isLValue : 1; // Can this value be updated in assignment, or increment operators, etc 98 bool isTemporary : 1; 99 bool isConstant : 1; 100 bool isVariable : 1; 101 bool isExplicitHandle : 1; 102 bool isRefToLocal : 1; // The reference may be to a local variable 103 bool isHandleSafe : 1; // the life-time of the handle is guaranteed for the duration of the access 104 short dummy : 9; 105 short stackOffset; 106 107 private: 108 // These values must not be accessed directly in order to avoid problems with endianess. 109 // Use the appropriate accessor methods instead 110 union 111 { 112 asQWORD qwordValue; 113 double doubleValue; 114 asDWORD dwordValue; 115 float floatValue; 116 asWORD wordValue; 117 asBYTE byteValue; 118 }; 119 }; 120 121 struct asCExprContext; 122 123 // This class holds information for arguments that needs to be 124 // cleaned up after the result of a function has been evaluated. 125 struct asSDeferredParam 126 { asSDeferredParamasSDeferredParam127 asSDeferredParam() {argNode = 0; origExpr = 0;} 128 129 asCScriptNode *argNode; 130 asCExprValue argType; 131 int argInOutFlags; 132 asCExprContext *origExpr; 133 }; 134 135 // TODO: refactor: asCExprContext should have indicators to inform where the value is, 136 // i.e. if the reference to an object is pushed on the stack or not, etc 137 138 // This class holds information about an expression that is being evaluated, e.g. 139 // the current bytecode, ambiguous symbol names, property accessors, etc. 140 struct asCExprContext 141 { 142 asCExprContext(asCScriptEngine *engine); 143 ~asCExprContext(); 144 void Clear(); 145 bool IsClassMethod() const; 146 bool IsGlobalFunc() const; 147 void SetLambda(asCScriptNode *funcDecl); 148 bool IsLambda() const; 149 void SetVoidExpression(); 150 bool IsVoidExpression() const; 151 void Merge(asCExprContext *after); 152 153 asCByteCode bc; 154 asCExprValue type; 155 int property_get; 156 int property_set; 157 bool property_const; // If the object that is being accessed through property accessor is read-only 158 bool property_handle; // If the property accessor is called on an object stored in a handle 159 bool property_ref; // If the property accessor is called on a reference 160 bool isVoidExpression; // Set to true if the expression is an explicit 'void', e.g. used to ignore out parameters in func calls 161 bool isCleanArg; // Set to true if the expression has only been initialized with default constructor 162 asCExprContext *property_arg; 163 asCArray<asSDeferredParam> deferredParams; 164 asCScriptNode *exprNode; 165 asCExprContext *origExpr; 166 // TODO: cleanup: use ambiguousName and an enum to say if it is a method, global func, or enum value 167 asCString methodName; 168 asCString enumValue; 169 }; 170 171 struct asSOverloadCandidate 172 { asSOverloadCandidateasSOverloadCandidate173 asSOverloadCandidate() : funcId(0), cost(0) {} asSOverloadCandidateasSOverloadCandidate174 asSOverloadCandidate(int _id, asUINT _cost) : funcId(_id), cost(_cost) {} 175 int funcId; 176 asUINT cost; 177 }; 178 179 struct asSNamedArgument 180 { 181 asCString name; 182 asCExprContext *ctx; 183 asUINT match; 184 }; 185 186 enum EImplicitConv 187 { 188 asIC_IMPLICIT_CONV, 189 asIC_EXPLICIT_REF_CAST, 190 asIC_EXPLICIT_VAL_CAST 191 }; 192 193 enum EConvCost 194 { 195 asCC_NO_CONV = 0, 196 asCC_CONST_CONV = 1, 197 asCC_ENUM_SAME_SIZE_CONV = 2, 198 asCC_ENUM_DIFF_SIZE_CONV = 3, 199 asCC_PRIMITIVE_SIZE_CONV = 4, 200 asCC_SIGNED_CONV = 5, 201 asCC_INT_FLOAT_CONV = 6, 202 asCC_REF_CONV = 7, 203 asCC_OBJ_TO_PRIMITIVE_CONV = 8, 204 asCC_TO_OBJECT_CONV = 9, 205 asCC_VARIABLE_CONV = 10 206 }; 207 208 class asCCompiler 209 { 210 public: 211 asCCompiler(asCScriptEngine *engine); 212 ~asCCompiler(); 213 214 int CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray<asCString> ¶meterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl); 215 int CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl); 216 int CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc); 217 int CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *expr, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc); 218 219 protected: 220 friend class asCBuilder; 221 222 void Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc); 223 224 // Statements 225 void CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc); 226 void CompileDeclaration(asCScriptNode *decl, asCByteCode *bc); 227 void CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc); 228 void CompileIfStatement(asCScriptNode *node, bool *hasReturn, asCByteCode *bc); 229 void CompileSwitchStatement(asCScriptNode *node, bool *hasReturn, asCByteCode *bc); 230 void CompileCase(asCScriptNode *node, asCByteCode *bc); 231 void CompileForStatement(asCScriptNode *node, asCByteCode *bc); 232 void CompileWhileStatement(asCScriptNode *node, asCByteCode *bc); 233 void CompileDoWhileStatement(asCScriptNode *node, asCByteCode *bc); 234 void CompileBreakStatement(asCScriptNode *node, asCByteCode *bc); 235 void CompileContinueStatement(asCScriptNode *node, asCByteCode *bc); 236 void CompileReturnStatement(asCScriptNode *node, asCByteCode *bc); 237 void CompileExpressionStatement(asCScriptNode *node, asCByteCode *bc); 238 239 // Expressions 240 int CompileAssignment(asCScriptNode *expr, asCExprContext *out); 241 int CompileCondition(asCScriptNode *expr, asCExprContext *out); 242 int CompileExpression(asCScriptNode *expr, asCExprContext *out); 243 int CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asCExprContext *out); 244 int CompileExpressionTerm(asCScriptNode *node, asCExprContext *out); 245 int CompileExpressionPreOp(asCScriptNode *node, asCExprContext *out); 246 int CompileExpressionPostOp(asCScriptNode *node, asCExprContext *out); 247 int CompileExpressionValue(asCScriptNode *node, asCExprContext *out); 248 int CompileFunctionCall(asCScriptNode *node, asCExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = ""); 249 int CompileConstructCall(asCScriptNode *node, asCExprContext *out); 250 int CompileConversion(asCScriptNode *node, asCExprContext *out); 251 int CompileOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken, bool leftToRight = true); 252 void CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); 253 void CompileMathOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); 254 void CompileBitwiseOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); 255 void CompileComparisonOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); 256 void CompileBooleanOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); 257 bool CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool isHandle = false, eTokenType opToken = ttUnrecognizedToken); 258 int CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool specificReturn = false, const asCDataType &returnType = asCDataType::CreatePrimitive(ttVoid, false)); 259 260 void CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem); 261 int CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList); 262 263 int CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem = 0, bool derefDest = false); 264 int CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar = false, bool derefDestination = false); 265 void CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc); 266 int CompileArgumentList(asCScriptNode *node, asCArray<asCExprContext *> &args, asCArray<asSNamedArgument> &namedArgs); 267 int CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asCExprContext*> &args, int funcId, asCObjectType *type, asCArray<asSNamedArgument> *namedArgs = 0); 268 asUINT MatchFunctions(asCArray<int> &funcs, asCArray<asCExprContext*> &args, asCScriptNode *node, const char *name, asCArray<asSNamedArgument> *namedArgs = NULL, asCObjectType *objectType = NULL, bool isConstMethod = false, bool silent = false, bool allowObjectConstruct = true, const asCString &scope = ""); 269 int CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional = false, bool noFunction = false, bool noGlobal = false, asCObjectType *objType = 0); 270 void CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults); 271 bool CompileAutoType(asCDataType &autoType, asCExprContext &compiledCtx, asCScriptNode *exprNode, asCScriptNode *errNode); 272 bool CompileInitialization(asCScriptNode *node, asCByteCode *bc, asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled = 0); 273 void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination); 274 275 // Helper functions 276 void ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix); 277 void ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node); 278 int ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node); 279 int ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode); 280 int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); 281 int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); 282 void PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap = false); 283 void PrepareOperand(asCExprContext *ctx, asCScriptNode *node); 284 void PrepareForAssignment(asCDataType *lvalue, asCExprContext *rvalue, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr = 0); 285 int PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node); 286 bool IsVariableInitialized(asCExprValue *type, asCScriptNode *node); 287 void Dereference(asCExprContext *ctx, bool generateCode); 288 bool CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode = true); 289 asUINT MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); 290 int MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); 291 void PerformFunctionCall(int funcId, asCExprContext *out, bool isConstructor = false, asCArray<asCExprContext*> *args = 0, asCObjectType *objTypeForConstruct = 0, bool useVariable = false, int varOffset = 0, int funcPtrVar = 0); 292 void MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args, bool addOneToOffset); 293 void MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asCExprContext*> &args, asCScriptNode *node, bool useVariable = false, int stackOffset = 0, int funcPtrVar = 0); 294 void PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args); 295 void AfterFunctionCall(int funcId, asCArray<asCExprContext*> &args, asCExprContext *ctx, bool deferAll); 296 void ProcessDeferredParams(asCExprContext *ctx); 297 int PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction = false, int refType = 0, bool isMakingCopy = false); 298 void PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction = false, int refType = 0, bool isMakingCopy = false); 299 bool IsLValue(asCExprValue &type); 300 int DoAssignment(asCExprContext *out, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode); 301 void MergeExprBytecode(asCExprContext *before, asCExprContext *after); 302 void MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after); 303 void FilterConst(asCArray<int> &funcs, bool removeConst = true); 304 void ConvertToVariable(asCExprContext *ctx); 305 void ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); 306 void ConvertToTempVariable(asCExprContext *ctx); 307 void ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); 308 void ConvertToReference(asCExprContext *ctx); 309 void PushVariableOnStack(asCExprContext *ctx, bool asReference); 310 void DestroyVariables(asCByteCode *bc); 311 asSNameSpace *DetermineNameSpace(const asCString &scope); 312 int SetupParametersAndReturnVariable(asCArray<asCString> ¶meterNames, asCScriptNode *func); 313 314 void DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node); 315 316 // Returns the cost of the conversion (the sum of the EConvCost performed) 317 asUINT ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); 318 asUINT ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); 319 asUINT ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); 320 asUINT ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); 321 asUINT ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); 322 asUINT ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); 323 asUINT ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); 324 void ImplicitConversionConstant(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType); 325 void ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node); 326 asUINT ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); 327 328 void LineInstr(asCByteCode *bc, size_t pos); 329 330 asUINT ProcessStringConstant(asCString &str, asCScriptNode *node, bool processEscapeSequences = true); 331 void ProcessHeredocStringConstant(asCString &str, asCScriptNode *node); 332 int GetPrecedence(asCScriptNode *op); 333 void Error(const asCString &msg, asCScriptNode *node); 334 void Warning(const asCString &msg, asCScriptNode *node); 335 void Information(const asCString &msg, asCScriptNode *node); 336 void PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node, asCObjectType *inType = 0); 337 void AddVariableScope(bool isBreakScope = false, bool isContinueScope = false); 338 void RemoveVariableScope(); 339 void FinalizeFunction(); 340 341 asCByteCode byteCode; 342 343 bool hasCompileErrors; 344 345 int nextLabel; 346 int numLambdas; 347 348 asCVariableScope *variables; 349 asCBuilder *builder; 350 asCScriptEngine *engine; 351 asCScriptCode *script; 352 asCScriptFunction *outFunc; 353 354 bool m_isConstructor; 355 bool m_isConstructorCalled; 356 sClassDeclaration *m_classDecl; 357 sGlobalVariableDescription *m_globalVar; 358 359 asCArray<int> breakLabels; 360 asCArray<int> continueLabels; 361 362 int AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap = false); 363 int AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx); 364 int GetVariableOffset(int varIndex); 365 int GetVariableSlot(int varOffset); 366 void DeallocateVariable(int pos); 367 void ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc); 368 void ReleaseTemporaryVariable(int offset, asCByteCode *bc); 369 bool IsVariableOnHeap(int offset); 370 371 // This ordered array indicates the type of each variable 372 asCArray<asCDataType> variableAllocations; 373 374 // This ordered array indicates which variables are temporaries or not 375 asCArray<bool> variableIsTemporary; 376 377 // This unordered array gives the offsets of all temporary variables, whether currently allocated or not 378 asCArray<int> tempVariableOffsets; 379 380 // This ordered array indicated if the variable is on the heap or not 381 asCArray<bool> variableIsOnHeap; 382 383 // This unordered array gives the indexes of the currently unused variables 384 asCArray<int> freeVariables; 385 386 // This array holds the offsets of the currently allocated temporary variables 387 asCArray<int> tempVariables; 388 389 // This array holds the indices of variables that must not be used in an allocation 390 asCArray<int> reservedVariables; 391 392 bool isCompilingDefaultArg; 393 bool isProcessingDeferredParams; 394 int noCodeOutput; 395 }; 396 397 END_AS_NAMESPACE 398 399 #endif // AS_NO_COMPILER 400 401 #endif 402