2008-10-18 17:17:44 +00:00
|
|
|
/*
|
|
|
|
** thingdef_expression.cpp
|
|
|
|
**
|
|
|
|
** Expression evaluation
|
|
|
|
**
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
** Copyright 2008 Christoph Oelckers
|
|
|
|
** All rights reserved.
|
|
|
|
**
|
|
|
|
** Redistribution and use in source and binary forms, with or without
|
|
|
|
** modification, are permitted provided that the following conditions
|
|
|
|
** are met:
|
|
|
|
**
|
|
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer.
|
|
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
|
|
** documentation and/or other materials provided with the distribution.
|
|
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
|
|
** derived from this software without specific prior written permission.
|
|
|
|
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
|
|
|
|
** covered by the terms of the GNU General Public License as published by
|
|
|
|
** the Free Software Foundation; either version 2 of the License, or (at
|
|
|
|
** your option) any later version.
|
|
|
|
**
|
|
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
2009-10-17 01:38:54 +00:00
|
|
|
#include <malloc.h>
|
2008-10-18 17:17:44 +00:00
|
|
|
#include "actor.h"
|
|
|
|
#include "sc_man.h"
|
|
|
|
#include "tarray.h"
|
|
|
|
#include "templates.h"
|
|
|
|
#include "cmdlib.h"
|
|
|
|
#include "i_system.h"
|
|
|
|
#include "m_random.h"
|
|
|
|
#include "a_pickups.h"
|
|
|
|
#include "thingdef.h"
|
|
|
|
#include "p_lnspec.h"
|
|
|
|
#include "doomstat.h"
|
|
|
|
#include "thingdef_exp.h"
|
2009-11-20 05:34:20 +00:00
|
|
|
#include "m_fixed.h"
|
2009-10-11 00:02:14 +00:00
|
|
|
#include "vmbuilder.h"
|
2008-10-19 21:43:36 +00:00
|
|
|
|
|
|
|
// Accessible actor member variables
|
|
|
|
DEFINE_MEMBER_VARIABLE(alpha, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(angle, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(args, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(ceilingz, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(floorz, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(health, AActor)
|
2011-01-14 22:59:20 +00:00
|
|
|
DEFINE_MEMBER_VARIABLE(Mass, AActor)
|
2008-10-19 21:43:36 +00:00
|
|
|
DEFINE_MEMBER_VARIABLE(pitch, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(special, AActor)
|
2009-09-14 20:47:53 +00:00
|
|
|
DEFINE_MEMBER_VARIABLE(special1, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(special2, AActor)
|
2008-10-19 21:43:36 +00:00
|
|
|
DEFINE_MEMBER_VARIABLE(tid, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(TIDtoHate, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(waterlevel, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(x, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(y, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(z, AActor)
|
2009-06-30 20:57:51 +00:00
|
|
|
DEFINE_MEMBER_VARIABLE(velx, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(vely, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(velz, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE_ALIAS(momx, velx, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE_ALIAS(momy, vely, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE_ALIAS(momz, velz, AActor)
|
2010-11-08 00:01:21 +00:00
|
|
|
DEFINE_MEMBER_VARIABLE(scaleX, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(scaleY, AActor)
|
2012-10-28 04:36:52 +00:00
|
|
|
//DEFINE_MEMBER_VARIABLE(Damage, AActor)
|
2009-09-14 19:44:14 +00:00
|
|
|
DEFINE_MEMBER_VARIABLE(Score, AActor)
|
2012-03-11 09:08:35 +00:00
|
|
|
DEFINE_MEMBER_VARIABLE(accuracy, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(stamina, AActor)
|
2012-11-09 23:06:40 +00:00
|
|
|
DEFINE_MEMBER_VARIABLE(height, AActor)
|
|
|
|
DEFINE_MEMBER_VARIABLE(radius, AActor)
|
2013-04-20 21:32:03 +00:00
|
|
|
DEFINE_MEMBER_VARIABLE(reactiontime, AActor)
|
2013-06-01 02:23:27 +00:00
|
|
|
DEFINE_MEMBER_VARIABLE(meleerange, AActor)
|
2008-10-19 21:43:36 +00:00
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit::ExpEmit(VMFunctionBuilder *build, int type)
|
2009-10-15 23:11:54 +00:00
|
|
|
: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false)
|
2009-10-11 00:02:14 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-10-15 23:11:54 +00:00
|
|
|
void ExpEmit::Free(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
if (!Fixed && !Konst)
|
|
|
|
{
|
|
|
|
build->Registers[RegType].Return(RegNum, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-26 04:04:06 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// FindDecorateBuiltinFunction
|
|
|
|
//
|
|
|
|
// Returns the symbol for a decorate utility function. If not found, create
|
|
|
|
// it and install it in Actor.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static PSymbol *FindDecorateBuiltinFunction(FName funcname, VMNativeFunction::NativeCallType func)
|
|
|
|
{
|
|
|
|
PSymbol *sym = RUNTIME_CLASS(AActor)->Symbols.FindSymbol(funcname, false);
|
|
|
|
if (sym == NULL)
|
|
|
|
{
|
|
|
|
PSymbolVMFunction *symfunc = new PSymbolVMFunction(funcname);
|
|
|
|
VMNativeFunction *calldec = new VMNativeFunction(func, funcname);
|
|
|
|
symfunc->Function = calldec;
|
|
|
|
sym = symfunc;
|
|
|
|
RUNTIME_CLASS(AActor)->Symbols.AddSymbol(sym);
|
|
|
|
}
|
|
|
|
return sym;
|
|
|
|
}
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxExpression::Emit (VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Unemitted expression found");
|
|
|
|
return ExpEmit();
|
|
|
|
}
|
|
|
|
|
2008-10-21 18:10:50 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
bool FxExpression::isConstant() const
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxExpression::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
2008-10-25 17:38:00 +00:00
|
|
|
isresolved = true;
|
2008-10-21 18:10:50 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2008-10-25 17:38:00 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxExpression::ResolveAsBoolean(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
FxExpression *x = Resolve(ctx);
|
|
|
|
if (x != NULL)
|
|
|
|
{
|
|
|
|
switch (x->ValueType.Type)
|
|
|
|
{
|
|
|
|
case VAL_Sound:
|
|
|
|
case VAL_Color:
|
|
|
|
case VAL_Name:
|
|
|
|
x->ValueType = VAL_Int;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FxExpression::RequestAddress()
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "invalid dereference\n");
|
|
|
|
}
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxParameter::FxParameter(FxExpression *operand)
|
|
|
|
: FxExpression(operand->ScriptPosition)
|
|
|
|
{
|
|
|
|
Operand = operand;
|
2009-10-15 21:59:37 +00:00
|
|
|
ValueType = operand->ValueType;
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxParameter::~FxParameter()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(Operand);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxParameter::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(Operand, ctx);
|
2009-10-15 21:59:37 +00:00
|
|
|
ValueType = Operand->ValueType;
|
2009-10-11 00:02:14 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
ExpEmit FxParameter::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
if (Operand->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
ExpVal val = static_cast<FxConstant *>(Operand)->GetValue();
|
2009-10-11 00:02:14 +00:00
|
|
|
if (val.Type == VAL_Int || val.Type == VAL_Sound || val.Type == VAL_Name || val.Type == VAL_Color)
|
|
|
|
{
|
2013-07-28 02:38:35 +00:00
|
|
|
build->EmitParamInt(val.Int);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
else if (val.Type == VAL_Float)
|
|
|
|
{
|
2009-10-15 03:58:23 +00:00
|
|
|
build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, build->GetConstantFloat(val.Float));
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
else if (val.Type == VAL_Class || val.Type == VAL_Object)
|
|
|
|
{
|
|
|
|
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(val.pointer, ATAG_OBJECT));
|
|
|
|
}
|
|
|
|
else if (val.Type == VAL_State)
|
|
|
|
{
|
|
|
|
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(val.pointer, ATAG_STATE));
|
|
|
|
}
|
2009-10-17 01:38:54 +00:00
|
|
|
else if (val.Type == VAL_String)
|
|
|
|
{
|
|
|
|
build->Emit(OP_PARAM, 0, REGT_STRING | REGT_KONST, build->GetConstantString(val.GetString()));
|
|
|
|
}
|
2009-10-11 00:02:14 +00:00
|
|
|
else
|
|
|
|
{
|
2009-10-17 01:38:54 +00:00
|
|
|
build->Emit(OP_PARAM, 0, REGT_NIL, 0);
|
2009-10-11 00:02:14 +00:00
|
|
|
ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ExpEmit where = Operand->Emit(build);
|
|
|
|
|
2009-10-15 03:58:23 +00:00
|
|
|
if (where.RegType == REGT_NIL)
|
2009-10-11 00:02:14 +00:00
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Attempted to pass a non-value");
|
|
|
|
build->Emit(OP_PARAM, 0, where.RegType, where.RegNum);
|
|
|
|
}
|
2009-10-15 03:58:23 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
build->Emit(OP_PARAM, 0, where.RegType, where.RegNum);
|
2009-10-15 23:11:54 +00:00
|
|
|
where.Free(build);
|
2009-10-15 03:58:23 +00:00
|
|
|
}
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
return ExpEmit();
|
|
|
|
}
|
2008-10-19 21:43:36 +00:00
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
FxExpression *FxConstant::MakeConstant(PSymbol *sym, const FScriptPosition &pos)
|
|
|
|
{
|
|
|
|
FxExpression *x;
|
2010-04-03 02:06:51 +00:00
|
|
|
PSymbolConst *csym = dyn_cast<PSymbolConst>(sym);
|
|
|
|
if (csym != NULL)
|
2008-10-19 21:43:36 +00:00
|
|
|
{
|
|
|
|
switch(csym->ValueType)
|
|
|
|
{
|
|
|
|
case VAL_Int:
|
|
|
|
x = new FxConstant(csym->Value, pos);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VAL_Float:
|
|
|
|
x = new FxConstant(csym->Float, pos);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
pos.Message(MSG_ERROR, "Invalid constant '%s'\n", csym->SymbolName.GetChars());
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pos.Message(MSG_ERROR, "'%s' is not a constant\n", sym->SymbolName.GetChars());
|
|
|
|
x = NULL;
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2009-10-15 03:58:23 +00:00
|
|
|
ExpEmit FxConstant::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit out;
|
|
|
|
|
|
|
|
out.Konst = true;
|
|
|
|
if (value.Type == VAL_Int || value.Type == VAL_Sound || value.Type == VAL_Name || value.Type == VAL_Color)
|
|
|
|
{
|
|
|
|
out.RegType = REGT_INT;
|
|
|
|
out.RegNum = build->GetConstantInt(value.Int);
|
|
|
|
}
|
|
|
|
else if (value.Type == VAL_Float)
|
|
|
|
{
|
|
|
|
out.RegType = REGT_FLOAT;
|
|
|
|
out.RegNum = build->GetConstantFloat(value.Float);
|
|
|
|
}
|
|
|
|
else if (value.Type == VAL_Class || value.Type == VAL_Object)
|
|
|
|
{
|
|
|
|
out.RegType = REGT_POINTER;
|
|
|
|
out.RegNum = build->GetConstantAddress(value.pointer, ATAG_OBJECT);
|
|
|
|
}
|
|
|
|
else if (value.Type == VAL_State)
|
|
|
|
{
|
|
|
|
out.RegType = REGT_POINTER;
|
|
|
|
out.RegNum = build->GetConstantAddress(value.pointer, ATAG_STATE);
|
|
|
|
}
|
2009-10-17 01:38:54 +00:00
|
|
|
else if (value.Type == VAL_String)
|
|
|
|
{
|
|
|
|
out.RegType = REGT_STRING;
|
|
|
|
out.RegNum = build->GetConstantString(value.GetString());
|
|
|
|
}
|
2009-10-15 03:58:23 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Cannot emit needed constant");
|
|
|
|
out.RegType = REGT_NIL;
|
|
|
|
out.RegNum = 0;
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxIntCast::FxIntCast(FxExpression *x)
|
|
|
|
: FxExpression(x->ScriptPosition)
|
|
|
|
{
|
|
|
|
basex=x;
|
|
|
|
ValueType = VAL_Int;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxIntCast::~FxIntCast()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(basex);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxIntCast::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(basex, ctx);
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
if (basex->ValueType == VAL_Int)
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
2008-10-19 21:43:36 +00:00
|
|
|
FxExpression *x = basex;
|
|
|
|
basex = NULL;
|
2008-10-18 17:17:44 +00:00
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
2008-10-19 21:43:36 +00:00
|
|
|
else if (basex->ValueType == VAL_Float)
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
2008-10-19 21:43:36 +00:00
|
|
|
if (basex->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
ExpVal constval = static_cast<FxConstant *>(basex)->GetValue();
|
2008-10-19 21:43:36 +00:00
|
|
|
FxExpression *x = new FxConstant(constval.GetInt(), ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
2008-10-18 17:17:44 +00:00
|
|
|
delete this;
|
2008-10-19 21:43:36 +00:00
|
|
|
return NULL;
|
2008-10-18 17:17:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxIntCast::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit from = basex->Emit(build);
|
|
|
|
assert(!from.Konst);
|
|
|
|
assert(basex->ValueType == VAL_Float);
|
|
|
|
ExpEmit to(build, REGT_INT);
|
|
|
|
build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_F2I);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxFloatCast::FxFloatCast(FxExpression *x)
|
|
|
|
: FxExpression(x->ScriptPosition)
|
|
|
|
{
|
|
|
|
basex=x;
|
|
|
|
ValueType = VAL_Float;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxFloatCast::~FxFloatCast()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(basex);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxFloatCast::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(basex, ctx);
|
|
|
|
|
|
|
|
if (basex->ValueType == VAL_Float)
|
|
|
|
{
|
|
|
|
FxExpression *x = basex;
|
|
|
|
basex = NULL;
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
else if (basex->ValueType == VAL_Int)
|
|
|
|
{
|
|
|
|
if (basex->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
ExpVal constval = static_cast<FxConstant *>(basex)->GetValue();
|
2009-10-11 00:02:14 +00:00
|
|
|
FxExpression *x = new FxConstant(constval.GetFloat(), ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
ExpEmit FxFloatCast::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit from = basex->Emit(build);
|
|
|
|
assert(!from.Konst);
|
|
|
|
assert(basex->ValueType == VAL_Int);
|
2009-10-15 23:11:54 +00:00
|
|
|
from.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit to(build, REGT_FLOAT);
|
|
|
|
build->Emit(OP_CAST, to.RegNum, from.RegNum, CAST_I2F);
|
|
|
|
return to;
|
|
|
|
}
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxPlusSign::FxPlusSign(FxExpression *operand)
|
|
|
|
: FxExpression(operand->ScriptPosition)
|
|
|
|
{
|
|
|
|
Operand=operand;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxPlusSign::~FxPlusSign()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(Operand);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxPlusSign::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(Operand, ctx);
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
if (Operand->ValueType.isNumeric())
|
|
|
|
{
|
|
|
|
FxExpression *e = Operand;
|
|
|
|
Operand = NULL;
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-10-18 17:17:44 +00:00
|
|
|
}
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxPlusSign::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
return Operand->Emit(build);
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxMinusSign::FxMinusSign(FxExpression *operand)
|
|
|
|
: FxExpression(operand->ScriptPosition)
|
|
|
|
{
|
|
|
|
Operand=operand;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxMinusSign::~FxMinusSign()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(Operand);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxMinusSign::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(Operand, ctx);
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
if (Operand->ValueType.isNumeric())
|
|
|
|
{
|
|
|
|
if (Operand->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
ExpVal val = static_cast<FxConstant *>(Operand)->GetValue();
|
2008-10-19 21:43:36 +00:00
|
|
|
FxExpression *e = val.Type == VAL_Int?
|
|
|
|
new FxConstant(-val.Int, ScriptPosition) :
|
|
|
|
new FxConstant(-val.Float, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
ValueType = Operand->ValueType;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
else
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
2008-10-19 21:43:36 +00:00
|
|
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
2008-10-18 17:17:44 +00:00
|
|
|
delete this;
|
2008-10-19 21:43:36 +00:00
|
|
|
return NULL;
|
2008-10-18 17:17:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
assert(ValueType.Type == Operand->ValueType.Type);
|
|
|
|
ExpEmit from = Operand->Emit(build);
|
2012-10-18 03:19:27 +00:00
|
|
|
assert(from.Konst == 0);
|
2009-10-11 00:02:14 +00:00
|
|
|
// Do it in-place.
|
|
|
|
if (ValueType == VAL_Int)
|
|
|
|
{
|
|
|
|
build->Emit(OP_NEG, from.RegNum, from.RegNum, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(ValueType == VAL_Float);
|
|
|
|
build->Emit(OP_NEG, from.RegNum, from.RegNum, 0);
|
|
|
|
}
|
|
|
|
return from;
|
|
|
|
}
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxUnaryNotBitwise::FxUnaryNotBitwise(FxExpression *operand)
|
|
|
|
: FxExpression(operand->ScriptPosition)
|
|
|
|
{
|
|
|
|
Operand=operand;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxUnaryNotBitwise::~FxUnaryNotBitwise()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(Operand);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxUnaryNotBitwise::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(Operand, ctx);
|
|
|
|
|
2013-08-03 02:13:40 +00:00
|
|
|
if (Operand->ValueType == VAL_Float /* lax */)
|
2008-10-19 21:43:36 +00:00
|
|
|
{
|
|
|
|
// DECORATE allows floats here so cast them to int.
|
|
|
|
Operand = new FxIntCast(Operand);
|
|
|
|
Operand = Operand->Resolve(ctx);
|
|
|
|
if (Operand == NULL)
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
if (Operand->ValueType != VAL_Int)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Integer type expected");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Operand->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
int result = ~static_cast<FxConstant *>(Operand)->GetValue().GetInt();
|
2008-10-18 17:17:44 +00:00
|
|
|
FxExpression *e = new FxConstant(result, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
ValueType = VAL_Int;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxUnaryNotBitwise::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
assert(ValueType.Type == Operand->ValueType.Type);
|
|
|
|
assert(ValueType == VAL_Int);
|
|
|
|
ExpEmit from = Operand->Emit(build);
|
2012-10-18 03:19:27 +00:00
|
|
|
assert(from.Konst == 0);
|
2009-10-11 00:02:14 +00:00
|
|
|
// Do it in-place.
|
|
|
|
build->Emit(OP_NOT, from.RegNum, from.RegNum, 0);
|
|
|
|
return from;
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxUnaryNotBoolean::FxUnaryNotBoolean(FxExpression *operand)
|
|
|
|
: FxExpression(operand->ScriptPosition)
|
|
|
|
{
|
|
|
|
Operand=operand;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxUnaryNotBoolean::~FxUnaryNotBoolean()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(Operand);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxUnaryNotBoolean::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
if (Operand)
|
2010-11-08 00:01:21 +00:00
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
|
|
|
Operand = Operand->ResolveAsBoolean(ctx);
|
|
|
|
}
|
|
|
|
if (!Operand)
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
if (Operand->ValueType.isNumeric() || Operand->ValueType.isPointer())
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
2008-10-19 21:43:36 +00:00
|
|
|
if (Operand->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
bool result = !static_cast<FxConstant *>(Operand)->GetValue().GetBool();
|
2008-10-19 21:43:36 +00:00
|
|
|
FxExpression *e = new FxConstant(result, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
2008-10-18 17:17:44 +00:00
|
|
|
delete this;
|
2008-10-19 21:43:36 +00:00
|
|
|
return NULL;
|
2008-10-18 17:17:44 +00:00
|
|
|
}
|
|
|
|
ValueType = VAL_Int;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit from = Operand->Emit(build);
|
2009-10-15 23:11:54 +00:00
|
|
|
assert(!from.Konst);
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit to(build, REGT_INT);
|
2009-10-15 23:11:54 +00:00
|
|
|
from.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
|
|
|
|
// Preload result with 0.
|
|
|
|
build->Emit(OP_LI, to.RegNum, 0, 0);
|
|
|
|
|
|
|
|
// Check source against 0.
|
|
|
|
if (from.RegType == REGT_INT)
|
|
|
|
{
|
|
|
|
build->Emit(OP_EQ_R, 0, from.RegNum, to.RegNum);
|
|
|
|
}
|
|
|
|
else if (from.RegType == REGT_FLOAT)
|
|
|
|
{
|
|
|
|
build->Emit(OP_EQF_K, 0, from.RegNum, build->GetConstantFloat(0));
|
|
|
|
}
|
|
|
|
else if (from.RegNum == REGT_POINTER)
|
|
|
|
{
|
|
|
|
build->Emit(OP_EQA_K, 0, from.RegNum, build->GetConstantAddress(NULL, ATAG_GENERIC));
|
|
|
|
}
|
|
|
|
build->Emit(OP_JMP, 1);
|
|
|
|
|
|
|
|
// Reload result with 1 if the comparison fell through.
|
|
|
|
build->Emit(OP_LI, to.RegNum, 1);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxBinary::FxBinary(int o, FxExpression *l, FxExpression *r)
|
|
|
|
: FxExpression(l->ScriptPosition)
|
|
|
|
{
|
|
|
|
Operator=o;
|
|
|
|
left=l;
|
|
|
|
right=r;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxBinary::~FxBinary()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(left);
|
|
|
|
SAFE_DELETE(right);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
bool FxBinary::ResolveLR(FCompileContext& ctx, bool castnumeric)
|
|
|
|
{
|
|
|
|
RESOLVE(left, ctx);
|
|
|
|
RESOLVE(right, ctx);
|
|
|
|
if (!left || !right)
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
if (left->ValueType == VAL_Int && right->ValueType == VAL_Int)
|
|
|
|
{
|
|
|
|
ValueType = VAL_Int;
|
|
|
|
}
|
|
|
|
else if (left->ValueType.isNumeric() && right->ValueType.isNumeric())
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
|
|
|
ValueType = VAL_Float;
|
|
|
|
}
|
2008-10-19 21:43:36 +00:00
|
|
|
else if (left->ValueType == VAL_Object && right->ValueType == VAL_Object)
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
2008-10-19 21:43:36 +00:00
|
|
|
ValueType = VAL_Object;
|
|
|
|
}
|
|
|
|
else if (left->ValueType == VAL_Class && right->ValueType == VAL_Class)
|
|
|
|
{
|
|
|
|
ValueType = VAL_Class;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ValueType = VAL_Unknown;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (castnumeric)
|
|
|
|
{
|
|
|
|
// later!
|
2008-10-18 17:17:44 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-10-15 03:58:23 +00:00
|
|
|
void FxBinary::Promote(FCompileContext &ctx)
|
2009-10-11 00:02:14 +00:00
|
|
|
{
|
|
|
|
if (left->ValueType == VAL_Float && right->ValueType == VAL_Int)
|
|
|
|
{
|
2009-10-15 03:58:23 +00:00
|
|
|
right = (new FxFloatCast(right))->Resolve(ctx);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
else if (left->ValueType == VAL_Int && right->ValueType == VAL_Float)
|
|
|
|
{
|
2009-10-15 03:58:23 +00:00
|
|
|
left = (new FxFloatCast(left))->Resolve(ctx);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
}
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxAddSub::FxAddSub(int o, FxExpression *l, FxExpression *r)
|
|
|
|
: FxBinary(o, l, r)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxAddSub::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
if (!ResolveLR(ctx, true)) return NULL;
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
if (!ValueType.isNumeric())
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (left->isConstant() && right->isConstant())
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
|
|
|
if (ValueType == VAL_Float)
|
|
|
|
{
|
|
|
|
double v;
|
2013-07-31 03:52:27 +00:00
|
|
|
double v1 = static_cast<FxConstant *>(left)->GetValue().GetFloat();
|
|
|
|
double v2 = static_cast<FxConstant *>(right)->GetValue().GetFloat();
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
v = Operator == '+'? v1 + v2 :
|
|
|
|
Operator == '-'? v1 - v2 : 0;
|
|
|
|
|
|
|
|
FxExpression *e = new FxConstant(v, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int v;
|
2013-07-31 03:52:27 +00:00
|
|
|
int v1 = static_cast<FxConstant *>(left)->GetValue().GetInt();
|
|
|
|
int v2 = static_cast<FxConstant *>(right)->GetValue().GetInt();
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
v = Operator == '+'? v1 + v2 :
|
|
|
|
Operator == '-'? v1 - v2 : 0;
|
|
|
|
|
|
|
|
FxExpression *e = new FxConstant(v, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2009-10-15 03:58:23 +00:00
|
|
|
Promote(ctx);
|
2008-10-18 17:17:44 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxAddSub::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
assert(Operator == '+' || Operator == '-');
|
|
|
|
ExpEmit op1 = left->Emit(build);
|
|
|
|
ExpEmit op2 = right->Emit(build);
|
|
|
|
if (Operator == '+')
|
|
|
|
{
|
|
|
|
// Since addition is commutative, only the second operand may be a constant.
|
|
|
|
if (op1.Konst)
|
|
|
|
{
|
2010-09-16 03:14:32 +00:00
|
|
|
swapvalues(op1, op2);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
assert(!op1.Konst);
|
2009-10-15 23:11:54 +00:00
|
|
|
op1.Free(build);
|
|
|
|
op2.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
if (ValueType == VAL_Float)
|
|
|
|
{
|
|
|
|
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
|
|
|
|
ExpEmit to(build, REGT_FLOAT);
|
|
|
|
build->Emit(op2.Konst ? OP_ADDF_RK : OP_ADDF_RR, to.RegNum, op1.RegNum, op2.RegNum);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(ValueType == VAL_Int);
|
|
|
|
assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT);
|
|
|
|
ExpEmit to(build, REGT_INT);
|
|
|
|
build->Emit(op2.Konst ? OP_ADD_RK : OP_ADD_RR, to.RegNum, op1.RegNum, op2.RegNum);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Subtraction is not commutative, so either side may be constant (but not both).
|
|
|
|
assert(!op1.Konst || !op2.Konst);
|
2009-10-15 23:11:54 +00:00
|
|
|
op1.Free(build);
|
|
|
|
op2.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
if (ValueType == VAL_Float)
|
|
|
|
{
|
|
|
|
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
|
|
|
|
ExpEmit to(build, REGT_FLOAT);
|
|
|
|
build->Emit(op1.Konst ? OP_SUBF_KR : op2.Konst ? OP_SUBF_RK : OP_SUBF_RR,
|
|
|
|
to.RegNum, op1.RegNum, op2.RegNum);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(ValueType == VAL_Int);
|
|
|
|
assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT);
|
|
|
|
ExpEmit to(build, REGT_INT);
|
|
|
|
build->Emit(op1.Konst ? OP_SUB_KR : op2.Konst ? OP_SUB_RK : OP_SUB_RR,
|
|
|
|
to.RegNum, op1.RegNum, op2.RegNum);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxMulDiv::FxMulDiv(int o, FxExpression *l, FxExpression *r)
|
|
|
|
: FxBinary(o, l, r)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxMulDiv::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
|
|
|
|
if (!ResolveLR(ctx, true)) return NULL;
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
if (!ValueType.isNumeric())
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (left->isConstant() && right->isConstant())
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
|
|
|
if (ValueType == VAL_Float)
|
|
|
|
{
|
|
|
|
double v;
|
2013-07-31 03:52:27 +00:00
|
|
|
double v1 = static_cast<FxConstant *>(left)->GetValue().GetFloat();
|
|
|
|
double v2 = static_cast<FxConstant *>(right)->GetValue().GetFloat();
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
if (Operator != '*' && v2 == 0)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Division by 0");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
v = Operator == '*'? v1 * v2 :
|
|
|
|
Operator == '/'? v1 / v2 :
|
|
|
|
Operator == '%'? fmod(v1, v2) : 0;
|
|
|
|
|
|
|
|
FxExpression *e = new FxConstant(v, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int v;
|
2013-07-31 03:52:27 +00:00
|
|
|
int v1 = static_cast<FxConstant *>(left)->GetValue().GetInt();
|
|
|
|
int v2 = static_cast<FxConstant *>(right)->GetValue().GetInt();
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
if (Operator != '*' && v2 == 0)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Division by 0");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
v = Operator == '*'? v1 * v2 :
|
|
|
|
Operator == '/'? v1 / v2 :
|
|
|
|
Operator == '%'? v1 % v2 : 0;
|
|
|
|
|
|
|
|
FxExpression *e = new FxConstant(v, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2009-10-15 03:58:23 +00:00
|
|
|
Promote(ctx);
|
2008-10-18 17:17:44 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxMulDiv::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit op1 = left->Emit(build);
|
|
|
|
ExpEmit op2 = right->Emit(build);
|
|
|
|
|
|
|
|
if (Operator == '*')
|
|
|
|
{
|
|
|
|
// Multiplication is commutative, so only the second operand may be constant.
|
|
|
|
if (op1.Konst)
|
|
|
|
{
|
2010-09-16 03:14:32 +00:00
|
|
|
swapvalues(op1, op2);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
assert(!op1.Konst);
|
2009-10-15 23:11:54 +00:00
|
|
|
op1.Free(build);
|
|
|
|
op2.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
if (ValueType == VAL_Float)
|
|
|
|
{
|
|
|
|
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
|
|
|
|
ExpEmit to(build, REGT_FLOAT);
|
|
|
|
build->Emit(op2.Konst ? OP_MULF_RK : OP_MULF_RR, to.RegNum, op1.RegNum, op2.RegNum);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(ValueType == VAL_Int);
|
|
|
|
assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT);
|
|
|
|
ExpEmit to(build, REGT_INT);
|
|
|
|
build->Emit(op2.Konst ? OP_MUL_RK : OP_MUL_RR, to.RegNum, op1.RegNum, op2.RegNum);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Division is not commutative, so either side may be constant (but not both).
|
|
|
|
assert(!op1.Konst || !op2.Konst);
|
|
|
|
assert(Operator == '%' || Operator == '/');
|
2009-10-15 23:11:54 +00:00
|
|
|
op1.Free(build);
|
|
|
|
op2.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
if (ValueType == VAL_Float)
|
|
|
|
{
|
|
|
|
assert(op1.RegType == REGT_FLOAT && op2.RegType == REGT_FLOAT);
|
|
|
|
ExpEmit to(build, REGT_FLOAT);
|
|
|
|
build->Emit(Operator == '/' ? (op1.Konst ? OP_DIVF_KR : op2.Konst ? OP_DIVF_RK : OP_DIVF_RR)
|
|
|
|
: (op1.Konst ? OP_MODF_KR : op2.Konst ? OP_MODF_RK : OP_MODF_RR),
|
|
|
|
to.RegNum, op1.RegNum, op2.RegNum);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(ValueType == VAL_Int);
|
|
|
|
assert(op1.RegType == REGT_INT && op2.RegType == REGT_INT);
|
|
|
|
ExpEmit to(build, REGT_INT);
|
|
|
|
build->Emit(Operator == '/' ? (op1.Konst ? OP_DIV_KR : op2.Konst ? OP_DIV_RK : OP_DIV_RR)
|
|
|
|
: (op1.Konst ? OP_MOD_KR : op2.Konst ? OP_MOD_RK : OP_MOD_RR),
|
|
|
|
to.RegNum, op1.RegNum, op2.RegNum);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxCompareRel::FxCompareRel(int o, FxExpression *l, FxExpression *r)
|
|
|
|
: FxBinary(o, l, r)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
2012-07-07 03:43:11 +00:00
|
|
|
if (!ResolveLR(ctx, true)) return NULL;
|
2008-10-18 17:17:44 +00:00
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
if (!ValueType.isNumeric())
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (left->isConstant() && right->isConstant())
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
|
|
|
int v;
|
|
|
|
|
|
|
|
if (ValueType == VAL_Float)
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
double v1 = static_cast<FxConstant *>(left)->GetValue().GetFloat();
|
|
|
|
double v2 = static_cast<FxConstant *>(right)->GetValue().GetFloat();
|
2008-10-18 17:17:44 +00:00
|
|
|
v = Operator == '<'? v1 < v2 :
|
|
|
|
Operator == '>'? v1 > v2 :
|
|
|
|
Operator == TK_Geq? v1 >= v2 :
|
|
|
|
Operator == TK_Leq? v1 <= v2 : 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
int v1 = static_cast<FxConstant *>(left)->GetValue().GetInt();
|
|
|
|
int v2 = static_cast<FxConstant *>(right)->GetValue().GetInt();
|
2008-10-18 17:17:44 +00:00
|
|
|
v = Operator == '<'? v1 < v2 :
|
|
|
|
Operator == '>'? v1 > v2 :
|
|
|
|
Operator == TK_Geq? v1 >= v2 :
|
|
|
|
Operator == TK_Leq? v1 <= v2 : 0;
|
|
|
|
}
|
|
|
|
FxExpression *e = new FxConstant(v, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
}
|
2009-10-15 03:58:23 +00:00
|
|
|
Promote(ctx);
|
2008-10-18 17:17:44 +00:00
|
|
|
ValueType = VAL_Int;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxCompareRel::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit op1 = left->Emit(build);
|
|
|
|
ExpEmit op2 = right->Emit(build);
|
|
|
|
assert(op1.RegType == op2.RegType);
|
|
|
|
assert(op1.RegType == REGT_INT || op1.RegType == REGT_FLOAT);
|
|
|
|
assert(!op1.Konst || !op2.Konst);
|
|
|
|
assert(Operator == '<' || Operator == '>' || Operator == TK_Geq || Operator == TK_Leq);
|
|
|
|
static const VM_UBYTE InstrMap[][4] =
|
|
|
|
{
|
|
|
|
{ OP_LT_RR, OP_LTF_RR, 0 }, // <
|
|
|
|
{ OP_LE_RR, OP_LEF_RR, 1 }, // >
|
|
|
|
{ OP_LT_RR, OP_LTF_RR, 1 }, // >=
|
2012-10-18 04:04:33 +00:00
|
|
|
{ OP_LE_RR, OP_LEF_RR, 0 } // <=
|
2009-10-11 00:02:14 +00:00
|
|
|
};
|
|
|
|
int instr, check, index;
|
2012-10-23 03:19:26 +00:00
|
|
|
ExpEmit to(build, REGT_INT);
|
2009-10-11 00:02:14 +00:00
|
|
|
|
|
|
|
index = Operator == '<' ? 0 :
|
|
|
|
Operator == '>' ? 1 :
|
|
|
|
Operator == TK_Geq ? 2 : 3;
|
|
|
|
instr = InstrMap[index][op1.RegType == REGT_INT ? 0 : 1];
|
|
|
|
check = InstrMap[index][2];
|
|
|
|
if (op2.Konst)
|
|
|
|
{
|
|
|
|
instr += 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-15 23:11:54 +00:00
|
|
|
op2.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
if (op1.Konst)
|
|
|
|
{
|
|
|
|
instr += 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-15 23:11:54 +00:00
|
|
|
op1.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// See FxUnaryNotBoolean for comments, since it's the same thing.
|
|
|
|
build->Emit(OP_LI, to.RegNum, 0, 0);
|
|
|
|
build->Emit(instr, check, op1.RegNum, op2.RegNum);
|
|
|
|
build->Emit(OP_JMP, 1);
|
|
|
|
build->Emit(OP_LI, to.RegNum, 1);
|
|
|
|
return to;
|
|
|
|
}
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxCompareEq::FxCompareEq(int o, FxExpression *l, FxExpression *r)
|
|
|
|
: FxBinary(o, l, r)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
|
2012-07-07 03:43:11 +00:00
|
|
|
if (!ResolveLR(ctx, true)) return NULL;
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
if (!left || !right)
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
if (!ValueType.isNumeric() && !ValueType.isPointer())
|
|
|
|
{
|
2008-10-25 17:38:00 +00:00
|
|
|
if (left->ValueType.Type == right->ValueType.Type)
|
|
|
|
{
|
|
|
|
// compare other types?
|
|
|
|
if (left->ValueType == VAL_Sound || left->ValueType == VAL_Color || left->ValueType == VAL_Name)
|
|
|
|
{
|
|
|
|
left->ValueType = right->ValueType = VAL_Int;
|
|
|
|
goto cont;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-10-25 17:38:00 +00:00
|
|
|
cont:
|
|
|
|
if (left->isConstant() && right->isConstant())
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
|
|
|
int v;
|
|
|
|
|
|
|
|
if (ValueType == VAL_Float)
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
double v1 = static_cast<FxConstant *>(left)->GetValue().GetFloat();
|
|
|
|
double v2 = static_cast<FxConstant *>(right)->GetValue().GetFloat();
|
2008-10-18 17:17:44 +00:00
|
|
|
v = Operator == TK_Eq? v1 == v2 : v1 != v2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
int v1 = static_cast<FxConstant *>(left)->GetValue().GetInt();
|
|
|
|
int v2 = static_cast<FxConstant *>(right)->GetValue().GetInt();
|
2008-10-18 17:17:44 +00:00
|
|
|
v = Operator == TK_Eq? v1 == v2 : v1 != v2;
|
|
|
|
}
|
|
|
|
FxExpression *e = new FxConstant(v, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
}
|
2009-10-15 03:58:23 +00:00
|
|
|
Promote(ctx);
|
2008-10-18 17:17:44 +00:00
|
|
|
ValueType = VAL_Int;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxCompareEq::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit op1 = left->Emit(build);
|
|
|
|
ExpEmit op2 = right->Emit(build);
|
|
|
|
assert(op1.RegType == op2.RegType);
|
|
|
|
assert(op1.RegType == REGT_INT || op1.RegType == REGT_FLOAT || op1.RegType == REGT_POINTER);
|
|
|
|
int instr;
|
|
|
|
|
|
|
|
// Only the second operand may be constant.
|
|
|
|
if (op1.Konst)
|
|
|
|
{
|
2010-09-16 03:14:32 +00:00
|
|
|
swapvalues(op1, op2);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
assert(!op1.Konst);
|
|
|
|
|
2012-10-26 20:27:49 +00:00
|
|
|
ExpEmit to(build, REGT_INT);
|
2012-10-25 03:56:09 +00:00
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
instr = op1.RegType == REGT_INT ? OP_EQ_R :
|
|
|
|
op1.RegType == REGT_FLOAT ? OP_EQF_R :
|
|
|
|
OP_EQA_R;
|
2009-10-15 23:11:54 +00:00
|
|
|
op1.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
if (!op2.Konst)
|
|
|
|
{
|
2009-10-15 23:11:54 +00:00
|
|
|
op2.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
instr += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// See FxUnaryNotBoolean for comments, since it's the same thing.
|
|
|
|
build->Emit(OP_LI, to.RegNum, 0, 0);
|
|
|
|
build->Emit(instr, Operator != TK_Eq, op1.RegNum, op2.RegNum);
|
|
|
|
build->Emit(OP_JMP, 1);
|
|
|
|
build->Emit(OP_LI, to.RegNum, 1);
|
|
|
|
return to;
|
|
|
|
}
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxBinaryInt::FxBinaryInt(int o, FxExpression *l, FxExpression *r)
|
|
|
|
: FxBinary(o, l, r)
|
|
|
|
{
|
|
|
|
ValueType = VAL_Int;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxBinaryInt::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
2012-07-07 03:43:11 +00:00
|
|
|
if (!ResolveLR(ctx, false)) return NULL;
|
2008-10-18 17:17:44 +00:00
|
|
|
|
2013-08-03 02:13:40 +00:00
|
|
|
if (ValueType == VAL_Float /* lax */)
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
2008-10-19 21:43:36 +00:00
|
|
|
// For DECORATE which allows floats here.
|
|
|
|
if (left->ValueType != VAL_Int)
|
|
|
|
{
|
|
|
|
left = new FxIntCast(left);
|
|
|
|
left = left->Resolve(ctx);
|
|
|
|
}
|
|
|
|
if (right->ValueType != VAL_Int)
|
|
|
|
{
|
|
|
|
right = new FxIntCast(right);
|
2013-05-13 02:55:48 +00:00
|
|
|
right = right->Resolve(ctx);
|
2008-10-19 21:43:36 +00:00
|
|
|
}
|
|
|
|
if (left == NULL || right == NULL)
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ValueType = VAL_Int;
|
2008-10-18 17:17:44 +00:00
|
|
|
}
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
if (ValueType != VAL_Int)
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
2008-10-19 21:43:36 +00:00
|
|
|
ScriptPosition.Message(MSG_ERROR, "Integer type expected");
|
2008-10-18 17:17:44 +00:00
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-10-19 21:43:36 +00:00
|
|
|
else if (left->isConstant() && right->isConstant())
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
int v1 = static_cast<FxConstant *>(left)->GetValue().GetInt();
|
|
|
|
int v2 = static_cast<FxConstant *>(right)->GetValue().GetInt();
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
FxExpression *e = new FxConstant(
|
|
|
|
Operator == TK_LShift? v1 << v2 :
|
|
|
|
Operator == TK_RShift? v1 >> v2 :
|
2008-10-18 21:45:51 +00:00
|
|
|
Operator == TK_URShift? int((unsigned int)(v1) >> v2) :
|
2008-10-18 17:17:44 +00:00
|
|
|
Operator == '&'? v1 & v2 :
|
|
|
|
Operator == '|'? v1 | v2 :
|
|
|
|
Operator == '^'? v1 ^ v2 : 0, ScriptPosition);
|
|
|
|
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxBinaryInt::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
assert(left->ValueType == VAL_Int);
|
|
|
|
assert(right->ValueType == VAL_Int);
|
|
|
|
static const VM_UBYTE InstrMap[][4] =
|
|
|
|
{
|
|
|
|
{ OP_SLL_RR, OP_SLL_KR, OP_SLL_RI }, // TK_LShift
|
|
|
|
{ OP_SRA_RR, OP_SRA_KR, OP_SRA_RI }, // TK_RShift
|
|
|
|
{ OP_SRL_RR, OP_SRL_KR, OP_SRL_RI }, // TK_URShift
|
|
|
|
{ OP_AND_RR, 0, OP_AND_RK }, // '&'
|
|
|
|
{ OP_OR_RR, 0, OP_OR_RK }, // '|'
|
|
|
|
{ OP_XOR_RR, 0, OP_XOR_RK }, // '^'
|
|
|
|
};
|
|
|
|
int index, instr, rop;
|
|
|
|
ExpEmit op1, op2;
|
|
|
|
|
|
|
|
index = Operator == TK_LShift ? 0 :
|
|
|
|
Operator == TK_RShift ? 1 :
|
|
|
|
Operator == TK_URShift ? 2 :
|
|
|
|
Operator == '&' ? 3 :
|
|
|
|
Operator == '|' ? 4 :
|
|
|
|
Operator == '^' ? 5 : -1;
|
|
|
|
assert(index >= 0);
|
|
|
|
op1 = left->Emit(build);
|
|
|
|
if (index < 3)
|
|
|
|
{ // Shift instructions use right-hand immediates instead of constant registers.
|
|
|
|
if (right->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
rop = static_cast<FxConstant *>(right)->GetValue().GetInt();
|
2009-10-11 00:02:14 +00:00
|
|
|
op2.Konst = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
op2 = right->Emit(build);
|
|
|
|
assert(!op2.Konst);
|
2009-10-15 23:11:54 +00:00
|
|
|
op2.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
rop = op2.RegNum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // The other operators only take a constant on the right-hand side.
|
|
|
|
op2 = right->Emit(build);
|
|
|
|
if (op1.Konst)
|
|
|
|
{
|
2010-09-16 03:14:32 +00:00
|
|
|
swapvalues(op1, op2);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
assert(!op1.Konst);
|
|
|
|
rop = op2.RegNum;
|
2009-10-15 23:11:54 +00:00
|
|
|
op2.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
if (!op1.Konst)
|
|
|
|
{
|
2009-10-15 23:11:54 +00:00
|
|
|
op1.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
if (!op2.Konst)
|
|
|
|
{
|
|
|
|
instr = InstrMap[index][0];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
instr = InstrMap[index][2];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(!op2.Konst);
|
|
|
|
instr = InstrMap[index][1];
|
|
|
|
}
|
|
|
|
assert(instr != 0);
|
|
|
|
ExpEmit to(build, REGT_INT);
|
|
|
|
build->Emit(instr, to.RegNum, op1.RegNum, rop);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxBinaryLogical::FxBinaryLogical(int o, FxExpression *l, FxExpression *r)
|
|
|
|
: FxExpression(l->ScriptPosition)
|
|
|
|
{
|
|
|
|
Operator=o;
|
|
|
|
left=l;
|
|
|
|
right=r;
|
|
|
|
ValueType = VAL_Int;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxBinaryLogical::~FxBinaryLogical()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(left);
|
|
|
|
SAFE_DELETE(right);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
if (left) left = left->ResolveAsBoolean(ctx);
|
|
|
|
if (right) right = right->ResolveAsBoolean(ctx);
|
|
|
|
if (!left || !right)
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int b_left=-1, b_right=-1;
|
|
|
|
|
2013-07-31 03:52:27 +00:00
|
|
|
if (left->isConstant()) b_left = static_cast<FxConstant *>(left)->GetValue().GetBool();
|
|
|
|
if (right->isConstant()) b_right = static_cast<FxConstant *>(right)->GetValue().GetBool();
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
// Do some optimizations. This will throw out all sub-expressions that are not
|
|
|
|
// needed to retrieve the final result.
|
|
|
|
if (Operator == TK_AndAnd)
|
|
|
|
{
|
|
|
|
if (b_left==0 || b_right==0)
|
|
|
|
{
|
|
|
|
FxExpression *x = new FxConstant(0, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
else if (b_left==1 && b_right==1)
|
|
|
|
{
|
|
|
|
FxExpression *x = new FxConstant(1, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
else if (b_left==1)
|
|
|
|
{
|
|
|
|
FxExpression *x = right;
|
|
|
|
right=NULL;
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
else if (b_right==1)
|
|
|
|
{
|
|
|
|
FxExpression *x = left;
|
|
|
|
left=NULL;
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (Operator == TK_OrOr)
|
|
|
|
{
|
|
|
|
if (b_left==1 || b_right==1)
|
|
|
|
{
|
|
|
|
FxExpression *x = new FxConstant(1, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
if (b_left==0 && b_right==0)
|
|
|
|
{
|
|
|
|
FxExpression *x = new FxConstant(0, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
else if (b_left==0)
|
|
|
|
{
|
|
|
|
FxExpression *x = right;
|
|
|
|
right=NULL;
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
else if (b_right==0)
|
|
|
|
{
|
|
|
|
FxExpression *x = left;
|
|
|
|
left=NULL;
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
}
|
2009-10-11 00:02:14 +00:00
|
|
|
if (left->ValueType != VAL_Int && left->ValueType != VAL_Sound)
|
|
|
|
{
|
|
|
|
left = new FxIntCast(left);
|
|
|
|
}
|
|
|
|
if (right->ValueType != VAL_Int && right->ValueType != VAL_Sound)
|
|
|
|
{
|
|
|
|
right = new FxIntCast(right);
|
|
|
|
}
|
2008-10-18 17:17:44 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
// This is not the "right" way to do these, but it works for now.
|
|
|
|
// (Problem: No information sharing is done between nodes to reduce the
|
|
|
|
// code size if you have something like a1 && a2 && a3 && ... && an.)
|
|
|
|
assert(left->ValueType == VAL_Int && right->ValueType == VAL_Int);
|
|
|
|
ExpEmit op1 = left->Emit(build);
|
|
|
|
assert(!op1.Konst);
|
|
|
|
int zero = build->GetConstantInt(0);
|
2009-10-15 23:11:54 +00:00
|
|
|
op1.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
|
|
|
|
if (Operator == TK_AndAnd)
|
|
|
|
{
|
|
|
|
build->Emit(OP_EQ_K, 1, op1.RegNum, zero);
|
|
|
|
// If op1 is 0, skip evaluation of op2.
|
|
|
|
size_t patchspot = build->Emit(OP_JMP, 0, 0, 0);
|
|
|
|
|
|
|
|
// Evaluate op2.
|
|
|
|
ExpEmit op2 = right->Emit(build);
|
|
|
|
assert(!op2.Konst);
|
2009-10-15 23:11:54 +00:00
|
|
|
op2.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
|
|
|
|
ExpEmit to(build, REGT_INT);
|
|
|
|
build->Emit(OP_EQ_K, 0, op2.RegNum, zero);
|
|
|
|
build->Emit(OP_JMP, 2);
|
|
|
|
build->Emit(OP_LI, to.RegNum, 1);
|
|
|
|
build->Emit(OP_JMP, 1);
|
|
|
|
size_t target = build->Emit(OP_LI, to.RegNum, 0);
|
|
|
|
build->Backpatch(patchspot, target);
|
|
|
|
return to;
|
|
|
|
}
|
|
|
|
else
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
2009-10-11 00:02:14 +00:00
|
|
|
assert(Operator == TK_OrOr);
|
|
|
|
build->Emit(OP_EQ_K, 0, op1.RegNum, zero);
|
|
|
|
// If op1 is not 0, skip evaluation of op2.
|
|
|
|
size_t patchspot = build->Emit(OP_JMP, 0, 0, 0);
|
|
|
|
|
|
|
|
// Evaluate op2.
|
|
|
|
ExpEmit op2 = right->Emit(build);
|
|
|
|
assert(!op2.Konst);
|
2009-10-15 23:11:54 +00:00
|
|
|
op2.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
|
|
|
|
ExpEmit to(build, REGT_INT);
|
|
|
|
build->Emit(OP_EQ_K, 1, op2.RegNum, zero);
|
|
|
|
build->Emit(OP_JMP, 2);
|
|
|
|
build->Emit(OP_LI, to.RegNum, 0);
|
|
|
|
build->Emit(OP_JMP, 1);
|
|
|
|
size_t target = build->Emit(OP_LI, to.RegNum, 1);
|
|
|
|
build->Backpatch(patchspot, target);
|
|
|
|
return to;
|
2008-10-18 17:17:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxConditional::FxConditional(FxExpression *c, FxExpression *t, FxExpression *f)
|
|
|
|
: FxExpression(c->ScriptPosition)
|
|
|
|
{
|
|
|
|
condition = c;
|
|
|
|
truex=t;
|
|
|
|
falsex=f;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxConditional::~FxConditional()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(condition);
|
|
|
|
SAFE_DELETE(truex);
|
|
|
|
SAFE_DELETE(falsex);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxConditional::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
if (condition) condition = condition->ResolveAsBoolean(ctx);
|
|
|
|
RESOLVE(truex, ctx);
|
|
|
|
RESOLVE(falsex, ctx);
|
|
|
|
ABORT(condition && truex && falsex);
|
|
|
|
|
|
|
|
if (truex->ValueType == VAL_Int && falsex->ValueType == VAL_Int)
|
|
|
|
ValueType = VAL_Int;
|
2008-10-19 21:43:36 +00:00
|
|
|
else if (truex->ValueType.isNumeric() && falsex->ValueType.isNumeric())
|
2008-10-18 17:17:44 +00:00
|
|
|
ValueType = VAL_Float;
|
2008-10-19 21:43:36 +00:00
|
|
|
//else if (truex->ValueType != falsex->ValueType)
|
2008-10-18 17:17:44 +00:00
|
|
|
|
|
|
|
if (condition->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
ExpVal condval = static_cast<FxConstant *>(condition)->GetValue();
|
2008-10-18 17:17:44 +00:00
|
|
|
bool result = condval.GetBool();
|
|
|
|
|
|
|
|
FxExpression *e = result? truex:falsex;
|
|
|
|
delete (result? falsex:truex);
|
|
|
|
falsex = truex = NULL;
|
|
|
|
delete this;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
if (ValueType == VAL_Float)
|
|
|
|
{
|
|
|
|
if (truex->ValueType != VAL_Float)
|
|
|
|
{
|
|
|
|
truex = new FxFloatCast(truex);
|
|
|
|
RESOLVE(truex, ctx);
|
|
|
|
}
|
|
|
|
if (falsex->ValueType != VAL_Float)
|
|
|
|
{
|
|
|
|
falsex = new FxFloatCast(falsex);
|
|
|
|
RESOLVE(falsex, ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxConditional::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit out;
|
|
|
|
|
|
|
|
// The true and false expressions ought to be assigned to the
|
|
|
|
// same temporary instead of being copied to it. Oh well; good enough
|
|
|
|
// for now.
|
|
|
|
ExpEmit cond = condition->Emit(build);
|
|
|
|
assert(cond.RegType == REGT_INT && !cond.Konst);
|
|
|
|
|
|
|
|
// Test condition.
|
|
|
|
build->Emit(OP_EQ_K, 1, cond.RegNum, build->GetConstantInt(0));
|
|
|
|
size_t patchspot = build->Emit(OP_JMP, 0);
|
|
|
|
|
|
|
|
// Evaluate true expression.
|
|
|
|
if (truex->isConstant() && truex->ValueType == VAL_Int)
|
|
|
|
{
|
|
|
|
out = ExpEmit(build, REGT_INT);
|
2013-07-31 03:52:27 +00:00
|
|
|
build->EmitLoadInt(out.RegNum, static_cast<FxConstant *>(truex)->GetValue().GetInt());
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ExpEmit trueop = truex->Emit(build);
|
|
|
|
if (trueop.Konst)
|
|
|
|
{
|
|
|
|
assert(trueop.RegType == REGT_FLOAT);
|
|
|
|
out = ExpEmit(build, REGT_FLOAT);
|
|
|
|
build->Emit(OP_LKF, out.RegNum, trueop.RegNum);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Use the register returned by the true condition as the
|
|
|
|
// target for the false condition.
|
|
|
|
out = trueop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Evaluate false expression.
|
|
|
|
build->BackpatchToHere(patchspot);
|
|
|
|
if (falsex->isConstant() && falsex->ValueType == VAL_Int)
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
build->EmitLoadInt(out.RegNum, static_cast<FxConstant *>(falsex)->GetValue().GetInt());
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ExpEmit falseop = falsex->Emit(build);
|
|
|
|
if (falseop.Konst)
|
|
|
|
{
|
|
|
|
assert(falseop.RegType == REGT_FLOAT);
|
|
|
|
build->Emit(OP_LKF, out.RegNum, falseop.RegNum);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Move result from the register returned by "false" to the one
|
|
|
|
// returned by "true" so that only one register is returned by
|
|
|
|
// this tree.
|
2009-10-15 23:11:54 +00:00
|
|
|
falseop.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
if (falseop.RegType == REGT_INT)
|
|
|
|
{
|
|
|
|
build->Emit(OP_MOVE, out.RegNum, falseop.RegNum, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(falseop.RegType == REGT_FLOAT);
|
|
|
|
build->Emit(OP_MOVEF, out.RegNum, falseop.RegNum, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
FxAbs::FxAbs(FxExpression *v)
|
|
|
|
: FxExpression(v->ScriptPosition)
|
|
|
|
{
|
|
|
|
val = v;
|
2008-10-19 21:43:36 +00:00
|
|
|
ValueType = v->ValueType;
|
2008-10-18 17:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxAbs::~FxAbs()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxAbs::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(val, ctx);
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
|
2011-03-24 04:14:27 +00:00
|
|
|
if (!val->ValueType.isNumeric())
|
2008-10-19 21:43:36 +00:00
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (val->isConstant())
|
2008-10-18 17:17:44 +00:00
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
ExpVal value = static_cast<FxConstant *>(val)->GetValue();
|
2008-10-18 17:17:44 +00:00
|
|
|
switch (value.Type)
|
|
|
|
{
|
|
|
|
case VAL_Int:
|
|
|
|
value.Int = abs(value.Int);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VAL_Float:
|
|
|
|
value.Float = fabs(value.Float);
|
|
|
|
|
|
|
|
default:
|
|
|
|
// shouldn't happen
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
FxExpression *x = new FxConstant(value, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
ValueType = val->ValueType;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxAbs::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit absofsteal = val->Emit(build);
|
|
|
|
assert(!absofsteal.Konst);
|
|
|
|
ExpEmit out(build, absofsteal.RegType);
|
|
|
|
if (absofsteal.RegType == REGT_INT)
|
|
|
|
{
|
|
|
|
build->Emit(OP_ABS, out.RegNum, absofsteal.RegNum, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(absofsteal.RegType == REGT_FLOAT);
|
|
|
|
build->Emit(OP_FLOP, out.RegNum, absofsteal.RegNum, FLOP_ABS);
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos)
|
|
|
|
: FxExpression(pos)
|
|
|
|
{
|
2008-12-07 12:11:59 +00:00
|
|
|
if (mi != NULL && ma != NULL)
|
|
|
|
{
|
2009-10-15 21:59:37 +00:00
|
|
|
min = new FxParameter(new FxIntCast(mi));
|
|
|
|
max = new FxParameter(new FxIntCast(ma));
|
2008-12-07 12:11:59 +00:00
|
|
|
}
|
|
|
|
else min = max = NULL;
|
2008-10-18 17:17:44 +00:00
|
|
|
rng = r;
|
|
|
|
ValueType = VAL_Int;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxRandom::~FxRandom()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(min);
|
|
|
|
SAFE_DELETE(max);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxRandom::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
if (min && max)
|
|
|
|
{
|
|
|
|
RESOLVE(min, ctx);
|
|
|
|
RESOLVE(max, ctx);
|
|
|
|
ABORT(min && max);
|
2012-07-14 03:10:47 +00:00
|
|
|
assert(min->ValueType == ValueType.Type);
|
|
|
|
assert(max->ValueType == ValueType.Type);
|
2008-10-18 17:17:44 +00:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
int DecoRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
|
|
|
{
|
|
|
|
assert(numparam >= 1 && numparam <= 3);
|
|
|
|
FRandom *rng = reinterpret_cast<FRandom *>(param[0].a);
|
|
|
|
if (numparam == 1)
|
|
|
|
{
|
|
|
|
ret->SetInt((*rng)());
|
|
|
|
}
|
|
|
|
else if (numparam == 2)
|
|
|
|
{
|
|
|
|
int maskval = param[1].i;
|
|
|
|
ret->SetInt(rng->Random2(maskval));
|
|
|
|
}
|
|
|
|
else if (numparam == 3)
|
|
|
|
{
|
|
|
|
int min = param[1].i, max = param[2].i;
|
|
|
|
if (max < min)
|
|
|
|
{
|
2010-09-16 03:14:32 +00:00
|
|
|
swapvalues(max, min);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
ret->SetInt((*rng)(max - min + 1) + min);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ExpEmit FxRandom::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
2012-10-26 04:04:06 +00:00
|
|
|
// Call DecoRandom to generate a random number.
|
2009-10-11 00:02:14 +00:00
|
|
|
VMFunction *callfunc;
|
2012-10-26 04:04:06 +00:00
|
|
|
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom);
|
|
|
|
|
2010-04-16 02:57:51 +00:00
|
|
|
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
2009-10-11 00:02:14 +00:00
|
|
|
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
|
|
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
|
|
|
|
|
|
|
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
|
|
|
|
if (min != NULL && max != NULL)
|
|
|
|
{
|
2009-10-15 21:59:37 +00:00
|
|
|
min->Emit(build);
|
|
|
|
max->Emit(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1);
|
|
|
|
}
|
|
|
|
ExpEmit out(build, REGT_INT);
|
|
|
|
build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2009-09-06 02:16:55 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos)
|
|
|
|
: FxRandom(r, NULL, NULL, pos)
|
|
|
|
{
|
|
|
|
if (mi != NULL && ma != NULL)
|
|
|
|
{
|
2009-10-15 21:59:37 +00:00
|
|
|
min = new FxParameter(new FxFloatCast(mi));
|
|
|
|
max = new FxParameter(new FxFloatCast(ma));
|
2009-09-06 02:16:55 +00:00
|
|
|
}
|
2012-07-01 03:16:37 +00:00
|
|
|
ValueType = VAL_Float;
|
2009-09-06 02:16:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
int DecoFRandom(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
|
|
|
{
|
|
|
|
assert(numparam == 1 || numparam == 3);
|
|
|
|
FRandom *rng = reinterpret_cast<FRandom *>(param[0].a);
|
|
|
|
|
|
|
|
int random = (*rng)(0x40000000);
|
|
|
|
double frandom = random / double(0x40000000);
|
|
|
|
|
|
|
|
if (numparam == 3)
|
|
|
|
{
|
|
|
|
double min = param[1].f, max = param[2].f;
|
|
|
|
if (max < min)
|
|
|
|
{
|
2010-09-16 03:14:32 +00:00
|
|
|
swapvalues(max, min);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
ret->SetFloat(frandom * (max - min) + min);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret->SetFloat(frandom);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ExpEmit FxFRandom::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
2012-10-26 04:04:06 +00:00
|
|
|
// Call the DecoFRandom function to generate a floating point random number..
|
2009-10-11 00:02:14 +00:00
|
|
|
VMFunction *callfunc;
|
2012-10-26 04:04:06 +00:00
|
|
|
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoFRandom, DecoFRandom);
|
|
|
|
|
2010-04-16 02:57:51 +00:00
|
|
|
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
2009-10-11 00:02:14 +00:00
|
|
|
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
|
|
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
|
|
|
|
|
|
|
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
|
|
|
|
if (min != NULL && max != NULL)
|
|
|
|
{
|
2009-10-15 21:59:37 +00:00
|
|
|
min->Emit(build);
|
|
|
|
max->Emit(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 1, 1);
|
|
|
|
}
|
|
|
|
ExpEmit out(build, REGT_FLOAT);
|
|
|
|
build->Emit(OP_RESULT, 0, REGT_FLOAT, out.RegNum);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2008-10-18 17:17:44 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos)
|
|
|
|
: FxExpression(pos)
|
|
|
|
{
|
|
|
|
rng = r;
|
|
|
|
if (m) mask = new FxIntCast(m);
|
|
|
|
else mask = new FxConstant(-1, pos);
|
2009-10-15 21:59:37 +00:00
|
|
|
mask = new FxParameter(mask);
|
2008-10-18 17:17:44 +00:00
|
|
|
ValueType = VAL_Int;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxRandom2::~FxRandom2()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxRandom2::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(mask, ctx);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxRandom2::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
2012-10-26 04:04:06 +00:00
|
|
|
// Call the DecoRandom function to generate the random number.
|
2009-10-11 00:02:14 +00:00
|
|
|
VMFunction *callfunc;
|
2012-10-26 04:04:06 +00:00
|
|
|
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoRandom, DecoRandom);
|
|
|
|
|
2010-04-16 02:57:51 +00:00
|
|
|
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
2009-10-11 00:02:14 +00:00
|
|
|
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
|
|
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
|
|
|
|
|
|
|
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
|
2009-10-15 21:59:37 +00:00
|
|
|
mask->Emit(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1);
|
|
|
|
ExpEmit out(build, REGT_INT);
|
|
|
|
build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxIdentifier::FxIdentifier(FName name, const FScriptPosition &pos)
|
|
|
|
: FxExpression(pos)
|
|
|
|
{
|
|
|
|
Identifier = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
PSymbol * sym;
|
|
|
|
FxExpression *newex = NULL;
|
|
|
|
//FBaseCVar * cv = NULL;
|
|
|
|
//FString s;
|
|
|
|
int num;
|
|
|
|
//const PClass *Class;
|
|
|
|
|
|
|
|
CHECKRESOLVED();
|
|
|
|
// see if the current class (if valid) defines something with this name.
|
|
|
|
if ((sym = ctx.FindInClass(Identifier)) != NULL)
|
|
|
|
{
|
2010-04-03 02:06:51 +00:00
|
|
|
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
2008-10-19 21:43:36 +00:00
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as class constant\n", Identifier.GetChars());
|
|
|
|
newex = FxConstant::MakeConstant(sym, ScriptPosition);
|
|
|
|
}
|
2013-08-24 03:02:51 +00:00
|
|
|
else if (sym->IsKindOf(RUNTIME_CLASS(PField)))
|
2008-10-19 21:43:36 +00:00
|
|
|
{
|
2013-08-24 03:02:51 +00:00
|
|
|
PField *vsym = static_cast<PField*>(sym);
|
|
|
|
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as member variable, index %d\n", Identifier.GetChars(), vsym->Offset);
|
2008-10-19 21:43:36 +00:00
|
|
|
newex = new FxClassMember((new FxSelf(ScriptPosition))->Resolve(ctx), vsym, ScriptPosition);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Invalid member identifier '%s'\n", Identifier.GetChars());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// now check the global identifiers.
|
|
|
|
else if ((sym = ctx.FindGlobal(Identifier)) != NULL)
|
|
|
|
{
|
2010-04-03 02:06:51 +00:00
|
|
|
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
2008-10-19 21:43:36 +00:00
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as global constant\n", Identifier.GetChars());
|
|
|
|
newex = FxConstant::MakeConstant(sym, ScriptPosition);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Invalid global identifier '%s'\n", Identifier.GetChars());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
else if ((Class = PClass::FindClass(Identifier)))
|
|
|
|
{
|
|
|
|
pos.Message(MSG_DEBUGLOG, "Resolving name '%s' as class name\n", Identifier.GetChars());
|
|
|
|
newex = new FxClassType(Class, ScriptPosition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
// also check for CVars
|
|
|
|
/*
|
|
|
|
else if ((cv = FindCVar(Identifier, NULL)) != NULL)
|
|
|
|
{
|
|
|
|
CLOG(CL_RESOLVE, LPrintf("Resolving name '%s' as cvar\n", Identifier.GetChars()));
|
|
|
|
newex = new FxCVar(cv, ScriptPosition);
|
|
|
|
}
|
|
|
|
*/
|
2009-10-11 00:02:14 +00:00
|
|
|
// and line specials
|
2008-10-19 21:43:36 +00:00
|
|
|
else if ((num = P_FindLineSpecial(Identifier, NULL, NULL)))
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_DEBUGLOG, "Resolving name '%s' as line special %d\n", Identifier.GetChars(), num);
|
|
|
|
newex = new FxConstant(num, ScriptPosition);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Unknown identifier '%s'", Identifier.GetChars());
|
|
|
|
newex = new FxConstant(0, ScriptPosition);
|
|
|
|
}
|
|
|
|
delete this;
|
|
|
|
return newex? newex->Resolve(ctx) : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxSelf::FxSelf(const FScriptPosition &pos)
|
|
|
|
: FxExpression(pos)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxSelf::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
if (!ctx.cls)
|
|
|
|
{
|
|
|
|
// can't really happen with DECORATE's expression evaluator.
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "self used outside of a member function");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ValueType = ctx.cls;
|
|
|
|
ValueType.Type = VAL_Object;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxSelf::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
2013-07-29 00:40:48 +00:00
|
|
|
// self is always the first pointer passed to the function
|
2009-10-15 23:11:54 +00:00
|
|
|
ExpEmit me(0, REGT_POINTER);
|
|
|
|
me.Fixed = true;
|
|
|
|
return me;
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
|
2008-10-19 21:43:36 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2013-08-24 03:02:51 +00:00
|
|
|
FxClassMember::FxClassMember(FxExpression *x, PField* mem, const FScriptPosition &pos)
|
2008-10-19 21:43:36 +00:00
|
|
|
: FxExpression(pos)
|
|
|
|
{
|
|
|
|
classx = x;
|
|
|
|
membervar = mem;
|
|
|
|
AddressRequested = false;
|
|
|
|
//if (classx->IsDefaultObject()) Readonly=true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxClassMember::~FxClassMember()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(classx);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void FxClassMember::RequestAddress()
|
|
|
|
{
|
|
|
|
AddressRequested = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxClassMember::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(classx, ctx);
|
|
|
|
|
|
|
|
if (classx->ValueType != VAL_Object && classx->ValueType != VAL_Class)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Member variable requires a class or object");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-24 03:02:51 +00:00
|
|
|
PType *type = membervar->Type;
|
|
|
|
PArray *arraytype = dyn_cast<PArray>(type);
|
|
|
|
|
|
|
|
if (arraytype != NULL)
|
|
|
|
{
|
|
|
|
type = arraytype->ElementType;
|
|
|
|
}
|
|
|
|
if (type->IsKindOf(RUNTIME_CLASS(PPointer)))
|
|
|
|
{
|
|
|
|
ValueType = VAL_Object;
|
|
|
|
}
|
|
|
|
else if (type->IsKindOf(RUNTIME_CLASS(PInt)))
|
2008-10-19 21:43:36 +00:00
|
|
|
{
|
|
|
|
ValueType = VAL_Int;
|
2013-08-24 03:02:51 +00:00
|
|
|
}
|
|
|
|
else if (type->IsKindOf(RUNTIME_CLASS(PFloat)))
|
|
|
|
{
|
2008-10-19 21:43:36 +00:00
|
|
|
ValueType = VAL_Float;
|
2013-08-24 03:02:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-10-19 21:43:36 +00:00
|
|
|
ScriptPosition.Message(MSG_ERROR, "Invalid type for member variable %s", membervar->SymbolName.GetChars());
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-08-24 03:02:51 +00:00
|
|
|
if (arraytype != NULL)
|
|
|
|
{
|
|
|
|
ValueType.MakeArray(arraytype->ElementCount);
|
|
|
|
}
|
2008-10-19 21:43:36 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxClassMember::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit obj = classx->Emit(build);
|
|
|
|
assert(obj.RegType == REGT_POINTER);
|
|
|
|
|
|
|
|
if (AddressRequested)
|
|
|
|
{
|
2013-08-24 03:02:51 +00:00
|
|
|
if (membervar->Offset == 0)
|
2009-10-11 00:02:14 +00:00
|
|
|
{
|
|
|
|
return obj;
|
|
|
|
}
|
2009-10-15 23:11:54 +00:00
|
|
|
obj.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit out(build, REGT_POINTER);
|
2013-08-24 03:02:51 +00:00
|
|
|
build->Emit(OP_ADDA_RK, out.RegNum, obj.RegNum, build->GetConstantInt((int)membervar->Offset));
|
2009-10-11 00:02:14 +00:00
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2013-08-24 03:02:51 +00:00
|
|
|
int offsetreg = build->GetConstantInt((int)membervar->Offset);
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit loc, tmp;
|
|
|
|
|
|
|
|
if (obj.Konst)
|
|
|
|
{
|
|
|
|
// If the situation where we are dereferencing a constant
|
|
|
|
// pointer is common, then it would probably be worthwhile
|
|
|
|
// to add new opcodes for those. But as of right now, I
|
|
|
|
// don't expect it to be a particularly common case.
|
|
|
|
ExpEmit newobj(build, REGT_POINTER);
|
|
|
|
build->Emit(OP_LKP, newobj.RegNum, obj.RegNum);
|
|
|
|
obj = newobj;
|
|
|
|
}
|
|
|
|
|
2013-08-24 03:02:51 +00:00
|
|
|
loc = ExpEmit(build, membervar->Type->GetRegType());
|
|
|
|
build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg);
|
2009-10-15 23:11:54 +00:00
|
|
|
obj.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
return loc;
|
|
|
|
}
|
2008-10-19 21:43:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index)
|
|
|
|
:FxExpression(base->ScriptPosition)
|
|
|
|
{
|
|
|
|
Array=base;
|
|
|
|
index = _index;
|
|
|
|
//AddressRequested = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxArrayElement::~FxArrayElement()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(Array);
|
|
|
|
SAFE_DELETE(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
void FxArrayElement::RequestAddress()
|
|
|
|
{
|
|
|
|
AddressRequested = true;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(Array,ctx);
|
|
|
|
SAFE_RESOLVE(index,ctx);
|
|
|
|
|
2013-08-03 02:13:40 +00:00
|
|
|
if (index->ValueType == VAL_Float /* lax */)
|
2008-10-19 21:43:36 +00:00
|
|
|
{
|
|
|
|
// DECORATE allows floats here so cast them to int.
|
|
|
|
index = new FxIntCast(index);
|
|
|
|
index = index->Resolve(ctx);
|
|
|
|
if (index == NULL)
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (index->ValueType != VAL_Int)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Array index must be integer");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Array->ValueType != VAL_Array)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays.");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ValueType = Array->ValueType.GetBaseType();
|
|
|
|
if (ValueType != VAL_Int)
|
|
|
|
{
|
|
|
|
// int arrays only for now
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Only integer arrays are supported.");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Array->RequestAddress();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// in its current state this won't be able to do more than handle the args array.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit start = Array->Emit(build);
|
|
|
|
ExpEmit dest(build, REGT_INT);
|
|
|
|
if (start.Konst)
|
|
|
|
{
|
|
|
|
ExpEmit tmpstart(build, REGT_POINTER);
|
|
|
|
build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum);
|
|
|
|
start = tmpstart;
|
|
|
|
}
|
|
|
|
if (index->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
int indexval = static_cast<FxConstant *>(index)->GetValue().GetInt();
|
2009-10-11 00:02:14 +00:00
|
|
|
if (indexval < 0 || indexval >= Array->ValueType.size)
|
|
|
|
{
|
|
|
|
I_Error("Array index out of bounds");
|
|
|
|
}
|
|
|
|
indexval <<= 2;
|
|
|
|
build->Emit(OP_LW, dest.RegNum, start.RegNum, build->GetConstantInt(indexval));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ExpEmit indexv(index->Emit(build));
|
|
|
|
build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, 2);
|
|
|
|
build->Emit(OP_BOUND, indexv.RegNum, Array->ValueType.size);
|
|
|
|
build->Emit(OP_LW_R, dest.RegNum, start.RegNum, indexv.RegNum);
|
2009-10-15 23:11:54 +00:00
|
|
|
indexv.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
2009-10-15 23:11:54 +00:00
|
|
|
start.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
return dest;
|
|
|
|
}
|
2008-10-19 21:43:36 +00:00
|
|
|
|
2008-10-21 18:10:50 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxFunctionCall::FxFunctionCall(FxExpression *self, FName methodname, FArgumentList *args, const FScriptPosition &pos)
|
|
|
|
: FxExpression(pos)
|
|
|
|
{
|
|
|
|
Self = self;
|
|
|
|
MethodName = methodname;
|
|
|
|
ArgList = args;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxFunctionCall::~FxFunctionCall()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(Self);
|
|
|
|
SAFE_DELETE(ArgList);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
2012-07-14 03:04:41 +00:00
|
|
|
// There's currently only 3 global functions.
|
|
|
|
// If this changes later, it won't be here!
|
|
|
|
if (MethodName == NAME_Sin || MethodName == NAME_Cos || MethodName == NAME_Sqrt)
|
2008-10-21 18:10:50 +00:00
|
|
|
{
|
|
|
|
if (Self != NULL)
|
|
|
|
{
|
2012-07-14 03:04:41 +00:00
|
|
|
ScriptPosition.Message(MSG_ERROR, "Global functions cannot have a self pointer");
|
2008-10-21 18:10:50 +00:00
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
FxExpression *x = new FxGlobalFunctionCall(MethodName, ArgList, ScriptPosition);
|
|
|
|
ArgList = NULL;
|
|
|
|
delete this;
|
|
|
|
return x->Resolve(ctx);
|
|
|
|
}
|
|
|
|
|
2012-02-21 19:24:02 +00:00
|
|
|
int min, max, special;
|
|
|
|
if (MethodName == NAME_ACS_NamedExecuteWithResult || MethodName == NAME_CallACS)
|
|
|
|
{
|
|
|
|
special = -ACS_ExecuteWithResult;
|
|
|
|
min = 1;
|
|
|
|
max = 5;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
special = P_FindLineSpecial(MethodName.GetChars(), &min, &max);
|
|
|
|
}
|
|
|
|
if (special != 0 && min >= 0)
|
2008-10-21 18:10:50 +00:00
|
|
|
{
|
|
|
|
int paramcount = ArgList? ArgList->Size() : 0;
|
|
|
|
if (paramcount < min)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)",
|
|
|
|
MethodName.GetChars(), min, paramcount);
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (paramcount > max)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "too many parameters for '%s' (expected %d, got %d)",
|
|
|
|
MethodName.GetChars(), max, paramcount);
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
FxExpression *x = new FxActionSpecialCall(Self, special, ArgList, ScriptPosition);
|
|
|
|
ArgList = NULL;
|
|
|
|
delete this;
|
|
|
|
return x->Resolve(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Call to unknown function '%s'", MethodName.GetChars());
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
2012-02-21 19:24:02 +00:00
|
|
|
// FxActionSpecialCall
|
2008-10-21 18:10:50 +00:00
|
|
|
//
|
2012-02-21 19:24:02 +00:00
|
|
|
// If special is negative, then the first argument will be treated as a
|
|
|
|
// name for ACS_NamedExecuteWithResult.
|
2008-10-21 18:10:50 +00:00
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos)
|
|
|
|
: FxExpression(pos)
|
|
|
|
{
|
|
|
|
Self = self;
|
|
|
|
Special = special;
|
|
|
|
ArgList = args;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxActionSpecialCall::~FxActionSpecialCall()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(Self);
|
|
|
|
SAFE_DELETE(ArgList);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
bool failed = false;
|
|
|
|
|
|
|
|
if (ArgList != NULL)
|
|
|
|
{
|
|
|
|
for(unsigned i = 0; i < ArgList->Size(); i++)
|
|
|
|
{
|
|
|
|
(*ArgList)[i] = (*ArgList)[i]->Resolve(ctx);
|
|
|
|
if ((*ArgList)[i] == NULL) failed = true;
|
2012-02-21 19:24:02 +00:00
|
|
|
if (Special < 0 && i == 0)
|
|
|
|
{
|
|
|
|
if ((*ArgList)[i]->ValueType != VAL_Name)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Name expected for parameter %d", i);
|
|
|
|
failed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((*ArgList)[i]->ValueType != VAL_Int)
|
2008-10-21 18:10:50 +00:00
|
|
|
{
|
2013-08-03 02:13:40 +00:00
|
|
|
if ((*ArgList)[i]->ValueType == VAL_Float /* lax */)
|
2008-10-21 18:10:50 +00:00
|
|
|
{
|
|
|
|
(*ArgList)[i] = new FxIntCast((*ArgList)[i]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Integer expected for parameter %d", i);
|
|
|
|
failed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (failed)
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ValueType = VAL_Int;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
int DecoCallLineSpecial(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
|
|
|
{
|
|
|
|
assert(numparam > 2 && numparam < 7);
|
|
|
|
assert(numret == 1);
|
|
|
|
assert(param[0].Type == REGT_INT);
|
|
|
|
assert(param[1].Type == REGT_POINTER);
|
|
|
|
int v[5] = { 0 };
|
|
|
|
|
|
|
|
for (int i = 2; i < numparam; ++i)
|
|
|
|
{
|
|
|
|
v[i - 2] = param[i].i;
|
|
|
|
}
|
|
|
|
ret->SetInt(LineSpecials[param[0].i](NULL, reinterpret_cast<AActor*>(param[1].a), false, v[0], v[1], v[2], v[3], v[4]));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
assert(Self == NULL);
|
|
|
|
unsigned i = 0;
|
|
|
|
|
2012-10-18 03:19:27 +00:00
|
|
|
build->Emit(OP_PARAMI, abs(Special)); // pass special number
|
2009-10-11 00:02:14 +00:00
|
|
|
build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self
|
|
|
|
if (ArgList != NULL)
|
|
|
|
{
|
|
|
|
for (; i < ArgList->Size(); ++i)
|
|
|
|
{
|
2009-10-15 21:59:37 +00:00
|
|
|
FxExpression *argex = (*ArgList)[i];
|
2012-10-18 03:19:27 +00:00
|
|
|
if (Special < 0 && i == 0)
|
2009-10-15 21:59:37 +00:00
|
|
|
{
|
2012-10-18 03:19:27 +00:00
|
|
|
assert(argex->ValueType == VAL_Name);
|
|
|
|
assert(argex->isConstant());
|
2013-07-31 03:52:27 +00:00
|
|
|
build->EmitParamInt(-static_cast<FxConstant *>(argex)->GetValue().GetName());
|
2009-10-15 21:59:37 +00:00
|
|
|
}
|
|
|
|
else
|
2009-10-11 00:02:14 +00:00
|
|
|
{
|
2012-10-18 03:19:27 +00:00
|
|
|
assert(argex->ValueType == VAL_Int);
|
|
|
|
if (argex->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
build->EmitParamInt(static_cast<FxConstant *>(argex)->GetValue().GetInt());
|
2012-10-18 03:19:27 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ExpEmit arg(argex->Emit(build));
|
|
|
|
build->Emit(OP_PARAM, 0, arg.RegType, arg.RegNum);
|
|
|
|
arg.Free(build);
|
|
|
|
}
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-10-26 04:04:06 +00:00
|
|
|
// Call the DecoCallLineSpecial function to perform the desired special.
|
2009-10-11 00:02:14 +00:00
|
|
|
VMFunction *callfunc;
|
2012-10-26 04:04:06 +00:00
|
|
|
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoCallLineSpecial, DecoCallLineSpecial);
|
|
|
|
|
2010-04-16 02:57:51 +00:00
|
|
|
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
2009-10-11 00:02:14 +00:00
|
|
|
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
|
|
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
|
|
|
|
|
|
|
ExpEmit dest(build, REGT_INT);
|
|
|
|
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2 + i, 1);
|
|
|
|
build->Emit(OP_RESULT, 0, REGT_INT, dest.RegNum);
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
2008-10-21 18:10:50 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxGlobalFunctionCall::FxGlobalFunctionCall(FName fname, FArgumentList *args, const FScriptPosition &pos)
|
|
|
|
: FxExpression(pos)
|
|
|
|
{
|
|
|
|
Name = fname;
|
|
|
|
ArgList = args;
|
|
|
|
}
|
2008-10-19 21:43:36 +00:00
|
|
|
|
2008-10-21 18:10:50 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxGlobalFunctionCall::~FxGlobalFunctionCall()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(ArgList);
|
|
|
|
}
|
|
|
|
|
|
|
|
FxExpression *FxGlobalFunctionCall::Resolve(FCompileContext& ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
|
|
|
|
if (ArgList == NULL || ArgList->Size() != 1)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", Name.GetChars());
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*ArgList)[0] = (*ArgList)[0]->Resolve(ctx);
|
|
|
|
if ((*ArgList)[0] == NULL)
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(*ArgList)[0]->ValueType.isNumeric())
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-10-11 00:02:14 +00:00
|
|
|
if ((*ArgList)[0]->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
double v = static_cast<FxConstant *>((*ArgList)[0])->GetValue().GetFloat();
|
2012-07-14 03:04:41 +00:00
|
|
|
if (Name == NAME_Sqrt)
|
|
|
|
{
|
|
|
|
v = sqrt(v);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
v *= M_PI / 180.0; // convert from degrees to radians
|
|
|
|
v = (Name == NAME_Sin) ? sin(v) : cos(v);
|
|
|
|
}
|
2009-10-11 00:02:14 +00:00
|
|
|
FxExpression *x = new FxConstant(v, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
if ((*ArgList)[0]->ValueType == VAL_Int)
|
|
|
|
{
|
|
|
|
(*ArgList)[0] = new FxFloatCast((*ArgList)[0]);
|
|
|
|
}
|
2008-10-21 18:10:50 +00:00
|
|
|
ValueType = VAL_Float;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
ExpEmit FxGlobalFunctionCall::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit v = (*ArgList)[0]->Emit(build);
|
|
|
|
assert(!v.Konst && v.RegType == REGT_FLOAT);
|
|
|
|
|
2012-07-14 03:04:41 +00:00
|
|
|
build->Emit(OP_FLOP, v.RegNum, v.RegNum,
|
|
|
|
(Name == NAME_Sqrt) ? FLOP_SQRT :
|
2013-07-29 01:29:25 +00:00
|
|
|
(Name == NAME_Sin) ? FLOP_SIN_DEG :
|
|
|
|
FLOP_COS_DEG);
|
2009-10-11 00:02:14 +00:00
|
|
|
return v;
|
|
|
|
}
|
2008-10-25 17:38:00 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxClassTypeCast::FxClassTypeCast(const PClass *dtype, FxExpression *x)
|
|
|
|
: FxExpression(x->ScriptPosition)
|
|
|
|
{
|
|
|
|
desttype = dtype;
|
|
|
|
basex=x;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxClassTypeCast::~FxClassTypeCast()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(basex);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxClassTypeCast::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(basex, ctx);
|
|
|
|
|
|
|
|
if (basex->ValueType != VAL_Name)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Cannot convert to class type");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (basex->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
FName clsname = static_cast<FxConstant *>(basex)->GetValue().GetName();
|
2008-10-29 16:13:05 +00:00
|
|
|
const PClass *cls = NULL;
|
|
|
|
|
2013-04-09 22:15:41 +00:00
|
|
|
if (clsname != NAME_None)
|
2008-10-25 17:38:00 +00:00
|
|
|
{
|
2013-04-09 22:15:41 +00:00
|
|
|
cls = PClass::FindClass(clsname);
|
2008-10-25 17:38:00 +00:00
|
|
|
if (cls == NULL)
|
|
|
|
{
|
2013-08-03 02:13:40 +00:00
|
|
|
/* lax */
|
2008-10-25 17:38:00 +00:00
|
|
|
// Since this happens in released WADs it must pass without a terminal error... :(
|
|
|
|
ScriptPosition.Message(MSG_WARNING,
|
|
|
|
"Unknown class name '%s'",
|
|
|
|
clsname.GetChars(), desttype->TypeName.GetChars());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!cls->IsDescendantOf(desttype))
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR,"class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars());
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ScriptPosition.Message(MSG_DEBUG,"resolving '%s' as class name", clsname.GetChars());
|
|
|
|
}
|
|
|
|
FxExpression *x = new FxConstant(cls, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2009-10-11 00:02:14 +00:00
|
|
|
int DecoNameToClass(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
|
|
|
{
|
|
|
|
assert(numparam == 2);
|
|
|
|
assert(numret == 1);
|
|
|
|
assert(param[0].Type == REGT_INT);
|
|
|
|
assert(param[1].Type == REGT_POINTER);
|
|
|
|
assert(ret->RegType == REGT_POINTER);
|
|
|
|
|
|
|
|
FName clsname = ENamedName(param[0].i);
|
|
|
|
const PClass *cls = PClass::FindClass(clsname);
|
|
|
|
const PClass *desttype = reinterpret_cast<PClass *>(param[0].a);
|
|
|
|
|
|
|
|
if (!cls->IsDescendantOf(desttype))
|
|
|
|
{
|
|
|
|
Printf("class '%s' is not compatible with '%s'", clsname.GetChars(), desttype->TypeName.GetChars());
|
|
|
|
cls = NULL;
|
|
|
|
}
|
2010-02-14 19:59:21 +00:00
|
|
|
ret->SetPointer(const_cast<PClass *>(cls), ATAG_OBJECT);
|
2009-10-11 00:02:14 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ExpEmit FxClassTypeCast::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
if (basex->ValueType != VAL_Name)
|
|
|
|
{
|
|
|
|
return ExpEmit(build->GetConstantAddress(NULL, ATAG_OBJECT), REGT_POINTER, true);
|
|
|
|
}
|
|
|
|
ExpEmit clsname = basex->Emit(build);
|
|
|
|
assert(!clsname.Konst);
|
|
|
|
ExpEmit dest(build, REGT_POINTER);
|
|
|
|
build->Emit(OP_PARAM, 0, clsname.RegType, clsname.RegNum);
|
|
|
|
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(const_cast<PClass *>(desttype), ATAG_OBJECT));
|
|
|
|
|
2012-10-26 04:04:06 +00:00
|
|
|
// Call the DecoNameToClass function to convert from 'name' to class.
|
2009-10-11 00:02:14 +00:00
|
|
|
VMFunction *callfunc;
|
2012-10-26 04:04:06 +00:00
|
|
|
PSymbol *sym = FindDecorateBuiltinFunction(NAME_DecoNameToClass, DecoNameToClass);
|
|
|
|
|
2010-04-16 02:57:51 +00:00
|
|
|
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
2009-10-11 00:02:14 +00:00
|
|
|
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
|
|
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
|
|
|
|
|
|
|
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1);
|
|
|
|
build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum);
|
2009-10-15 23:11:54 +00:00
|
|
|
clsname.Free(build);
|
2009-10-11 00:02:14 +00:00
|
|
|
return dest;
|
|
|
|
}
|
2008-10-25 17:38:00 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxStateByIndex::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
2010-03-24 02:49:37 +00:00
|
|
|
if (ctx.cls->NumOwnedStates == 0)
|
2008-10-25 17:38:00 +00:00
|
|
|
{
|
|
|
|
// This can't really happen
|
|
|
|
assert(false);
|
|
|
|
}
|
2010-03-24 02:49:37 +00:00
|
|
|
if (ctx.cls->NumOwnedStates <= index)
|
2008-10-25 17:38:00 +00:00
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "%s: Attempt to jump to non existing state index %d",
|
|
|
|
ctx.cls->TypeName.GetChars(), index);
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-03-24 02:49:37 +00:00
|
|
|
FxExpression *x = new FxConstant(ctx.cls->OwnedStates + index, ScriptPosition);
|
2008-10-25 17:38:00 +00:00
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxMultiNameState::FxMultiNameState(const char *_statestring, const FScriptPosition &pos)
|
|
|
|
:FxExpression(pos)
|
|
|
|
{
|
|
|
|
FName scopename;
|
|
|
|
FString statestring = _statestring;
|
|
|
|
int scopeindex = statestring.IndexOf("::");
|
|
|
|
|
|
|
|
if (scopeindex >= 0)
|
|
|
|
{
|
|
|
|
scopename = FName(statestring, scopeindex, false);
|
|
|
|
statestring = statestring.Right(statestring.Len() - scopeindex - 2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
scopename = NULL;
|
|
|
|
}
|
|
|
|
names = MakeStateNameList(statestring);
|
|
|
|
names.Insert(0, scopename);
|
|
|
|
scope = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
if (names[0] == NAME_None)
|
|
|
|
{
|
2009-01-06 00:03:18 +00:00
|
|
|
scope = NULL;
|
2008-10-25 17:38:00 +00:00
|
|
|
}
|
|
|
|
else if (names[0] == NAME_Super)
|
|
|
|
{
|
2010-03-24 02:49:37 +00:00
|
|
|
scope = dyn_cast<PClassActor>(ctx.cls->ParentClass);
|
2008-10-25 17:38:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-24 02:49:37 +00:00
|
|
|
scope = PClass::FindActor(names[0]);
|
2008-10-25 17:38:00 +00:00
|
|
|
if (scope == NULL)
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Unknown class '%s' in state label", names[0].GetChars());
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else if (!scope->IsDescendantOf(ctx.cls))
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(),ctx.cls->TypeName.GetChars());
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (scope != NULL)
|
|
|
|
{
|
2008-12-29 23:03:38 +00:00
|
|
|
FState *destination = NULL;
|
2008-10-25 17:38:00 +00:00
|
|
|
// If the label is class specific we can resolve it right here
|
2008-12-29 23:03:38 +00:00
|
|
|
if (names[1] != NAME_None)
|
2008-10-25 17:38:00 +00:00
|
|
|
{
|
2010-03-24 02:49:37 +00:00
|
|
|
destination = scope->FindState(names.Size()-1, &names[1], false);
|
2008-12-29 23:03:38 +00:00
|
|
|
if (destination == NULL)
|
|
|
|
{
|
2013-08-03 02:13:40 +00:00
|
|
|
ScriptPosition.Message(MSG_WARNING, "Unknown state jump destination");
|
|
|
|
/* lax */
|
2008-12-29 23:03:38 +00:00
|
|
|
return this;
|
|
|
|
}
|
2008-10-25 17:38:00 +00:00
|
|
|
}
|
|
|
|
FxExpression *x = new FxConstant(destination, ScriptPosition);
|
|
|
|
delete this;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
names.Delete(0);
|
|
|
|
names.ShrinkToFit();
|
2008-10-26 10:31:19 +00:00
|
|
|
ValueType = VAL_State;
|
2008-10-25 17:38:00 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2012-10-26 04:04:06 +00:00
|
|
|
static int DoFindState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, FName *names, int numnames)
|
2009-10-11 00:02:14 +00:00
|
|
|
{
|
2010-02-14 19:59:21 +00:00
|
|
|
PARAM_OBJECT_AT(0, self, AActor);
|
2010-03-24 02:49:37 +00:00
|
|
|
FState *state = self->GetClass()->FindState(numparam - 1, names);
|
2009-10-11 00:02:14 +00:00
|
|
|
if (state == NULL)
|
|
|
|
{
|
|
|
|
const char *dot = "";
|
|
|
|
Printf("Jump target '");
|
|
|
|
for (int i = 0; i < numparam - 1; i++)
|
|
|
|
{
|
|
|
|
Printf("%s%s", dot, names[i].GetChars());
|
|
|
|
dot = ".";
|
|
|
|
}
|
|
|
|
Printf("' not found in %s\n", self->GetClass()->TypeName.GetChars());
|
|
|
|
}
|
2010-02-14 19:59:21 +00:00
|
|
|
ret->SetPointer(state, ATAG_STATE);
|
2009-10-11 00:02:14 +00:00
|
|
|
return 1;
|
2012-10-26 04:04:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Find a state with any number of dots in its name.
|
|
|
|
int DecoFindMultiNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
|
|
|
{
|
|
|
|
assert(numparam > 1);
|
|
|
|
assert(numret == 1);
|
|
|
|
assert(ret->RegType == REGT_POINTER);
|
|
|
|
|
|
|
|
FName *names = (FName *)alloca((numparam - 1) * sizeof(FName));
|
|
|
|
for (int i = 1; i < numparam; ++i)
|
|
|
|
{
|
|
|
|
PARAM_NAME_AT(i, zaname);
|
|
|
|
names[i - 1] = zaname;
|
|
|
|
}
|
|
|
|
return DoFindState(stack, param, numparam, ret, names, numparam - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find a state without any dots in its name.
|
|
|
|
int DecoFindSingleNameState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret)
|
|
|
|
{
|
|
|
|
assert(numparam == 2);
|
|
|
|
assert(numret == 1);
|
|
|
|
assert(ret->RegType == REGT_POINTER);
|
|
|
|
|
|
|
|
PARAM_NAME_AT(1, zaname);
|
|
|
|
return DoFindState(stack, param, numparam, ret, &zaname, 1);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
ExpEmit dest(build, REGT_POINTER);
|
2010-02-14 19:59:21 +00:00
|
|
|
build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // pass stateowner
|
2009-10-11 00:02:14 +00:00
|
|
|
for (unsigned i = 0; i < names.Size(); ++i)
|
|
|
|
{
|
2013-07-28 02:38:35 +00:00
|
|
|
build->EmitParamInt(names[i]);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
|
|
|
|
2012-10-26 04:04:06 +00:00
|
|
|
// For one name, use the DecoFindSingleNameState function. For more than
|
|
|
|
// one name, use the DecoFindMultiNameState function.
|
2009-10-11 00:02:14 +00:00
|
|
|
VMFunction *callfunc;
|
2012-10-26 04:04:06 +00:00
|
|
|
PSymbol *sym;
|
|
|
|
|
|
|
|
if (names.Size() == 1)
|
2009-10-11 00:02:14 +00:00
|
|
|
{
|
2012-10-26 04:04:06 +00:00
|
|
|
sym = FindDecorateBuiltinFunction(NAME_DecoFindSingleNameState, DecoFindSingleNameState);
|
2009-10-11 00:02:14 +00:00
|
|
|
}
|
2012-10-26 04:04:06 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
sym = FindDecorateBuiltinFunction(NAME_DecoFindMultiNameState, DecoFindMultiNameState);
|
|
|
|
}
|
|
|
|
|
2010-04-16 02:57:51 +00:00
|
|
|
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
2009-10-11 00:02:14 +00:00
|
|
|
assert(((PSymbolVMFunction *)sym)->Function != NULL);
|
|
|
|
callfunc = ((PSymbolVMFunction *)sym)->Function;
|
|
|
|
|
|
|
|
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), names.Size() + 1, 1);
|
|
|
|
build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum);
|
|
|
|
return dest;
|
|
|
|
}
|
2008-10-25 17:38:00 +00:00
|
|
|
|
2012-10-28 04:36:52 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FxDamageValue::FxDamageValue(FxExpression *v, bool calc)
|
|
|
|
: FxExpression(v->ScriptPosition)
|
|
|
|
{
|
|
|
|
val = v;
|
|
|
|
ValueType = VAL_Unknown;
|
|
|
|
Calculated = calc;
|
|
|
|
MyFunction = NULL;
|
|
|
|
|
|
|
|
if (!calc)
|
|
|
|
{
|
|
|
|
assert(v->isConstant() && "Non-calculated damage must be constant");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FxDamageValue::~FxDamageValue()
|
|
|
|
{
|
|
|
|
SAFE_DELETE(val);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
FxExpression *FxDamageValue::Resolve(FCompileContext &ctx)
|
|
|
|
{
|
|
|
|
CHECKRESOLVED();
|
|
|
|
SAFE_RESOLVE(val, ctx)
|
|
|
|
|
|
|
|
if (!val->ValueType.isNumeric())
|
|
|
|
{
|
|
|
|
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
|
|
|
|
delete this;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is a highly-specialized "expression" type that emits a complete function.
|
|
|
|
ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build)
|
|
|
|
{
|
|
|
|
if (val->isConstant())
|
|
|
|
{
|
2013-07-31 03:52:27 +00:00
|
|
|
build->EmitRetInt(0, false, static_cast<FxConstant *>(val)->GetValue().Int);
|
2012-10-28 04:36:52 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ExpEmit emitval = val->Emit(build);
|
|
|
|
assert(emitval.RegType == REGT_INT);
|
|
|
|
build->Emit(OP_RET, 0, REGT_INT | (emitval.Konst ? REGT_KONST : 0), emitval.RegNum);
|
|
|
|
}
|
2012-10-29 01:11:24 +00:00
|
|
|
build->Emit(OP_RETI, 1 | RET_FINAL, Calculated);
|
2012-10-28 04:36:52 +00:00
|
|
|
|
|
|
|
return ExpEmit();
|
|
|
|
}
|