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> &parameterNames, 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> &parameterNames, 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