|
@@ -1,6 +1,6 @@
|
|
|
/*
|
|
/*
|
|
|
AngelCode Scripting Library
|
|
AngelCode Scripting Library
|
|
|
- Copyright (c) 2003-2013 Andreas Jonsson
|
|
|
|
|
|
|
+ Copyright (c) 2003-2014 Andreas Jonsson
|
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
This software is provided 'as-is', without any express or implied
|
|
|
warranty. In no event will the authors be held liable for any
|
|
warranty. In no event will the authors be held liable for any
|
|
@@ -36,7 +36,7 @@
|
|
|
// The class that does the actual compilation of the functions
|
|
// The class that does the actual compilation of the functions
|
|
|
//
|
|
//
|
|
|
|
|
|
|
|
-#include <math.h> // fmodf()
|
|
|
|
|
|
|
+#include <math.h> // fmodf() pow()
|
|
|
|
|
|
|
|
#include "as_config.h"
|
|
#include "as_config.h"
|
|
|
|
|
|
|
@@ -49,6 +49,7 @@
|
|
|
#include "as_texts.h"
|
|
#include "as_texts.h"
|
|
|
#include "as_parser.h"
|
|
#include "as_parser.h"
|
|
|
#include "as_debug.h"
|
|
#include "as_debug.h"
|
|
|
|
|
+#include "as_context.h" // as_powi()
|
|
|
|
|
|
|
|
BEGIN_AS_NAMESPACE
|
|
BEGIN_AS_NAMESPACE
|
|
|
|
|
|
|
@@ -363,7 +364,7 @@ int asCCompiler::SetupParametersAndReturnVariable(asCArray<asCString> ¶meter
|
|
|
{
|
|
{
|
|
|
// Get the parameter type
|
|
// Get the parameter type
|
|
|
asCDataType &type = outFunc->parameterTypes[n];
|
|
asCDataType &type = outFunc->parameterTypes[n];
|
|
|
- asETypeModifiers inoutFlag = outFunc->inOutFlags[n];
|
|
|
|
|
|
|
+ asETypeModifiers inoutFlag = n < outFunc->inOutFlags.GetLength() ? outFunc->inOutFlags[n] : asTM_NONE;
|
|
|
|
|
|
|
|
// Is the data type allowed?
|
|
// Is the data type allowed?
|
|
|
// TODO: Hasn't this been validated by the builder already?
|
|
// TODO: Hasn't this been validated by the builder already?
|
|
@@ -820,14 +821,44 @@ int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isOb
|
|
|
|
|
|
|
|
int func = 0;
|
|
int func = 0;
|
|
|
asSTypeBehaviour *beh = type.GetBehaviour();
|
|
asSTypeBehaviour *beh = type.GetBehaviour();
|
|
|
- if( beh ) func = beh->factory;
|
|
|
|
|
|
|
+ if( beh )
|
|
|
|
|
+ {
|
|
|
|
|
+ func = beh->factory;
|
|
|
|
|
+
|
|
|
|
|
+ // If no trivial default factory is found, look for a factory where all params have default args
|
|
|
|
|
+ if( func == 0 )
|
|
|
|
|
+ {
|
|
|
|
|
+ for( asUINT n = 0; n < beh->factories.GetLength(); n++ )
|
|
|
|
|
+ {
|
|
|
|
|
+ asCScriptFunction *f = engine->scriptFunctions[beh->factories[n]];
|
|
|
|
|
+ if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
|
|
|
|
|
+ f->defaultArgs[0] != 0 )
|
|
|
|
|
+ {
|
|
|
|
|
+ func = beh->factories[n];
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
if( func > 0 )
|
|
if( func > 0 )
|
|
|
{
|
|
{
|
|
|
|
|
+ asCArray<asSExprContext *> args;
|
|
|
|
|
+ asCScriptFunction *f = engine->scriptFunctions[func];
|
|
|
|
|
+ if( f->parameterTypes.GetLength() )
|
|
|
|
|
+ {
|
|
|
|
|
+ // Add the default values for arguments not explicitly supplied
|
|
|
|
|
+ CompileDefaultArgs(node, args, f);
|
|
|
|
|
+
|
|
|
|
|
+ PrepareFunctionCall(func, &ctx.bc, args);
|
|
|
|
|
+
|
|
|
|
|
+ MoveArgsToStack(func, &ctx.bc, args, false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if( isVarGlobOrMem == 0 )
|
|
if( isVarGlobOrMem == 0 )
|
|
|
{
|
|
{
|
|
|
// Call factory and store the handle in the given variable
|
|
// Call factory and store the handle in the given variable
|
|
|
- PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType(), true, offset);
|
|
|
|
|
|
|
+ PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType(), true, offset);
|
|
|
|
|
|
|
|
// Pop the reference left by the function call
|
|
// Pop the reference left by the function call
|
|
|
ctx.bc.Instr(asBC_PopPtr);
|
|
ctx.bc.Instr(asBC_PopPtr);
|
|
@@ -835,7 +866,7 @@ int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isOb
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
// Call factory
|
|
// Call factory
|
|
|
- PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
|
|
|
|
|
|
|
+ PerformFunctionCall(func, &ctx, false, &args, type.GetObjectType());
|
|
|
|
|
|
|
|
// TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
|
|
// TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination
|
|
|
// instead of first storing it in a local variable and then copying it to the
|
|
// instead of first storing it in a local variable and then copying it to the
|
|
@@ -879,38 +910,101 @@ int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isOb
|
|
|
|
|
|
|
|
bc->AddCode(&ctx.bc);
|
|
bc->AddCode(&ctx.bc);
|
|
|
|
|
|
|
|
|
|
+ // Cleanup
|
|
|
|
|
+ for( asUINT n = 0; n < args.GetLength(); n++ )
|
|
|
|
|
+ if( args[n] )
|
|
|
|
|
+ {
|
|
|
|
|
+ asDELETE(args[n],asSExprContext);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
|
|
+ asSExprContext ctx(engine);
|
|
|
|
|
+ ctx.exprNode = node;
|
|
|
|
|
+
|
|
|
asSTypeBehaviour *beh = type.GetBehaviour();
|
|
asSTypeBehaviour *beh = type.GetBehaviour();
|
|
|
|
|
|
|
|
int func = 0;
|
|
int func = 0;
|
|
|
- if( beh ) func = beh->construct;
|
|
|
|
|
|
|
+ if( beh )
|
|
|
|
|
+ {
|
|
|
|
|
+ func = beh->construct;
|
|
|
|
|
+
|
|
|
|
|
+ // If no trivial default constructor is found, look for a constructor where all params have default args
|
|
|
|
|
+ if( func == 0 )
|
|
|
|
|
+ {
|
|
|
|
|
+ for( asUINT n = 0; n < beh->constructors.GetLength(); n++ )
|
|
|
|
|
+ {
|
|
|
|
|
+ asCScriptFunction *f = engine->scriptFunctions[beh->constructors[n]];
|
|
|
|
|
+ if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() &&
|
|
|
|
|
+ f->defaultArgs[0] != 0 )
|
|
|
|
|
+ {
|
|
|
|
|
+ func = beh->constructors[n];
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// Allocate and initialize with the default constructor
|
|
// Allocate and initialize with the default constructor
|
|
|
if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
|
|
if( func != 0 || (type.GetObjectType()->flags & asOBJ_POD) )
|
|
|
{
|
|
{
|
|
|
|
|
+ asCArray<asSExprContext *> args;
|
|
|
|
|
+ asCScriptFunction *f = engine->scriptFunctions[func];
|
|
|
|
|
+ if( f && f->parameterTypes.GetLength() )
|
|
|
|
|
+ {
|
|
|
|
|
+ // Add the default values for arguments not explicitly supplied
|
|
|
|
|
+ CompileDefaultArgs(node, args, f);
|
|
|
|
|
+
|
|
|
|
|
+ PrepareFunctionCall(func, &ctx.bc, args);
|
|
|
|
|
+
|
|
|
|
|
+ MoveArgsToStack(func, &ctx.bc, args, false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if( !isObjectOnHeap )
|
|
if( !isObjectOnHeap )
|
|
|
{
|
|
{
|
|
|
- asASSERT( isVarGlobOrMem == 0 );
|
|
|
|
|
|
|
+ if( isVarGlobOrMem == 0 )
|
|
|
|
|
+ {
|
|
|
|
|
+ // There is nothing to do if there is no function,
|
|
|
|
|
+ // as the memory is already allocated on the stack
|
|
|
|
|
+ if( func )
|
|
|
|
|
+ {
|
|
|
|
|
+ // Call the constructor as a normal function
|
|
|
|
|
+ bc->InstrSHORT(asBC_PSF, (short)offset);
|
|
|
|
|
+ if( derefDest )
|
|
|
|
|
+ bc->Instr(asBC_RDSPtr);
|
|
|
|
|
|
|
|
- // There is nothing to do if there is no function,
|
|
|
|
|
- // as the memory is already allocated on the stack
|
|
|
|
|
- if( func )
|
|
|
|
|
|
|
+ asSExprContext ctx(engine);
|
|
|
|
|
+ PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
|
|
|
|
|
+ bc->AddCode(&ctx.bc);
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: value on stack: This probably needs to be done in PerformFunctionCall
|
|
|
|
|
+ // Mark the object as initialized
|
|
|
|
|
+ bc->ObjInfo(offset, asOBJ_INIT);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else if( isVarGlobOrMem == 2 )
|
|
|
{
|
|
{
|
|
|
- // Call the constructor as a normal function
|
|
|
|
|
- bc->InstrSHORT(asBC_PSF, (short)offset);
|
|
|
|
|
- if( derefDest )
|
|
|
|
|
|
|
+ // Only POD types can be allocated inline in script classes
|
|
|
|
|
+ asASSERT( type.GetObjectType()->flags & asOBJ_POD );
|
|
|
|
|
+
|
|
|
|
|
+ if( func )
|
|
|
|
|
+ {
|
|
|
|
|
+ // Call the constructor as a normal function
|
|
|
|
|
+ bc->InstrSHORT(asBC_PSF, 0);
|
|
|
bc->Instr(asBC_RDSPtr);
|
|
bc->Instr(asBC_RDSPtr);
|
|
|
- asSExprContext ctx(engine);
|
|
|
|
|
- PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
|
|
|
|
|
- bc->AddCode(&ctx.bc);
|
|
|
|
|
|
|
+ bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
|
|
|
|
|
|
|
|
- // TODO: value on stack: This probably needs to be done in PerformFunctionCall
|
|
|
|
|
- // Mark the object as initialized
|
|
|
|
|
- bc->ObjInfo(offset, asOBJ_INIT);
|
|
|
|
|
|
|
+ asSExprContext ctx(engine);
|
|
|
|
|
+ PerformFunctionCall(func, &ctx, false, 0, type.GetObjectType());
|
|
|
|
|
+ bc->AddCode(&ctx.bc);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ asASSERT( false );
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
@@ -929,6 +1023,13 @@ int asCCompiler::CallDefaultConstructor(asCDataType &type, int offset, bool isOb
|
|
|
bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
|
|
bc->Alloc(asBC_ALLOC, type.GetObjectType(), func, AS_PTR_SIZE);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Cleanup
|
|
|
|
|
+ for( asUINT n = 0; n < args.GetLength(); n++ )
|
|
|
|
|
+ if( args[n] )
|
|
|
|
|
+ {
|
|
|
|
|
+ asDELETE(args[n],asSExprContext);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -1091,7 +1192,7 @@ int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *scrip
|
|
|
// Compile the expression
|
|
// Compile the expression
|
|
|
asSExprContext ctx(engine);
|
|
asSExprContext ctx(engine);
|
|
|
asQWORD constantValue;
|
|
asQWORD constantValue;
|
|
|
- if( CompileInitialization(node, &ctx.bc, gvar->datatype, gvar->idNode, gvar->index, &constantValue, 1) )
|
|
|
|
|
|
|
+ if( CompileInitialization(node, &ctx.bc, gvar->datatype, gvar->declaredAtNode, gvar->index, &constantValue, 1) )
|
|
|
{
|
|
{
|
|
|
// Should the variable be marked as pure constant?
|
|
// Should the variable be marked as pure constant?
|
|
|
if( gvar->datatype.IsPrimitive() && gvar->datatype.IsReadOnly() )
|
|
if( gvar->datatype.IsPrimitive() && gvar->datatype.IsReadOnly() )
|
|
@@ -1106,10 +1207,10 @@ int asCCompiler::CompileGlobalVariable(asCBuilder *builder, asCScriptCode *scrip
|
|
|
|
|
|
|
|
// Add information on the line number for the global variable
|
|
// Add information on the line number for the global variable
|
|
|
size_t pos = 0;
|
|
size_t pos = 0;
|
|
|
- if( gvar->idNode )
|
|
|
|
|
- pos = gvar->idNode->tokenPos;
|
|
|
|
|
- else if( gvar->nextNode )
|
|
|
|
|
- pos = gvar->nextNode->tokenPos;
|
|
|
|
|
|
|
+ if( gvar->declaredAtNode )
|
|
|
|
|
+ pos = gvar->declaredAtNode->tokenPos;
|
|
|
|
|
+ else if( gvar->initializationNode )
|
|
|
|
|
+ pos = gvar->initializationNode->tokenPos;
|
|
|
LineInstr(&byteCode, pos);
|
|
LineInstr(&byteCode, pos);
|
|
|
|
|
|
|
|
// Reserve space for all local variables
|
|
// Reserve space for all local variables
|
|
@@ -1305,6 +1406,8 @@ void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, a
|
|
|
// variable then it is not necessary to make a copy either
|
|
// variable then it is not necessary to make a copy either
|
|
|
if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) && !isMakingCopy )
|
|
if( !ctx->type.isTemporary && !(param.IsReadOnly() && ctx->type.isVariable) && !isMakingCopy )
|
|
|
{
|
|
{
|
|
|
|
|
+ // TODO: 2.28.1: Need to reserve variables, as the default constructor may need
|
|
|
|
|
+ // to allocate temporary variables to compute default args
|
|
|
// Make sure the variable is not used in the expression
|
|
// Make sure the variable is not used in the expression
|
|
|
offset = AllocateVariableNotIn(dt, true, false, ctx);
|
|
offset = AllocateVariableNotIn(dt, true, false, ctx);
|
|
|
|
|
|
|
@@ -1388,6 +1491,9 @@ void asCCompiler::PrepareArgument(asCDataType *paramType, asSExprContext *ctx, a
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
|
|
+ // TODO: 2.28.1: Need to reserve variables, as the default constructor may need
|
|
|
|
|
+ // to allocate temporary variables to compute default args
|
|
|
|
|
+
|
|
|
// Allocate and construct the temporary object
|
|
// Allocate and construct the temporary object
|
|
|
asCByteCode tmpBC(engine);
|
|
asCByteCode tmpBC(engine);
|
|
|
CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
|
|
CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node);
|
|
@@ -1882,6 +1988,10 @@ asUINT asCCompiler::MatchFunctions(asCArray<int> &funcs, asCArray<asSExprContext
|
|
|
bool noMatch = true;
|
|
bool noMatch = true;
|
|
|
if( args.GetLength() < desc->parameterTypes.GetLength() )
|
|
if( args.GetLength() < desc->parameterTypes.GetLength() )
|
|
|
{
|
|
{
|
|
|
|
|
+ // For virtual functions, the default args are defined in the real function of the object
|
|
|
|
|
+ if( desc->funcType == asFUNC_VIRTUAL )
|
|
|
|
|
+ desc = objectType->virtualFunctionTable[desc->vfTableIdx];
|
|
|
|
|
+
|
|
|
// Count the number of default args
|
|
// Count the number of default args
|
|
|
asUINT defaultArgs = 0;
|
|
asUINT defaultArgs = 0;
|
|
|
for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
|
|
for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ )
|
|
@@ -2068,7 +2178,8 @@ void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc)
|
|
|
asCString name(&script->code[node->tokenPos], node->tokenLength);
|
|
asCString name(&script->code[node->tokenPos], node->tokenLength);
|
|
|
|
|
|
|
|
// Verify that the name isn't used by a dynamic data type
|
|
// Verify that the name isn't used by a dynamic data type
|
|
|
- if( engine->GetObjectType(name.AddressOf(), outFunc->nameSpace) != 0 )
|
|
|
|
|
|
|
+ // TODO: Must check against registered funcdefs too
|
|
|
|
|
+ if( engine->GetRegisteredObjectType(name.AddressOf(), outFunc->nameSpace) != 0 )
|
|
|
{
|
|
{
|
|
|
asCString str;
|
|
asCString str;
|
|
|
str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
|
|
str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf());
|
|
@@ -2207,14 +2318,18 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
|
|
|
if( onHeap )
|
|
if( onHeap )
|
|
|
ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
|
|
ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
|
|
|
}
|
|
}
|
|
|
- else
|
|
|
|
|
|
|
+ else if( isVarGlobOrMem == 1 )
|
|
|
{
|
|
{
|
|
|
// Push the address of the location where the variable will be stored on the stack.
|
|
// Push the address of the location where the variable will be stored on the stack.
|
|
|
// This reference is safe, because the addresses of the global variables cannot change.
|
|
// This reference is safe, because the addresses of the global variables cannot change.
|
|
|
onHeap = true;
|
|
onHeap = true;
|
|
|
- if( isVarGlobOrMem == 1 )
|
|
|
|
|
- ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
|
|
|
|
|
- else
|
|
|
|
|
|
|
+ ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Value types may be allocated inline if they are POD types
|
|
|
|
|
+ onHeap = !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF);
|
|
|
|
|
+ if( onHeap )
|
|
|
{
|
|
{
|
|
|
ctx.bc.InstrSHORT(asBC_PSF, 0);
|
|
ctx.bc.InstrSHORT(asBC_PSF, 0);
|
|
|
ctx.bc.Instr(asBC_RDSPtr);
|
|
ctx.bc.Instr(asBC_RDSPtr);
|
|
@@ -2228,7 +2343,18 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
|
|
|
// When the object is allocated on the stack, the address to the
|
|
// When the object is allocated on the stack, the address to the
|
|
|
// object is pushed on the stack after the arguments as the object pointer
|
|
// object is pushed on the stack after the arguments as the object pointer
|
|
|
if( !onHeap )
|
|
if( !onHeap )
|
|
|
- ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ if( isVarGlobOrMem == 2 )
|
|
|
|
|
+ {
|
|
|
|
|
+ ctx.bc.InstrSHORT(asBC_PSF, 0);
|
|
|
|
|
+ ctx.bc.Instr(asBC_RDSPtr);
|
|
|
|
|
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ ctx.bc.InstrSHORT(asBC_PSF, (short)offset);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType());
|
|
PerformFunctionCall(funcs[0], &ctx, onHeap, &args, type.GetObjectType());
|
|
|
|
|
|
|
@@ -2273,8 +2399,10 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
|
|
|
// Call the default constructor here
|
|
// Call the default constructor here
|
|
|
if( isVarGlobOrMem == 0 )
|
|
if( isVarGlobOrMem == 0 )
|
|
|
CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
|
|
CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode);
|
|
|
- else
|
|
|
|
|
|
|
+ else if( isVarGlobOrMem == 1 )
|
|
|
CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
|
|
CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem);
|
|
|
|
|
+ else if( isVarGlobOrMem == 2 )
|
|
|
|
|
+ CallDefaultConstructor(type, offset, type.IsReference(), &ctx.bc, errNode, isVarGlobOrMem);
|
|
|
|
|
|
|
|
// Compile the expression
|
|
// Compile the expression
|
|
|
asSExprContext expr(engine);
|
|
asSExprContext expr(engine);
|
|
@@ -2333,8 +2461,14 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
|
|
|
lexpr.type.Set(type);
|
|
lexpr.type.Set(type);
|
|
|
if( isVarGlobOrMem == 0 )
|
|
if( isVarGlobOrMem == 0 )
|
|
|
lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
|
|
lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset));
|
|
|
- else
|
|
|
|
|
|
|
+ else if( isVarGlobOrMem == 1 )
|
|
|
lexpr.type.dataType.MakeReference(true);
|
|
lexpr.type.dataType.MakeReference(true);
|
|
|
|
|
+ else if( isVarGlobOrMem == 2 )
|
|
|
|
|
+ {
|
|
|
|
|
+ if( !lexpr.type.dataType.IsObject() || (lexpr.type.dataType.GetObjectType()->flags & asOBJ_REF) )
|
|
|
|
|
+ lexpr.type.dataType.MakeReference(true);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// Allow initialization of constant variables
|
|
// Allow initialization of constant variables
|
|
|
lexpr.type.dataType.MakeReadOnly(false);
|
|
lexpr.type.dataType.MakeReadOnly(false);
|
|
|
|
|
|
|
@@ -2425,8 +2559,15 @@ bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, as
|
|
|
// Call the default constructor here, as no explicit initialization is done
|
|
// Call the default constructor here, as no explicit initialization is done
|
|
|
if( isVarGlobOrMem == 0 )
|
|
if( isVarGlobOrMem == 0 )
|
|
|
CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
|
|
CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode);
|
|
|
- else
|
|
|
|
|
|
|
+ else if( isVarGlobOrMem == 1 )
|
|
|
CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
|
|
CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
|
|
|
|
|
+ else if( isVarGlobOrMem == 2 )
|
|
|
|
|
+ {
|
|
|
|
|
+ if( !type.IsObject() || type.IsReference() || (type.GetObjectType()->flags & asOBJ_REF) )
|
|
|
|
|
+ CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem);
|
|
|
|
|
+ else
|
|
|
|
|
+ CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bc->OptimizeLocally(tempVariableOffsets);
|
|
bc->OptimizeLocally(tempVariableOffsets);
|
|
@@ -2554,21 +2695,34 @@ void asCCompiler::CompileInitList(asCTypeInfo *var, asCScriptNode *node, asCByte
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
|
|
+ bool onHeap = true;
|
|
|
|
|
+
|
|
|
// Put the address where the object pointer will be placed on the stack
|
|
// Put the address where the object pointer will be placed on the stack
|
|
|
if( isVarGlobOrMem == 1 )
|
|
if( isVarGlobOrMem == 1 )
|
|
|
ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
|
|
ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue());
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- ctx.bc.InstrSHORT(asBC_PSF, 0);
|
|
|
|
|
- ctx.bc.Instr(asBC_RDSPtr);
|
|
|
|
|
- ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
|
|
|
|
|
|
|
+ onHeap = !var->dataType.IsObject() || var->dataType.IsReference() || (var->dataType.GetObjectType()->flags & asOBJ_REF);
|
|
|
|
|
+ if( onHeap )
|
|
|
|
|
+ {
|
|
|
|
|
+ ctx.bc.InstrSHORT(asBC_PSF, 0);
|
|
|
|
|
+ ctx.bc.Instr(asBC_RDSPtr);
|
|
|
|
|
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Add the address of the list buffer as the argument
|
|
// Add the address of the list buffer as the argument
|
|
|
ctx.bc.AddCode(&arg1.bc);
|
|
ctx.bc.AddCode(&arg1.bc);
|
|
|
|
|
|
|
|
|
|
+ if( !onHeap )
|
|
|
|
|
+ {
|
|
|
|
|
+ ctx.bc.InstrSHORT(asBC_PSF, 0);
|
|
|
|
|
+ ctx.bc.Instr(asBC_RDSPtr);
|
|
|
|
|
+ ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateObject(outFunc->objectType, false)));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// Call the ALLOC instruction to allocate memory and invoke constructor
|
|
// Call the ALLOC instruction to allocate memory and invoke constructor
|
|
|
- PerformFunctionCall(funcId, &ctx, true, &args, var->dataType.GetObjectType());
|
|
|
|
|
|
|
+ PerformFunctionCall(funcId, &ctx, onHeap, &args, var->dataType.GetObjectType());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -2671,6 +2825,7 @@ int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScr
|
|
|
// We now know the type
|
|
// We now know the type
|
|
|
dt = rctx.type.dataType;
|
|
dt = rctx.type.dataType;
|
|
|
dt.MakeReadOnly(false);
|
|
dt.MakeReadOnly(false);
|
|
|
|
|
+ dt.MakeReference(false);
|
|
|
|
|
|
|
|
// Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
|
|
// Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit.
|
|
|
if( bufferSize & 0x3 )
|
|
if( bufferSize & 0x3 )
|
|
@@ -4229,7 +4384,11 @@ int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, boo
|
|
|
int asCCompiler::GetVariableOffset(int varIndex)
|
|
int asCCompiler::GetVariableOffset(int varIndex)
|
|
|
{
|
|
{
|
|
|
// Return offset to the last dword on the stack
|
|
// Return offset to the last dword on the stack
|
|
|
|
|
+
|
|
|
|
|
+ // Start at 1 as offset 0 is reserved for the this pointer (or first argument for global functions)
|
|
|
int varOffset = 1;
|
|
int varOffset = 1;
|
|
|
|
|
+
|
|
|
|
|
+ // Skip lower variables
|
|
|
for( int n = 0; n < varIndex; n++ )
|
|
for( int n = 0; n < varIndex; n++ )
|
|
|
{
|
|
{
|
|
|
if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
|
|
if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() )
|
|
@@ -4240,6 +4399,7 @@ int asCCompiler::GetVariableOffset(int varIndex)
|
|
|
|
|
|
|
|
if( varIndex < (int)variableAllocations.GetLength() )
|
|
if( varIndex < (int)variableAllocations.GetLength() )
|
|
|
{
|
|
{
|
|
|
|
|
+ // For variables larger than 1 dword the returned offset should be to the last dword
|
|
|
int size;
|
|
int size;
|
|
|
if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
|
|
if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() )
|
|
|
size = variableAllocations[varIndex].GetSizeInMemoryDWords();
|
|
size = variableAllocations[varIndex].GetSizeInMemoryDWords();
|
|
@@ -4836,6 +4996,32 @@ asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asSExprContext *ctx, const
|
|
|
return asCC_NO_CONV;
|
|
return asCC_NO_CONV;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Is the conversion an ambiguous enum value?
|
|
|
|
|
+ if( ctx->enumValue != "" )
|
|
|
|
|
+ {
|
|
|
|
|
+ if( to.IsEnumType() )
|
|
|
|
|
+ {
|
|
|
|
|
+ // Attempt to resolve an ambiguous enum value
|
|
|
|
|
+ asCDataType out;
|
|
|
|
|
+ asDWORD value;
|
|
|
|
|
+ if( builder->GetEnumValueFromObjectType(to.GetObjectType(), ctx->enumValue.AddressOf(), out, value) )
|
|
|
|
|
+ {
|
|
|
|
|
+ ctx->type.SetConstantDW(out, value);
|
|
|
|
|
+ ctx->type.dataType.MakeReadOnly(to.IsReadOnly());
|
|
|
|
|
+
|
|
|
|
|
+ // It wasn't really a conversion. The compiler just resolved the ambiguity (or not)
|
|
|
|
|
+ return asCC_NO_CONV;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // The enum value is ambiguous
|
|
|
|
|
+ if( node && generateCode )
|
|
|
|
|
+ Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, node);
|
|
|
|
|
+
|
|
|
|
|
+ // Set a dummy to allow the compiler to try to continue the conversion
|
|
|
|
|
+ ctx->type.SetDummy();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// Determine the cost of this conversion
|
|
// Determine the cost of this conversion
|
|
|
asUINT cost = asCC_NO_CONV;
|
|
asUINT cost = asCC_NO_CONV;
|
|
|
if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
|
|
if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) )
|
|
@@ -5302,7 +5488,7 @@ asUINT asCCompiler::ImplicitConvObjectToPrimitive(asSExprContext *ctx, const asC
|
|
|
for( unsigned int n = 0; n < funcs.GetLength(); n++ )
|
|
for( unsigned int n = 0; n < funcs.GetLength(); n++ )
|
|
|
{
|
|
{
|
|
|
asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
|
|
asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]);
|
|
|
- if( descr->returnType.IsEqualExceptConst(target) )
|
|
|
|
|
|
|
+ if( descr->returnType.IsEqualExceptRefAndConst(target) )
|
|
|
{
|
|
{
|
|
|
funcId = funcs[n];
|
|
funcId = funcs[n];
|
|
|
break;
|
|
break;
|
|
@@ -6975,6 +7161,13 @@ int asCCompiler::CompileCondition(asCScriptNode *expr, asSExprContext *ctx)
|
|
|
ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
|
|
ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Allow either case to be converted to const @ if the other is const @
|
|
|
|
|
+ if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) )
|
|
|
|
|
+ {
|
|
|
|
|
+ le.type.dataType.MakeHandleToConst(true);
|
|
|
|
|
+ re.type.dataType.MakeHandleToConst(true);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
//---------------------------------
|
|
//---------------------------------
|
|
|
// Output the byte code
|
|
// Output the byte code
|
|
|
int afterLabel = nextLabel++;
|
|
int afterLabel = nextLabel++;
|
|
@@ -7639,7 +7832,15 @@ int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &s
|
|
|
found = true;
|
|
found = true;
|
|
|
if( e == 2 )
|
|
if( e == 2 )
|
|
|
{
|
|
{
|
|
|
- Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, errNode);
|
|
|
|
|
|
|
+ // Ambiguous enum value: Save the name for resolution later.
|
|
|
|
|
+ // The ambiguity could be resolved now, but I hesitate
|
|
|
|
|
+ // to store too much information in the context.
|
|
|
|
|
+ ctx->enumValue = name.AddressOf();
|
|
|
|
|
+
|
|
|
|
|
+ // We cannot set a dummy value because it will pass through
|
|
|
|
|
+ // cleanly as an integer.
|
|
|
|
|
+ ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0);
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -8680,6 +8881,8 @@ void asCCompiler::CompileConstructCall(asCScriptNode *node, asSExprContext *ctx)
|
|
|
{
|
|
{
|
|
|
int r = asSUCCESS;
|
|
int r = asSUCCESS;
|
|
|
|
|
|
|
|
|
|
+ // TODO: 2.28.1: Merge this with MakeFunctionCall
|
|
|
|
|
+
|
|
|
// Add the default values for arguments not explicitly supplied
|
|
// Add the default values for arguments not explicitly supplied
|
|
|
asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
|
|
asCScriptFunction *func = (funcs[0] & FUNC_IMPORTED) == 0 ? engine->scriptFunctions[funcs[0]] : 0;
|
|
|
if( func && args.GetLength() < (asUINT)func->GetParamCount() )
|
|
if( func && args.GetLength() < (asUINT)func->GetParamCount() )
|
|
@@ -8897,7 +9100,6 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
|
|
|
|
|
|
|
|
// Compile the arguments
|
|
// Compile the arguments
|
|
|
asCArray<asSExprContext *> args;
|
|
asCArray<asSExprContext *> args;
|
|
|
- asCArray<asCTypeInfo> temporaryVariables;
|
|
|
|
|
|
|
|
|
|
if( CompileArgumentList(node->lastChild, args) >= 0 )
|
|
if( CompileArgumentList(node->lastChild, args) >= 0 )
|
|
|
{
|
|
{
|
|
@@ -8926,7 +9128,14 @@ int asCCompiler::CompileFunctionCall(asCScriptNode *node, asSExprContext *ctx, a
|
|
|
// Add the default values for arguments not explicitly supplied
|
|
// Add the default values for arguments not explicitly supplied
|
|
|
asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
|
|
asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]);
|
|
|
if( func && args.GetLength() < (asUINT)func->GetParamCount() )
|
|
if( func && args.GetLength() < (asUINT)func->GetParamCount() )
|
|
|
- r = CompileDefaultArgs(node, args, func);
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ // Make sure to use the real function for virtual functions
|
|
|
|
|
+ asCScriptFunction *realFunc = func;
|
|
|
|
|
+ if( realFunc->funcType == asFUNC_VIRTUAL )
|
|
|
|
|
+ realFunc = objectType->virtualFunctionTable[realFunc->vfTableIdx];
|
|
|
|
|
+
|
|
|
|
|
+ r = CompileDefaultArgs(node, args, realFunc);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
|
|
// TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or
|
|
|
// is it enough to make sure it is in a local variable?
|
|
// is it enough to make sure it is in a local variable?
|
|
@@ -10390,6 +10599,7 @@ int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asSExprContext *ct
|
|
|
|
|
|
|
|
int asCCompiler::GetPrecedence(asCScriptNode *op)
|
|
int asCCompiler::GetPrecedence(asCScriptNode *op)
|
|
|
{
|
|
{
|
|
|
|
|
+ // x ** y
|
|
|
// x * y, x / y, x % y
|
|
// x * y, x / y, x % y
|
|
|
// x + y, x - y
|
|
// x + y, x - y
|
|
|
// x <= y, x < y, x >= y, x > y
|
|
// x <= y, x < y, x >= y, x > y
|
|
@@ -10408,40 +10618,43 @@ int asCCompiler::GetPrecedence(asCScriptNode *op)
|
|
|
|
|
|
|
|
// Evaluate operators by token
|
|
// Evaluate operators by token
|
|
|
int tokenType = op->tokenType;
|
|
int tokenType = op->tokenType;
|
|
|
- if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
|
|
|
|
|
|
|
+ if( tokenType == ttStarStar )
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
- if( tokenType == ttPlus || tokenType == ttMinus )
|
|
|
|
|
|
|
+ if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent )
|
|
|
return -1;
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
+ if( tokenType == ttPlus || tokenType == ttMinus )
|
|
|
|
|
+ return -2;
|
|
|
|
|
+
|
|
|
if( tokenType == ttBitShiftLeft ||
|
|
if( tokenType == ttBitShiftLeft ||
|
|
|
tokenType == ttBitShiftRight ||
|
|
tokenType == ttBitShiftRight ||
|
|
|
tokenType == ttBitShiftRightArith )
|
|
tokenType == ttBitShiftRightArith )
|
|
|
- return -2;
|
|
|
|
|
|
|
+ return -3;
|
|
|
|
|
|
|
|
if( tokenType == ttAmp )
|
|
if( tokenType == ttAmp )
|
|
|
- return -3;
|
|
|
|
|
|
|
+ return -4;
|
|
|
|
|
|
|
|
if( tokenType == ttBitXor )
|
|
if( tokenType == ttBitXor )
|
|
|
- return -4;
|
|
|
|
|
|
|
+ return -5;
|
|
|
|
|
|
|
|
if( tokenType == ttBitOr )
|
|
if( tokenType == ttBitOr )
|
|
|
- return -5;
|
|
|
|
|
|
|
+ return -6;
|
|
|
|
|
|
|
|
if( tokenType == ttLessThanOrEqual ||
|
|
if( tokenType == ttLessThanOrEqual ||
|
|
|
tokenType == ttLessThan ||
|
|
tokenType == ttLessThan ||
|
|
|
tokenType == ttGreaterThanOrEqual ||
|
|
tokenType == ttGreaterThanOrEqual ||
|
|
|
tokenType == ttGreaterThan )
|
|
tokenType == ttGreaterThan )
|
|
|
- return -6;
|
|
|
|
|
|
|
+ return -7;
|
|
|
|
|
|
|
|
if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
|
|
if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs )
|
|
|
- return -7;
|
|
|
|
|
|
|
+ return -8;
|
|
|
|
|
|
|
|
if( tokenType == ttAnd )
|
|
if( tokenType == ttAnd )
|
|
|
- return -8;
|
|
|
|
|
|
|
+ return -9;
|
|
|
|
|
|
|
|
if( tokenType == ttOr )
|
|
if( tokenType == ttOr )
|
|
|
- return -9;
|
|
|
|
|
|
|
+ return -10;
|
|
|
|
|
|
|
|
// Unknown operator
|
|
// Unknown operator
|
|
|
asASSERT(false);
|
|
asASSERT(false);
|
|
@@ -10473,6 +10686,7 @@ asUINT asCCompiler::MatchArgument(asCArray<int> &funcs, asCArray<asSOverloadCand
|
|
|
asSExprContext ti(engine);
|
|
asSExprContext ti(engine);
|
|
|
ti.type = argExpr->type;
|
|
ti.type = argExpr->type;
|
|
|
ti.methodName = argExpr->methodName;
|
|
ti.methodName = argExpr->methodName;
|
|
|
|
|
+ ti.enumValue = argExpr->enumValue;
|
|
|
if( argExpr->type.dataType.IsPrimitive() ) ti.type.dataType.MakeReference(false);
|
|
if( argExpr->type.dataType.IsPrimitive() ) ti.type.dataType.MakeReference(false);
|
|
|
asUINT cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
|
|
asUINT cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct);
|
|
|
|
|
|
|
@@ -10669,6 +10883,7 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont
|
|
|
case ttStar: op = "opMul"; op_r = "opMul_r"; break;
|
|
case ttStar: op = "opMul"; op_r = "opMul_r"; break;
|
|
|
case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
|
|
case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break;
|
|
|
case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
|
|
case ttPercent: op = "opMod"; op_r = "opMod_r"; break;
|
|
|
|
|
+ case ttStarStar: op = "opPow"; op_r = "opPow_r"; break;
|
|
|
case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
|
|
case ttBitOr: op = "opOr"; op_r = "opOr_r"; break;
|
|
|
case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
|
|
case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break;
|
|
|
case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
|
|
case ttBitXor: op = "opXor"; op_r = "opXor_r"; break;
|
|
@@ -10713,6 +10928,7 @@ bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asSExprCont
|
|
|
case ttMulAssign: op = "opMulAssign"; break;
|
|
case ttMulAssign: op = "opMulAssign"; break;
|
|
|
case ttDivAssign: op = "opDivAssign"; break;
|
|
case ttDivAssign: op = "opDivAssign"; break;
|
|
|
case ttModAssign: op = "opModAssign"; break;
|
|
case ttModAssign: op = "opModAssign"; break;
|
|
|
|
|
+ case ttPowAssign: op = "opPowAssign"; break;
|
|
|
case ttOrAssign: op = "opOrAssign"; break;
|
|
case ttOrAssign: op = "opOrAssign"; break;
|
|
|
case ttAndAssign: op = "opAndAssign"; break;
|
|
case ttAndAssign: op = "opAndAssign"; break;
|
|
|
case ttXorAssign: op = "opXorAssign"; break;
|
|
case ttXorAssign: op = "opXorAssign"; break;
|
|
@@ -10995,13 +11211,14 @@ int asCCompiler::CompileOperator(asCScriptNode *node, asSExprContext *lctx, asSE
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Math operators
|
|
// Math operators
|
|
|
- // + - * / % += -= *= /= %=
|
|
|
|
|
|
|
+ // + - * / % ** += -= *= /= %= **=
|
|
|
int op = node->tokenType;
|
|
int op = node->tokenType;
|
|
|
- if( op == ttPlus || op == ttAddAssign ||
|
|
|
|
|
- op == ttMinus || op == ttSubAssign ||
|
|
|
|
|
- op == ttStar || op == ttMulAssign ||
|
|
|
|
|
- op == ttSlash || op == ttDivAssign ||
|
|
|
|
|
- op == ttPercent || op == ttModAssign )
|
|
|
|
|
|
|
+ if( op == ttPlus || op == ttAddAssign ||
|
|
|
|
|
+ op == ttMinus || op == ttSubAssign ||
|
|
|
|
|
+ op == ttStar || op == ttMulAssign ||
|
|
|
|
|
+ op == ttSlash || op == ttDivAssign ||
|
|
|
|
|
+ op == ttPercent || op == ttModAssign ||
|
|
|
|
|
+ op == ttStarStar || op == ttPowAssign )
|
|
|
{
|
|
{
|
|
|
CompileMathOperator(node, lctx, rctx, ctx);
|
|
CompileMathOperator(node, lctx, rctx, ctx);
|
|
|
return 0;
|
|
return 0;
|
|
@@ -11213,10 +11430,25 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|
|
if( rctx->type.dataType.IsReference() )
|
|
if( rctx->type.dataType.IsReference() )
|
|
|
ConvertToVariable(rctx);
|
|
ConvertToVariable(rctx);
|
|
|
|
|
|
|
|
|
|
+ int op = node->tokenType;
|
|
|
if( to.IsPrimitive() )
|
|
if( to.IsPrimitive() )
|
|
|
{
|
|
{
|
|
|
- ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
|
|
|
|
|
- ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
|
|
|
|
|
|
|
+ // ttStarStar allows an integer, right-hand operand and a double
|
|
|
|
|
+ // left-hand operand.
|
|
|
|
|
+ if( (op == ttStarStar || op == ttPowAssign) &&
|
|
|
|
|
+ lctx->type.dataType.IsDoubleType() &&
|
|
|
|
|
+ (rctx->type.dataType.IsIntegerType() ||
|
|
|
|
|
+ rctx->type.dataType.IsUnsignedType()) )
|
|
|
|
|
+ {
|
|
|
|
|
+ to.SetTokenType(ttInt);
|
|
|
|
|
+ ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
|
|
|
|
|
+ to.SetTokenType(ttDouble);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true);
|
|
|
|
|
+ ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
reservedVariables.SetLength(l);
|
|
reservedVariables.SetLength(l);
|
|
|
|
|
|
|
@@ -11250,7 +11482,6 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|
|
bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
|
|
bool isConstant = lctx->type.isConstant && rctx->type.isConstant;
|
|
|
|
|
|
|
|
// Verify if we are dividing with a constant zero
|
|
// Verify if we are dividing with a constant zero
|
|
|
- int op = node->tokenType;
|
|
|
|
|
if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
|
|
if( rctx->type.isConstant && rctx->type.qwordValue == 0 &&
|
|
|
(op == ttSlash || op == ttDivAssign ||
|
|
(op == ttSlash || op == ttDivAssign ||
|
|
|
op == ttPercent || op == ttModAssign) )
|
|
op == ttPercent || op == ttModAssign) )
|
|
@@ -11267,7 +11498,7 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|
|
|
|
|
|
|
if( op == ttAddAssign || op == ttSubAssign ||
|
|
if( op == ttAddAssign || op == ttSubAssign ||
|
|
|
op == ttMulAssign || op == ttDivAssign ||
|
|
op == ttMulAssign || op == ttDivAssign ||
|
|
|
- op == ttModAssign )
|
|
|
|
|
|
|
+ op == ttModAssign || op == ttPowAssign )
|
|
|
{
|
|
{
|
|
|
// Merge the operands in the different order so that they are evaluated correctly
|
|
// Merge the operands in the different order so that they are evaluated correctly
|
|
|
MergeExprBytecode(ctx, rctx);
|
|
MergeExprBytecode(ctx, rctx);
|
|
@@ -11310,6 +11541,13 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|
|
else
|
|
else
|
|
|
instruction = asBC_MODu;
|
|
instruction = asBC_MODu;
|
|
|
}
|
|
}
|
|
|
|
|
+ else if( op == ttStarStar || op == ttPowAssign )
|
|
|
|
|
+ {
|
|
|
|
|
+ if( lctx->type.dataType.IsIntegerType() )
|
|
|
|
|
+ instruction = asBC_POWi;
|
|
|
|
|
+ else
|
|
|
|
|
+ instruction = asBC_POWu;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
@@ -11333,6 +11571,13 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|
|
else
|
|
else
|
|
|
instruction = asBC_MODu64;
|
|
instruction = asBC_MODu64;
|
|
|
}
|
|
}
|
|
|
|
|
+ else if( op == ttStarStar || op == ttPowAssign )
|
|
|
|
|
+ {
|
|
|
|
|
+ if( lctx->type.dataType.IsIntegerType() )
|
|
|
|
|
+ instruction = asBC_POWi64;
|
|
|
|
|
+ else
|
|
|
|
|
+ instruction = asBC_POWu64;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else if( lctx->type.dataType.IsFloatType() )
|
|
else if( lctx->type.dataType.IsFloatType() )
|
|
@@ -11347,19 +11592,35 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|
|
instruction = asBC_DIVf;
|
|
instruction = asBC_DIVf;
|
|
|
else if( op == ttPercent || op == ttModAssign )
|
|
else if( op == ttPercent || op == ttModAssign )
|
|
|
instruction = asBC_MODf;
|
|
instruction = asBC_MODf;
|
|
|
|
|
+ else if( op == ttStarStar || op == ttPowAssign )
|
|
|
|
|
+ instruction = asBC_POWf;
|
|
|
}
|
|
}
|
|
|
else if( lctx->type.dataType.IsDoubleType() )
|
|
else if( lctx->type.dataType.IsDoubleType() )
|
|
|
{
|
|
{
|
|
|
- if( op == ttPlus || op == ttAddAssign )
|
|
|
|
|
- instruction = asBC_ADDd;
|
|
|
|
|
- else if( op == ttMinus || op == ttSubAssign )
|
|
|
|
|
- instruction = asBC_SUBd;
|
|
|
|
|
- else if( op == ttStar || op == ttMulAssign )
|
|
|
|
|
- instruction = asBC_MULd;
|
|
|
|
|
- else if( op == ttSlash || op == ttDivAssign )
|
|
|
|
|
- instruction = asBC_DIVd;
|
|
|
|
|
- else if( op == ttPercent || op == ttModAssign )
|
|
|
|
|
- instruction = asBC_MODd;
|
|
|
|
|
|
|
+ if( rctx->type.dataType.IsIntegerType() )
|
|
|
|
|
+ {
|
|
|
|
|
+ asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
|
|
|
|
|
+
|
|
|
|
|
+ if( op == ttStarStar || op == ttPowAssign )
|
|
|
|
|
+ instruction = asBC_POWdi;
|
|
|
|
|
+ else
|
|
|
|
|
+ asASSERT(false); // Should not be possible
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ if( op == ttPlus || op == ttAddAssign )
|
|
|
|
|
+ instruction = asBC_ADDd;
|
|
|
|
|
+ else if( op == ttMinus || op == ttSubAssign )
|
|
|
|
|
+ instruction = asBC_SUBd;
|
|
|
|
|
+ else if( op == ttStar || op == ttMulAssign )
|
|
|
|
|
+ instruction = asBC_MULd;
|
|
|
|
|
+ else if( op == ttSlash || op == ttDivAssign )
|
|
|
|
|
+ instruction = asBC_DIVd;
|
|
|
|
|
+ else if( op == ttPercent || op == ttModAssign )
|
|
|
|
|
+ instruction = asBC_MODd;
|
|
|
|
|
+ else if( op == ttStarStar || op == ttPowAssign )
|
|
|
|
|
+ instruction = asBC_POWd;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
@@ -11413,6 +11674,14 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|
|
else
|
|
else
|
|
|
v = lctx->type.dwordValue % rctx->type.dwordValue;
|
|
v = lctx->type.dwordValue % rctx->type.dwordValue;
|
|
|
}
|
|
}
|
|
|
|
|
+ else if( op == ttStarStar )
|
|
|
|
|
+ {
|
|
|
|
|
+ bool isOverflow;
|
|
|
|
|
+ if( lctx->type.dataType.IsIntegerType() )
|
|
|
|
|
+ v = as_powi(lctx->type.intValue, rctx->type.intValue, isOverflow);
|
|
|
|
|
+ else
|
|
|
|
|
+ v = as_powu(lctx->type.dwordValue, rctx->type.dwordValue, isOverflow);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
ctx->type.SetConstantDW(lctx->type.dataType, v);
|
|
ctx->type.SetConstantDW(lctx->type.dataType, v);
|
|
|
|
|
|
|
@@ -11451,6 +11720,14 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|
|
else
|
|
else
|
|
|
v = lctx->type.qwordValue % rctx->type.qwordValue;
|
|
v = lctx->type.qwordValue % rctx->type.qwordValue;
|
|
|
}
|
|
}
|
|
|
|
|
+ else if( op == ttStarStar )
|
|
|
|
|
+ {
|
|
|
|
|
+ bool isOverflow;
|
|
|
|
|
+ if( lctx->type.dataType.IsIntegerType() )
|
|
|
|
|
+ v = as_powi64(asINT64(lctx->type.qwordValue), asINT64(rctx->type.qwordValue), isOverflow);
|
|
|
|
|
+ else
|
|
|
|
|
+ v = as_powu64(lctx->type.qwordValue, rctx->type.qwordValue, isOverflow);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
ctx->type.SetConstantQW(lctx->type.dataType, v);
|
|
ctx->type.SetConstantQW(lctx->type.dataType, v);
|
|
|
|
|
|
|
@@ -11482,31 +11759,47 @@ void asCCompiler::CompileMathOperator(asCScriptNode *node, asSExprContext *lctx,
|
|
|
else
|
|
else
|
|
|
v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
|
|
v = fmodf(lctx->type.floatValue, rctx->type.floatValue);
|
|
|
}
|
|
}
|
|
|
|
|
+ else if( op == ttStarStar )
|
|
|
|
|
+ v = pow(lctx->type.floatValue, rctx->type.floatValue);
|
|
|
|
|
|
|
|
ctx->type.SetConstantF(lctx->type.dataType, v);
|
|
ctx->type.SetConstantF(lctx->type.dataType, v);
|
|
|
}
|
|
}
|
|
|
else if( lctx->type.dataType.IsDoubleType() )
|
|
else if( lctx->type.dataType.IsDoubleType() )
|
|
|
{
|
|
{
|
|
|
double v = 0.0;
|
|
double v = 0.0;
|
|
|
- if( op == ttPlus )
|
|
|
|
|
- v = lctx->type.doubleValue + rctx->type.doubleValue;
|
|
|
|
|
- else if( op == ttMinus )
|
|
|
|
|
- v = lctx->type.doubleValue - rctx->type.doubleValue;
|
|
|
|
|
- else if( op == ttStar )
|
|
|
|
|
- v = lctx->type.doubleValue * rctx->type.doubleValue;
|
|
|
|
|
- else if( op == ttSlash )
|
|
|
|
|
|
|
+ if( rctx->type.dataType.IsIntegerType() )
|
|
|
{
|
|
{
|
|
|
- if( rctx->type.doubleValue == 0 )
|
|
|
|
|
- v = 0;
|
|
|
|
|
|
|
+ asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1);
|
|
|
|
|
+
|
|
|
|
|
+ if( op == ttStarStar || op == ttPowAssign )
|
|
|
|
|
+ v = pow(lctx->type.doubleValue, rctx->type.intValue);
|
|
|
else
|
|
else
|
|
|
- v = lctx->type.doubleValue / rctx->type.doubleValue;
|
|
|
|
|
|
|
+ asASSERT(false); // Should not be possible
|
|
|
}
|
|
}
|
|
|
- else if( op == ttPercent )
|
|
|
|
|
|
|
+ else
|
|
|
{
|
|
{
|
|
|
- if( rctx->type.doubleValue == 0 )
|
|
|
|
|
- v = 0;
|
|
|
|
|
- else
|
|
|
|
|
- v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
|
|
|
|
|
|
|
+ if( op == ttPlus )
|
|
|
|
|
+ v = lctx->type.doubleValue + rctx->type.doubleValue;
|
|
|
|
|
+ else if( op == ttMinus )
|
|
|
|
|
+ v = lctx->type.doubleValue - rctx->type.doubleValue;
|
|
|
|
|
+ else if( op == ttStar )
|
|
|
|
|
+ v = lctx->type.doubleValue * rctx->type.doubleValue;
|
|
|
|
|
+ else if( op == ttSlash )
|
|
|
|
|
+ {
|
|
|
|
|
+ if( rctx->type.doubleValue == 0 )
|
|
|
|
|
+ v = 0;
|
|
|
|
|
+ else
|
|
|
|
|
+ v = lctx->type.doubleValue / rctx->type.doubleValue;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if( op == ttPercent )
|
|
|
|
|
+ {
|
|
|
|
|
+ if( rctx->type.doubleValue == 0 )
|
|
|
|
|
+ v = 0;
|
|
|
|
|
+ else
|
|
|
|
|
+ v = fmod(lctx->type.doubleValue, rctx->type.doubleValue);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if( op == ttStarStar )
|
|
|
|
|
+ v = pow(lctx->type.doubleValue, rctx->type.doubleValue);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ctx->type.SetConstantD(lctx->type.dataType, v);
|
|
ctx->type.SetConstantD(lctx->type.dataType, v);
|
|
@@ -12693,6 +12986,7 @@ void asCCompiler::MergeExprBytecodeAndType(asSExprContext *before, asSExprContex
|
|
|
before->property_arg = after->property_arg;
|
|
before->property_arg = after->property_arg;
|
|
|
before->exprNode = after->exprNode;
|
|
before->exprNode = after->exprNode;
|
|
|
before->methodName = after->methodName;
|
|
before->methodName = after->methodName;
|
|
|
|
|
+ before->enumValue = after->enumValue;
|
|
|
|
|
|
|
|
after->property_arg = 0;
|
|
after->property_arg = 0;
|
|
|
|
|
|