1 /* 2 AngelCode Scripting Library 3 Copyright (c) 2003-2017 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 void SetAnonymousInitList(asCScriptNode *initList); 153 bool IsAnonymousInitList() const; 154 155 asCByteCode bc; 156 asCExprValue type; 157 int property_get; 158 int property_set; 159 bool property_const; // If the object that is being accessed through property accessor is read-only 160 bool property_handle; // If the property accessor is called on an object stored in a handle 161 bool property_ref; // If the property accessor is called on a reference 162 bool isVoidExpression; // Set to true if the expression is an explicit 'void', e.g. used to ignore out parameters in func calls 163 bool isCleanArg; // Set to true if the expression has only been initialized with default constructor 164 asCExprContext *property_arg; 165 asCArray<asSDeferredParam> deferredParams; 166 asCScriptNode *exprNode; 167 asCExprContext *origExpr; 168 // TODO: cleanup: use ambiguousName and an enum to say if it is a method, global func, or enum value 169 asCString methodName; 170 asCString enumValue; 171 bool isAnonymousInitList; // Set to true if the expression is an init list for which the type has not yet been determined 172 }; 173 174 struct asSOverloadCandidate 175 { asSOverloadCandidateasSOverloadCandidate176 asSOverloadCandidate() : funcId(0), cost(0) {} asSOverloadCandidateasSOverloadCandidate177 asSOverloadCandidate(int _id, asUINT _cost) : funcId(_id), cost(_cost) {} 178 int funcId; 179 asUINT cost; 180 }; 181 182 struct asSNamedArgument 183 { 184 asCString name; 185 asCExprContext *ctx; 186 asUINT match; 187 }; 188 189 enum EImplicitConv 190 { 191 asIC_IMPLICIT_CONV, 192 asIC_EXPLICIT_REF_CAST, 193 asIC_EXPLICIT_VAL_CAST 194 }; 195 196 enum EConvCost 197 { 198 asCC_NO_CONV = 0, 199 asCC_CONST_CONV = 1, 200 asCC_ENUM_SAME_SIZE_CONV = 2, 201 asCC_ENUM_DIFF_SIZE_CONV = 3, 202 asCC_PRIMITIVE_SIZE_CONV = 4, 203 asCC_SIGNED_CONV = 5, 204 asCC_INT_FLOAT_CONV = 6, 205 asCC_REF_CONV = 7, 206 asCC_OBJ_TO_PRIMITIVE_CONV = 8, 207 asCC_TO_OBJECT_CONV = 9, 208 asCC_VARIABLE_CONV = 10 209 }; 210 211 class asCCompiler 212 { 213 public: 214 asCCompiler(asCScriptEngine *engine); 215 ~asCCompiler(); 216 217 int CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray<asCString> ¶meterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl); 218 int CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl); 219 int CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc); 220 int CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *expr, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc); 221 222 protected: 223 friend class asCBuilder; 224 225 void Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc); 226 227 // Statements 228 void CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc); 229 void CompileDeclaration(asCScriptNode *decl, asCByteCode *bc); 230 void CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc); 231 void CompileIfStatement(asCScriptNode *node, bool *hasReturn, asCByteCode *bc); 232 void CompileSwitchStatement(asCScriptNode *node, bool *hasReturn, asCByteCode *bc); 233 void CompileCase(asCScriptNode *node, asCByteCode *bc); 234 void CompileForStatement(asCScriptNode *node, asCByteCode *bc); 235 void CompileWhileStatement(asCScriptNode *node, asCByteCode *bc); 236 void CompileDoWhileStatement(asCScriptNode *node, asCByteCode *bc); 237 void CompileBreakStatement(asCScriptNode *node, asCByteCode *bc); 238 void CompileContinueStatement(asCScriptNode *node, asCByteCode *bc); 239 void CompileReturnStatement(asCScriptNode *node, asCByteCode *bc); 240 void CompileExpressionStatement(asCScriptNode *node, asCByteCode *bc); 241 242 // Expressions 243 int CompileAssignment(asCScriptNode *expr, asCExprContext *out); 244 int CompileCondition(asCScriptNode *expr, asCExprContext *out); 245 int CompileExpression(asCScriptNode *expr, asCExprContext *out); 246 int CompilePostFixExpression(asCArray<asCScriptNode *> *postfix, asCExprContext *out); 247 int CompileExpressionTerm(asCScriptNode *node, asCExprContext *out); 248 int CompileExpressionPreOp(asCScriptNode *node, asCExprContext *out); 249 int CompileExpressionPostOp(asCScriptNode *node, asCExprContext *out); 250 int CompileExpressionValue(asCScriptNode *node, asCExprContext *out); 251 int CompileFunctionCall(asCScriptNode *node, asCExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = ""); 252 int CompileConstructCall(asCScriptNode *node, asCExprContext *out); 253 int CompileConversion(asCScriptNode *node, asCExprContext *out); 254 int CompileOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken, bool leftToRight = true); 255 void CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); 256 void CompileMathOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); 257 void CompileBitwiseOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); 258 void CompileComparisonOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); 259 void CompileBooleanOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); 260 bool CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool isHandle = false, eTokenType opToken = ttUnrecognizedToken); 261 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)); 262 263 void CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem); 264 int CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList); 265 int CompilerAnonymousInitList(asCScriptNode *listNode, asCExprContext *ctx, const asCDataType &dt); 266 267 int CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem = 0, bool derefDest = false); 268 int CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar = false, bool derefDestination = false); 269 void CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc); 270 int CompileArgumentList(asCScriptNode *node, asCArray<asCExprContext *> &args, asCArray<asSNamedArgument> &namedArgs); 271 int CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray<asCExprContext*> &args, int funcId, asCObjectType *type, asCArray<asSNamedArgument> *namedArgs = 0); 272 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 = ""); 273 int CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional = false, bool noFunction = false, bool noGlobal = false, asCObjectType *objType = 0); 274 void CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults); 275 bool CompileAutoType(asCDataType &autoType, asCExprContext &compiledCtx, asCScriptNode *exprNode, asCScriptNode *errNode); 276 bool CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled = 0); 277 void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination); 278 279 // Helper functions 280 void ConvertToPostFix(asCScriptNode *expr, asCArray<asCScriptNode *> &postfix); 281 void ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node); 282 int ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node); 283 int ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode); 284 int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); 285 int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); 286 void PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap = false); 287 void PrepareOperand(asCExprContext *ctx, asCScriptNode *node); 288 void PrepareForAssignment(asCDataType *lvalue, asCExprContext *rvalue, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr = 0); 289 int PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node); 290 bool IsVariableInitialized(asCExprValue *type, asCScriptNode *node); 291 void Dereference(asCExprContext *ctx, bool generateCode); 292 bool CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode = true); 293 asUINT MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCandidate> &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); 294 int MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); 295 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); 296 void MoveArgsToStack(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args, bool addOneToOffset); 297 void MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray<asCExprContext*> &args, asCScriptNode *node, bool useVariable = false, int stackOffset = 0, int funcPtrVar = 0); 298 void PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray<asCExprContext *> &args); 299 void AfterFunctionCall(int funcId, asCArray<asCExprContext*> &args, asCExprContext *ctx, bool deferAll); 300 void ProcessDeferredParams(asCExprContext *ctx); 301 int PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction = false, int refType = 0, bool isMakingCopy = false); 302 void PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction = false, int refType = 0, bool isMakingCopy = false); 303 bool IsLValue(asCExprValue &type); 304 int DoAssignment(asCExprContext *out, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode); 305 void MergeExprBytecode(asCExprContext *before, asCExprContext *after); 306 void MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after); 307 void FilterConst(asCArray<int> &funcs, bool removeConst = true); 308 void ConvertToVariable(asCExprContext *ctx); 309 void ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); 310 void ConvertToTempVariable(asCExprContext *ctx); 311 void ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); 312 void ConvertToReference(asCExprContext *ctx); 313 void PushVariableOnStack(asCExprContext *ctx, bool asReference); 314 void DestroyVariables(asCByteCode *bc); 315 asSNameSpace *DetermineNameSpace(const asCString &scope); 316 int SetupParametersAndReturnVariable(asCArray<asCString> ¶meterNames, asCScriptNode *func); 317 318 void DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node); 319 320 // Returns the cost of the conversion (the sum of the EConvCost performed) 321 asUINT ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); 322 asUINT ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); 323 asUINT ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); 324 asUINT ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); 325 asUINT ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); 326 asUINT ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); 327 asUINT ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); 328 void ImplicitConversionConstant(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType); 329 void ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node); 330 asUINT ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); 331 332 void LineInstr(asCByteCode *bc, size_t pos); 333 334 asUINT ProcessStringConstant(asCString &str, asCScriptNode *node, bool processEscapeSequences = true); 335 void ProcessHeredocStringConstant(asCString &str, asCScriptNode *node); 336 int GetPrecedence(asCScriptNode *op); 337 void Error(const asCString &msg, asCScriptNode *node); 338 void Warning(const asCString &msg, asCScriptNode *node); 339 void Information(const asCString &msg, asCScriptNode *node); 340 void PrintMatchingFuncs(asCArray<int> &funcs, asCScriptNode *node, asCObjectType *inType = 0); 341 void AddVariableScope(bool isBreakScope = false, bool isContinueScope = false); 342 void RemoveVariableScope(); 343 void FinalizeFunction(); 344 345 asCByteCode byteCode; 346 347 bool hasCompileErrors; 348 349 int nextLabel; 350 int numLambdas; 351 352 asCVariableScope *variables; 353 asCBuilder *builder; 354 asCScriptEngine *engine; 355 asCScriptCode *script; 356 asCScriptFunction *outFunc; 357 358 bool m_isConstructor; 359 bool m_isConstructorCalled; 360 sClassDeclaration *m_classDecl; 361 sGlobalVariableDescription *m_globalVar; 362 363 asCArray<int> breakLabels; 364 asCArray<int> continueLabels; 365 366 int AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap = false); 367 int AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx); 368 int GetVariableOffset(int varIndex); 369 int GetVariableSlot(int varOffset); 370 void DeallocateVariable(int pos); 371 void ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc); 372 void ReleaseTemporaryVariable(int offset, asCByteCode *bc); 373 bool IsVariableOnHeap(int offset); 374 375 // This ordered array indicates the type of each variable 376 asCArray<asCDataType> variableAllocations; 377 378 // This ordered array indicates which variables are temporaries or not 379 asCArray<bool> variableIsTemporary; 380 381 // This unordered array gives the offsets of all temporary variables, whether currently allocated or not 382 asCArray<int> tempVariableOffsets; 383 384 // This ordered array indicated if the variable is on the heap or not 385 asCArray<bool> variableIsOnHeap; 386 387 // This unordered array gives the indexes of the currently unused variables 388 asCArray<int> freeVariables; 389 390 // This array holds the offsets of the currently allocated temporary variables 391 asCArray<int> tempVariables; 392 393 // This array holds the indices of variables that must not be used in an allocation 394 asCArray<int> reservedVariables; 395 396 // This array holds the string constants that were allocated during the compilation, 397 // so they can be released upon completion, whether the compilation was successful or not. 398 asCArray<void*> usedStringConstants; 399 400 bool isCompilingDefaultArg; 401 bool isProcessingDeferredParams; 402 int noCodeOutput; 403 }; 404 405 END_AS_NAMESPACE 406 407 #endif // AS_NO_COMPILER 408 409 #endif 410