mirror of
https://github.com/Wack0/IFPSTools.NET.git
synced 2025-06-18 10:45:36 -04:00

libifpscc: initial commit readme: document ifpscc/libifpscc license: add credits for ifpscc/libifpscc (derived from code also MIT licensed) libifps: make additional fields/types public for libifpscc libifps: fix field documentation for some opcodes libifps: fix loading functions that are not exported libifps: allow saving a nonexistant primitive type if the same primitive type was added already libifps: fix parsing Extended constants libifps: fix ushort/short being mapped to the wrong types in one table csproj: set Prefer32Bit=false for release builds
155 lines
7.5 KiB
C#
155 lines
7.5 KiB
C#
using System;
|
|
using CodeGeneration;
|
|
using IFPSLib.Emit;
|
|
|
|
namespace ABT {
|
|
public sealed partial class TypeCast {
|
|
public override Operand CGenValue(CGenState state, Operand retLoc)
|
|
{
|
|
if (this.Kind == TypeCastType.FUNC_TO_PTR)
|
|
{
|
|
switch (this.Expr)
|
|
{
|
|
case Variable func:
|
|
return new Operand(IFPSLib.TypedData.Create(state.EmitType(this.Type) as IFPSLib.Types.FunctionPointerType, state.GetFunction(func.Name)));
|
|
default:
|
|
throw new InvalidProgramException().Attach(Expr);
|
|
}
|
|
}
|
|
if (this.Kind == TypeCastType.NOP) return Expr.CGenValue(state, retLoc);
|
|
|
|
var ret = this.Expr.CGenValue(state, null);
|
|
Operand op = null;
|
|
PointerType ptrType = null;
|
|
Operand dummyForType = null;
|
|
switch (this.Kind) {
|
|
case TypeCastType.ARRAY_TO_PTR:
|
|
// easy, pushvar
|
|
return state.FunctionState.PushVar(ret);
|
|
|
|
case TypeCastType.PTR_TO_INT32:
|
|
op = state.FunctionState.PushType(state.EmitType(Type));
|
|
state.CGenPushStackSize();
|
|
state.FunctionState.PushVar(ret);
|
|
state.FunctionState.PushVar(op);
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.Call, state.CastPointerRef));
|
|
state.CGenPopStackSize();
|
|
return op;
|
|
|
|
case TypeCastType.INT32_TO_PTR:
|
|
op = state.FunctionState.PushType(state.TypeArrayOfPointer);
|
|
ptrType = Type as PointerType;
|
|
if (ptrType == null) throw new InvalidProgramException().Attach(Expr);
|
|
state.CGenPushStackSize();
|
|
dummyForType = state.FunctionState.PushType(state.EmitType(ptrType.RefType));
|
|
state.FunctionState.PushVar(op);
|
|
state.FunctionState.Push(ret);
|
|
state.FunctionState.PushVar(dummyForType);
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.Call, state.CastRefPointer));
|
|
state.CGenPopStackSize();
|
|
return Operand.Create(op.Variable, 0);
|
|
|
|
case TypeCastType.PTR_TO_PTR:
|
|
// same as PTR_TO_INT32 then INT32_TO_PTR
|
|
ptrType = Type as PointerType;
|
|
if (ptrType == null) throw new InvalidProgramException().Attach(Expr);
|
|
op = state.FunctionState.PushType(state.TypeArrayOfPointer);
|
|
state.CGenPushStackSize();
|
|
dummyForType = state.FunctionState.PushType(state.EmitType(ptrType.RefType));
|
|
var dummyU32 = state.FunctionState.PushType(state.TypeU32);
|
|
state.CGenPushStackSize();
|
|
state.FunctionState.PushVar(ret);
|
|
state.FunctionState.PushVar(dummyU32);
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.Call, state.CastPointerRef));
|
|
state.CGenPopStackSize();
|
|
state.FunctionState.PushVar(op);
|
|
state.FunctionState.Push(dummyU32);
|
|
state.FunctionState.PushVar(dummyForType);
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.Call, state.CastRefPointer));
|
|
state.CGenPopStackSize();
|
|
return Operand.Create(op.Variable, 0);
|
|
|
|
case TypeCastType.VARIANT_TO_COM_INTERFACE:
|
|
// this might be interface and might be dispatch.
|
|
op = retLoc != null ? retLoc : state.FunctionState.PushType(state.EmitType(Type));
|
|
state.CGenPushStackSize();
|
|
// u32 type = VarType(variant)
|
|
var varType = state.FunctionState.PushType(state.TypeU16);
|
|
state.CGenPushStackSize();
|
|
state.FunctionState.Push(ret);
|
|
state.FunctionState.PushVar(varType);
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.Call, state.VarType));
|
|
state.CGenPopStackSize();
|
|
// if (varType != vtDispatch) { regular com interface cast }
|
|
// else { cast to dispatch first }
|
|
// cast is same for both, just need to provide the "correct" type
|
|
const ushort VT_DISPATCH = 9;
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.Sub, varType, Operand.Create(VT_DISPATCH)));
|
|
// regular com interface cast
|
|
state.CGenPushStackSize();
|
|
// typeNo
|
|
state.FunctionState.PushType(state.TypeU32);
|
|
// self
|
|
|
|
var comInterface = state.FunctionState.AddLocal();
|
|
|
|
var insnDispatch = Instruction.Create(OpCodes.PushType, state.TypeIDispatch);
|
|
var insnEnd = Instruction.Create(OpCodes.Assign, comInterface, ret);
|
|
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.JumpZ, insnDispatch, varType));
|
|
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.PushType, state.TypeIUnknown));
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.Jump, insnEnd));
|
|
|
|
state.CurrInsns.Add(insnDispatch);
|
|
|
|
state.CurrInsns.Add(insnEnd);
|
|
|
|
// retval
|
|
state.FunctionState.PushVar(op);
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.Call, state.ComInterfaceCast));
|
|
state.CGenPopStackSize();
|
|
return op;
|
|
|
|
case TypeCastType.COM_INTERFACE:
|
|
op = retLoc != null ? retLoc : state.FunctionState.PushType(state.EmitType(Type));
|
|
state.CGenPushStackSize();
|
|
// typeNo
|
|
state.FunctionState.PushType(state.TypeU32);
|
|
// self
|
|
state.FunctionState.Push(ret);
|
|
// retval
|
|
state.FunctionState.PushVar(op);
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.Call, state.ComInterfaceCast));
|
|
state.CGenPopStackSize();
|
|
return op;
|
|
|
|
|
|
case TypeCastType.NOP:
|
|
return ret;
|
|
|
|
case TypeCastType.COPY_CONSTRUCTOR:
|
|
if (retLoc == null) throw new InvalidOperationException("Cannot copy construct to an unknown variable").Attach(Expr);
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.Cpval, retLoc, ret));
|
|
return retLoc;
|
|
|
|
default:
|
|
op = retLoc != null ? retLoc : state.FunctionState.PushType(state.EmitType(Type));
|
|
state.CurrInsns.Add(Instruction.Create(OpCodes.Assign, op, ret));
|
|
return op;
|
|
}
|
|
}
|
|
|
|
public override Operand CGenAddress(CGenState state, Operand retLoc)
|
|
{
|
|
throw new InvalidOperationException("Cannot get the address of a cast expression.").Attach(Expr);
|
|
}
|
|
|
|
public override bool CallerNeedsToCleanStack(CGenState state, bool retLocKnown, bool forAddress = false)
|
|
{
|
|
if (Kind == TypeCastType.NOP) return Expr.CallerNeedsToCleanStack(state, retLocKnown);
|
|
if (Expr.CallerNeedsToCleanStack(state, false)) return true;
|
|
return !retLocKnown;
|
|
}
|
|
}
|
|
} |