public override void OutputIL(NitroIL into){ if(Size!=null){ Size.OutputIL(into); }else{ into.Emit(OpCodes.Ldc_I4,DirectSize); } Type ElementType=ArrayType.GetElementType(); into.Emit(OpCodes.Newarr,ElementType); if(DefaultValues==null || DefaultValues.Length==0){ return; } LocalBuilder temp=into.DeclareLocal(ArrayType); into.Emit(OpCodes.Stloc,temp); // Emit a series of SET's into the array. for(int i=0;i<DefaultValues.Length;i++){ into.Emit(OpCodes.Ldloc,temp); into.Emit(OpCodes.Ldc_I4,i); DefaultValues[i].OutputIL(into); if(ElementType.IsValueType){ into.Emit(OpCodes.Stelem,ElementType); }else{ into.Emit(OpCodes.Stelem_Ref); } } into.Emit(OpCodes.Ldloc,temp); }
public override void OutputIL(NitroIL into){ Type methodType=Method.ReturnType(); if(Input0!=null){ Type type=Input0.OutputType(out Input0); if(type==null){ if(methodType.IsValueType){ // We're returning null and the method returns a value type - this isn't allowed. Error("Can't return null here as the output type of the method is a value type."); } }else if(!methodType.IsAssignableFrom(type)){ if(Types.IsVoid(methodType)){ Error("This method cannot return anything (it's got no return type)"); }else{ Error("Must return something of type "+methodType+" (the methods return type)"); } } Input0.OutputIL(into); }else if(!Types.IsVoid(methodType)){ Error("Must return a value of type "+methodType); } if(Method.ReturnBay!=null){ into.Emit(OpCodes.Stloc,Method.ReturnBay); } into.Emit(OpCodes.Br,Method.EndOfMethod); }
public void OutputTarget(NitroIL into){ if(ElementType==null){ Error("Unused index operation"); } AppliedTo.OutputIL(into); Index.OutputIL(into); }
public override void OutputIL(NitroIL into){ // Emit any set operations before the block itself (e.g. i=0): for(int i=0;i<Parameters.Length;i++){ CompiledFragment parameter=Parameters[i]; if(Types.IsTypeOf(parameter,typeof(SetOperation))){ // Make sure it isn't a self set - e.g. i++, i=i+10. SetOperation set=(SetOperation)parameter; if(!set.SelfReferencing()){ set.OutputIL(into); Parameters[i]=null; }else{ set.Output=false; } }else{ // Compute it's output type: // Note that this must NOT be done for the SET ops as it makes them think // We want to use their output, which isn't true! parameter.OutputType(out parameter); Parameters[i]=parameter; } } Label continuePoint=into.DefineLabel(); Label start=into.DefineLabel(); Label end=into.DefineLabel(); Method.AddBreakPoint(new BreakPoint(continuePoint,end)); into.MarkLabel(start); // Logical operations (e.g. i<10): for(int i=0;i<Parameters.Length;i++){ CompiledFragment parameter=Parameters[i]; if(parameter==null){ continue; } if(Types.IsTypeOf(parameter,typeof(SetOperation))){ // Just checking for a logical operation will make an incremental (i++) operation think // It's being daisy chained. That's because its output type is checked for boolean in IsLogical. continue; } if(parameter.IsLogical()){ parameter.OutputIL(into); into.Emit(OpCodes.Brfalse,end); Parameters[i]=null; } } Body.CompileBody(Method); into.MarkLabel(continuePoint); // Increment/decrement ops (e.g. i++): for(int i=0;i<Parameters.Length;i++){ CompiledFragment cfrag=Parameters[i]; if(cfrag==null){ continue; } cfrag.OutputIL(into); } into.Emit(OpCodes.Br,start); into.MarkLabel(end); Method.PopBreakPoint(); }
public override void OutputIL(NitroIL into){ if(FromType==null){ FromType=ToBox.OutputType(out ToBox); } ToBox.OutputIL(into); into.Emit(OpCodes.Box,FromType); }
public override void OutputSet(NitroIL into,Type setting){ if(VariableType==null){ VariableType=setting; }else if(setting!=VariableType){ // Overwriting the variable with something of a different type. Create a new one. VariableType=setting; Builder=null; } if(VariableType==null){ VariableType=typeof(object); } if(Builder==null){ Builder=into.DeclareLocal(VariableType); } into.Emit(OpCodes.Stloc,Builder); }
/// <summary>Outputs this variable into IL.</summary> /// <param name="into">The IL stream to output it into.</param> /// <param name="accessingMember">True if we are accessing a field/method of this variable.</param> public override void OutputIL(NitroIL into,bool accessingMember){ if(accessingMember&&ParameterType.IsValueType){ // Must load by reference. It's a value type and we want some property of it. into.Emit(OpCodes.Ldarga,Builder.Position); }else{ into.Emit(OpCodes.Ldarg,Builder.Position); } }
public override void OutputIL(NitroIL into){ Input0.OutputIL(into); Input1.OutputIL(into); into.Emit(OpCodes.Ceq); // Flip by comparing with 0: into.Emit(OpCodes.Ldc_I4_0); into.Emit(OpCodes.Ceq); }
public override void OutputIL(NitroIL into){ if(Input0==null){ Input1.OutputIL(into); into.Emit(OpCodes.Neg); }else{ Input0.OutputIL(into); Input1.OutputIL(into); into.Emit(OpCodes.Sub); } }
/// <summary>Adds a break into the given IL stream, breaking out of the given number of loops.</summary> /// <param name="into">The IL stream to emit the break into.</param> /// <param name="depth">The amount of loops to break from. /// Can be affected with e.g. break 2; for getting out of a loop in a loop.</param> /// <returns>True if it could locate the loop and added the command.</returns> public bool Break(NitroIL into, int depth) { if (depth > BreakPoints.Count) { return(false); } BreakPoint point = BreakPoints[BreakPoints.Count - depth]; point.Break(into); return(true); }
public void OutputSet(NitroIL into, Type setting) { if (ElementType.IsValueType) { into.Emit(OpCodes.Stelem, ElementType); } else { into.Emit(OpCodes.Stelem_Ref); } }
public override void OutputIL(NitroIL into){ if(Types.IsDynamic(Constructor)){ if(Parameters!=null){ for(int i=0;i<Parameters.Length;i++){ Parameters[i].OutputIL(into); } } }else{ Types.OutputParameters(Parameters,Method,into,Constructor.GetParameters()); } into.Emit(OpCodes.Newobj,Constructor); }
/// <summary>Outputs this variable into IL.</summary> /// <param name="into">The IL stream to output it into.</param> /// <param name="accessingMember">True if we are accessing a field/method of this variable.</param> public override void OutputIL(NitroIL into, bool accessingMember) { if (accessingMember && ParameterType.IsValueType) { // Must load by reference. It's a value type and we want some property of it. into.Emit(OpCodes.Ldarga, Builder.Position); } else { into.Emit(OpCodes.Ldarg, Builder.Position); } }
public override void OutputIL(NitroIL into) { OutputTarget(into); if (ElementType.IsValueType) { into.Emit(OpCodes.Ldelem, ElementType); } else { into.Emit(OpCodes.Ldelem_Ref); } }
public override void OutputIL(NitroIL into) { GetMethodInfo(); // First, the instance this method is on: bool useVirtual = (CalledOn != null); if (useVirtual) { Type type = CalledOn.OutputType(out CalledOn); CalledOn.OutputIL(into); if (type.IsValueType) { if (!CalledOn.EmitsAddress) { // Value must be set into a temporary local and reloaded (but as an address). // Future optimization may be to pool these. LocalBuilder builder = into.DeclareLocal(type); into.Emit(OpCodes.Stloc, builder); into.Emit(OpCodes.Ldloca, builder); } useVirtual = false; } } // Next, its arguments: if (Types.IsDynamic(MethodToCall)) { if (Arguments != null) { for (int i = 0; i < Arguments.Length; i++) { Arguments[i].OutputIL(into); } } } else { Types.OutputParameters(Arguments, Method, into, MethodToCall.GetParameters()); } // And emit the call: if (useVirtual) { into.Emit(OpCodes.Callvirt, MethodToCall); } else { into.Emit(OpCodes.Call, MethodToCall); } }
public override void OutputIL(NitroIL into) { // Two args for the create call: // - Note that the first is the scope/ variable set into.Emit(OpCodes.Ldnull); into.Emit(OpCodes.Ldftn, ToDelegate); // Get the constructor: ConstructorInfo ctr = DelegateType.GetConstructors()[0]; // Create the delegate: into.Emit(OpCodes.Newobj, ctr); }
public bool OutputTarget(NitroIL into) { if (ElementType == null) { // Error("Unused index operation"); return(false); } AppliedTo.OutputIL(into); Index.OutputIL(into); return(true); }
public void OutputSet(NitroIL into, Type setting) { if (Field != null) { if (IsStatic) { into.Emit(OpCodes.Stsfld, Field); } else { into.Emit(OpCodes.Stfld, Field); } } else if (Property != null) { bool useVirtual = !IsStatic && !Property.PropertyType.IsValueType; MethodInfo setMethod = Property.GetSetMethod(); if (setMethod == null) { Error(Name + " is a readonly property."); } into.Emit(useVirtual?OpCodes.Callvirt:OpCodes.Call, setMethod); } else if (Methods != null) { // Extension property (hopefully!). Look for a set method lookalike. // Get types: Type[] argTypes = new Type[] { OfType(), setting }; // Get the overload: MethodInfo setMethod = Types.GetOverload(Methods, argTypes); if (setMethod == null) { Error(Name + " is a 'readonly' extension property."); } // Call the set method: into.Emit(OpCodes.Call, setMethod); } else { Error(Name + " is a function! Unable to set it's value."); } }
/// <summary>Outputs this variable into IL.</summary> /// <param name="into">The IL stream to output it into.</param> /// <param name="accessingMember">True if we are accessing a field/method of this variable.</param> public override void OutputIL(NitroIL into,bool accessingMember){ if(Builder==null){ // This variable hasn't been written to yet, so this is always like reading a null or zero. return; } if(accessingMember&&VariableType.IsValueType){ // Must load by reference. It's a value type and we want some property of it. into.Emit(OpCodes.Ldloca,Builder); }else{ into.Emit(OpCodes.Ldloc,Builder); } }
public void OutputTarget(NitroIL into) { if (IsStatic && (Field != null || Property != null)) { return; } if (Of == null || (Field == null && Property == null && MethodReturnType == null)) { Error("Unused or invalid property."); } if (MethodReturnType == null) { Of.OutputIL(into); } }
public override void OutputIL(NitroIL into) { // Get the input type: Type casting = ToCast.OutputType(out ToCast); // Special case - if the thing being casted is an object and // the thing we're casting to is a value type, we must unbox instead. if (ToType.IsValueType && casting == typeof(object)) { ToCast.OutputIL(into); into.Emit(OpCodes.Unbox_Any, ToType); return; } ToCast.OutputIL(into); into.Emit(OpCodes.Castclass, ToType); }
public override void OutputIL(NitroIL into) { if (Types.IsDynamic(Constructor)) { if (Parameters != null) { for (int i = 0; i < Parameters.Length; i++) { Parameters[i].OutputIL(into); } } } else { Types.OutputParameters(Parameters, Method, into, Constructor.GetParameters()); } into.Emit(OpCodes.Newobj, Constructor); }
/// <summary>Outputs this variable into IL.</summary> /// <param name="into">The IL stream to output it into.</param> /// <param name="accessingMember">True if we are accessing a field/method of this variable.</param> public override void OutputIL(NitroIL into, bool accessingMember) { if (Builder == null) { // This variable hasn't been written to yet, so this is always like reading a null or zero. return; } if (accessingMember && VariableType.IsValueType) { // Must load by reference. It's a value type and we want some property of it. into.Emit(OpCodes.Ldloca, Builder); } else { into.Emit(OpCodes.Ldloc, Builder); } }
public override void OutputIL(NitroIL into){ // Get Input0 onto the stack: if(Input0==null){ into.Emit(OpCodes.Ldnull,typeof(object)); }else{ Input0.OutputIL(into); } // Run GetObjectType() method: #if NETFX_CORE MethodInfo getType=typeof(TypeofOperation).GetTypeInfo().GetMethod("GetObjectType"); #else MethodInfo getType=typeof(TypeofOperation).GetMethod("GetObjectType"); #endif // Call it: into.Emit(OpCodes.Call,getType); }
public override void OutputIL(NitroIL into) { // Get Input0 onto the stack: if (Input0 == null) { into.Emit(OpCodes.Ldnull, typeof(object)); } else { Input0.OutputIL(into); } // Run GetObjectType() method: #if NETFX_CORE MethodInfo getType = typeof(TypeofOperation).GetTypeInfo().GetMethod("GetObjectType"); #else MethodInfo getType = typeof(TypeofOperation).GetMethod("GetObjectType"); #endif // Call it: into.Emit(OpCodes.Call, getType); }
public override void OutputIL(NitroIL into){ // Ensure our conditions output type is computed: OutputType(); Label End=into.DefineLabel(); Label Else=into.DefineLabel(); Conditions[0].OutputIL(into); into.Emit(OpCodes.Brfalse,Else); AllRoutesReturn=IfTrue.CompileBody(Method); into.Emit(OpCodes.Br,End); into.MarkLabel(Else); if(IfFalse!=null){ bool returns=IfFalse.CompileBody(Method); AllRoutesReturn=(AllRoutesReturn&&returns); }else{ AllRoutesReturn=false; } into.MarkLabel(End); }
public override void OutputIL(NitroIL into) { if (Size != null) { Size.OutputIL(into); } else { into.Emit(OpCodes.Ldc_I4, DirectSize); } Type ElementType = ArrayType.GetElementType(); into.Emit(OpCodes.Newarr, ElementType); if (DefaultValues == null || DefaultValues.Length == 0) { return; } LocalBuilder temp = into.DeclareLocal(ArrayType); into.Emit(OpCodes.Stloc, temp); // Emit a series of SET's into the array. for (int i = 0; i < DefaultValues.Length; i++) { into.Emit(OpCodes.Ldloc, temp); into.Emit(OpCodes.Ldc_I4, i); DefaultValues[i].OutputIL(into); if (ElementType.IsValueType) { into.Emit(OpCodes.Stelem, ElementType); } else { into.Emit(OpCodes.Stelem_Ref); } } into.Emit(OpCodes.Ldloc, temp); }
public bool OutputTarget(NitroIL into) { if (IsStatic && (Field != null || Property != null) && Methods == null) { return(true); } if (Of == null || (Field == null && Property == null && MethodReturnType == null && Methods == null)) { // Error("Unused or invalid property."); // Essentially declaring a property but we can just ignore this. // I.e. something like "hello;" which is valid in JS. return(false); } if (MethodReturnType == null) { Of.OutputIL(into); } return(true); }
public override void OutputIL(NitroIL into) { Type methodType = Method.ReturnType(); if (Input0 != null) { Type type = Input0.OutputType(out Input0); if (type == null) { if (methodType.IsValueType) { // We're returning null and the method returns a value type - this isn't allowed. Error("Can't return null here as the output type of the method is a value type."); } } else if (!methodType.IsAssignableFrom(type)) { if (Types.IsVoid(methodType)) { Error("This method cannot return anything (it's got no return type)"); } else { Error("Must return something of type " + methodType + " (the methods return type)"); } } Input0.OutputIL(into); } else if (!Types.IsVoid(methodType)) { Error("Must return a value of type " + methodType); } if (Method.ReturnBay != null) { into.Emit(OpCodes.Stloc, Method.ReturnBay); } into.Emit(OpCodes.Br, Method.EndOfMethod); }
/// <summary>Emits the Value held by this compiled fragment if possible.</summary> /// <param name="type">The type of the value (or one of the base types of the value).</param> /// <param name="into">The IL stream to output the IL into.</param> public void EmitValue(Type type,NitroIL into){ if(type==typeof(string)){ into.Emit(OpCodes.Ldstr,(string)Value); }else if(type==typeof(int)){ into.Emit(OpCodes.Ldc_I4,(int)Value); }else if(type==typeof(uint)){ into.Emit(OpCodes.Ldc_I4,(uint)Value); }else if(type==typeof(long)){ into.Emit(OpCodes.Ldc_I8,(long)Value); }else if(type==typeof(ulong)){ into.Emit(OpCodes.Ldc_I8,(ulong)Value); }else if(type==typeof(float)){ into.Emit(OpCodes.Ldc_R4,(float)Value); }else if(type==typeof(double)){ into.Emit(OpCodes.Ldc_R8,(double)Value); }else if(type==typeof(OpCode)){ into.Emit((OpCode)Value); }else if(type==typeof(bool)){ into.Emit(OpCodes.Ldc_I4,((bool)Value)?1:0); }else if(type==typeof(short)){ into.Emit(OpCodes.Ldc_I4,(short)Value); }else if(type==typeof(ushort)){ into.Emit(OpCodes.Ldc_I4,(ushort)Value); }else if(type==typeof(byte)){ into.Emit(OpCodes.Ldc_I4,(byte)Value); }else if(type==typeof(sbyte)){ into.Emit(OpCodes.Ldc_I4,(sbyte)Value); }else if(Types.IsSubclass(Value,typeof(Variable))){ // Is parent a type of methodoperation or propertyoperation? // If it is, IsMemberAccessor is true. ((Variable)Value).OutputIL(into, (ParentFragment!=null && ParentFragment.IsMemberAccessor()) ); }else{ Error("Didn't know how to output value "+Value+" (type is "+type+")"); } }
/// <summary>Outputs the given argument set into the given IL stream.</summary> /// <param name="args">The compiled set of arguments to be outputted.</param> /// <param name="method">The method that they are being used in.</param> /// <param name="into">The IL stream to output the arguments into.</param> /// <param name="parameters">The parameter info used to correctly match the location of the parameters.</param> public static void OutputParameters(CompiledFragment[] args,CompiledMethod method,NitroIL into,ParameterInfo[] parameters){ int argID=0; int argCount=0; if(args!=null){ argCount=args.Length; } for(int paramID=0;paramID<parameters.Length;paramID++){ ParameterInfo param=parameters[paramID]; Type paramType=param.ParameterType; if(IsParams(param)){ // The rest are going into an array Operation. // Get the type we want to cast them all to (because paramType at this stage must be an array): paramType=paramType.GetElementType(); CompiledFragment[] ops=new CompiledFragment[argCount-argID]; int Index=0; for(int i=argID;i<argCount;i++){ CompiledFragment frag=args[i]; Type fragType=frag.OutputType(out frag); if(fragType!=paramType){ frag=TryCast(method,frag,paramType); if(frag==null){ args[i].Error("Unable to box or cast "+fragType+" to "+paramType+" at parameter "+argID+". Note that you can't null a value type."); } } ops[Index++]=frag; } CompiledFragment arrayOp=new ArrayOperation(method,paramType,ops); arrayOp.OutputType(out arrayOp); arrayOp.OutputIL(into); return; } CompiledFragment argFrag=args[argID++]; Type argType=argFrag.OutputType(out argFrag); if(argType!=paramType){ CompiledFragment originalFragment=argFrag; argFrag=TryCast(method,argFrag,paramType); if(argFrag==null){ originalFragment.Error("Unable to box or cast "+argType+" to "+paramType+" at parameter "+argID+" of method call "+param.Member.Name+". Note that you can't null a value type."); } } argFrag.OutputIL(into); } }
/// <summary>Generates the IL of this operation into the given stream.</summary> /// <param name="into">The IL stream to output the IL into</param> public virtual void OutputIL(NitroIL into){ if(Value==null){ into.Emit(OpCodes.Ldnull); return; } // Output the variable that represents the result. Note: used by operations which are variables too. EmitValue(Value.GetType(),into); }
/// <summary>Emits a break - a jump to the end of the loop.</summary> /// <param name="into">The IL code to emit the instruction into.</param> public void Break(NitroIL into) { into.Emit(OpCodes.Br, End); }
public override void OutputSet(NitroIL into,Type setting){ into.Emit(OpCodes.Starg,Builder.Position); }
public override void OutputIL(NitroIL into){ GetMethodInfo(); // First, the instance this method is on: bool useVirtual=(CalledOn!=null); if(useVirtual){ Type type=CalledOn.OutputType(out CalledOn); CalledOn.OutputIL(into); if(type.IsValueType){ if(!CalledOn.EmitsAddress){ // Value must be set into a temporary local and reloaded (but as an address). // Future optimization may be to pool these. LocalBuilder builder=into.DeclareLocal(type); into.Emit(OpCodes.Stloc,builder); into.Emit(OpCodes.Ldloca,builder); } useVirtual=false; } } // Next, its arguments: if(Types.IsDynamic(MethodToCall)){ if(Arguments!=null){ for(int i=0;i<Arguments.Length;i++){ Arguments[i].OutputIL(into); } } }else{ Types.OutputParameters(Arguments,Method,into,MethodToCall.GetParameters()); } // And emit the call: if(useVirtual){ into.Emit(OpCodes.Callvirt,MethodToCall); }else{ into.Emit(OpCodes.Call,MethodToCall); } }
public override void OutputIL(NitroIL into) { Wrench.Log.Add("Switch operations are currently unsupported. The whole switch block will be ignored - use ifs instead."); }
public CompiledMethod(CompiledClass parent,string name,BracketFragment parameterBlock,BracketFragment codeBlock,TypeFragment retType,bool isPublic){ Name=name; Parent=parent; CodeBlock=codeBlock; Script=Parent.Script; ParameterBlock=parameterBlock; Type returnType=null; if(retType!=null){ returnType=retType.FindType(Script); if(returnType==null){ Error("Type '"+retType.Value+"' was not found."); } } string methodName=Name; MethodAttributes attrib=isPublic?MethodAttributes.Public:MethodAttributes.Private; if(methodName=="new"){ methodName=".ctor"; attrib|=MethodAttributes.HideBySig|MethodAttributes.SpecialName|MethodAttributes.RTSpecialName; } // Does the parent base type define this method? // If so, use it's name. Type baseType=Parent.Builder.BaseType; // Parse the parameter set right away: ParseParameters(); MethodInfo mInfo=Types.GetOverload(baseType.GetMethods(),Name,ParameterTypes,true); if(mInfo!=null){ methodName=mInfo.Name; attrib|=MethodAttributes.Virtual|MethodAttributes.HideBySig;//|MethodAttributes.NewSlot; } bool isVoid=Types.IsVoid(returnType); if(isVoid){ returnType=typeof(void); } Builder=Parent.Builder.DefineMethod( methodName, attrib, returnType, null ); ApplyParameters(); ILStream=new NitroIL(Builder.GetILGenerator()); EndOfMethod=ILStream.DefineLabel(); if(!isVoid){ ReturnBay=ILStream.DeclareLocal(returnType); } }
/// <summary>Emits the Value held by this compiled fragment if possible.</summary> /// <param name="type">The type of the value (or one of the base types of the value).</param> /// <param name="into">The IL stream to output the IL into.</param> public void EmitValue(Type type, NitroIL into) { if (type == typeof(string)) { into.Emit(OpCodes.Ldstr, (string)Value); } else if (type == typeof(int)) { into.Emit(OpCodes.Ldc_I4, (int)Value); } else if (type == typeof(uint)) { into.Emit(OpCodes.Ldc_I4, (uint)Value); } else if (type == typeof(long)) { into.Emit(OpCodes.Ldc_I8, (long)Value); } else if (type == typeof(ulong)) { into.Emit(OpCodes.Ldc_I8, (ulong)Value); } else if (type == typeof(float)) { into.Emit(OpCodes.Ldc_R4, (float)Value); } else if (type == typeof(double)) { into.Emit(OpCodes.Ldc_R8, (double)Value); } else if (type == typeof(OpCode)) { into.Emit((OpCode)Value); } else if (type == typeof(bool)) { into.Emit(OpCodes.Ldc_I4, ((bool)Value)?1:0); } else if (type == typeof(short)) { into.Emit(OpCodes.Ldc_I4, (short)Value); } else if (type == typeof(ushort)) { into.Emit(OpCodes.Ldc_I4, (ushort)Value); } else if (type == typeof(byte)) { into.Emit(OpCodes.Ldc_I4, (byte)Value); } else if (type == typeof(sbyte)) { into.Emit(OpCodes.Ldc_I4, (sbyte)Value); } else if (Types.IsSubclass(Value, typeof(Variable))) { // Is parent a type of methodoperation or propertyoperation? // If it is, IsMemberAccessor is true. ((Variable)Value).OutputIL(into, (ParentFragment != null && ParentFragment.IsMemberAccessor())); } else { Error("Didn't know how to output value " + Value + " (type is " + type + ")"); } }
public override void OutputIL(NitroIL into){ Wrench.Log.Add("Switch operations are currently unsupported. The whole switch block will be ignored - use ifs instead."); }
public override void OutputIL(NitroIL into){ into.Emit(OpCodes.Ldarg_0); }
public void OutputTarget(NitroIL into){ if(IsStatic&&(Field!=null || Property!=null)){ return; } if(Of==null||(Field==null&&Property==null&&MethodReturnType==null)){ Error("Unused or invalid property."); } if(MethodReturnType==null){ Of.OutputIL(into); } }
public void OutputSet(NitroIL into,Type setting){ if(Field!=null){ if(IsStatic){ into.Emit(OpCodes.Stsfld,Field); }else{ into.Emit(OpCodes.Stfld,Field); } }else if(Property!=null){ bool useVirtual=!IsStatic && !Property.PropertyType.IsValueType; MethodInfo setMethod=Property.GetSetMethod(); if(setMethod==null){ Error(Name+" is a readonly property."); } into.Emit(useVirtual?OpCodes.Callvirt:OpCodes.Call,setMethod); }else{ Error(Name+" is a function! Unable to set it's value."); } }
public override void OutputIL(NitroIL into){ OutputTarget(into); if(Field!=null){ if(Field.IsLiteral){ // Special case - this field isn't actually a field at all! // Load it's literal value: object literalFieldValue=Field.GetValue(null); // Get ready to write out the literal value: CompiledFragment literalValue=new CompiledFragment(literalFieldValue); // It might even be from an enum - let's check: if(Field.FieldType.IsEnum){ // Ok great it's from an enum. What type is it? Type literalValueType=Enum.GetUnderlyingType(Field.FieldType); // Use that type to emit the value: literalValue.EmitValue(literalValueType,into); }else{ literalValue.OutputIL(into); } }else if(ParentFragment!=null && ParentFragment.IsMemberAccessor() && Field.FieldType.IsValueType){ // Are we followed by another PropertyOperation? // A following operation in this sitation ends up being the parent. // If we are, and we output a valuetype, Ldflda must be used. if(IsStatic){ into.Emit(OpCodes.Ldsflda,Field); }else{ into.Emit(OpCodes.Ldflda,Field); } }else if(IsStatic){ into.Emit(OpCodes.Ldsfld,Field); }else{ into.Emit(OpCodes.Ldfld,Field); } }else if(Property!=null){ bool useVirtual=!IsStatic && !Property.PropertyType.IsValueType; into.Emit(useVirtual?OpCodes.Callvirt:OpCodes.Call,Property.GetGetMethod()); }else{ DynamicMethodCompiler.Compile(Method,Name,MethodReturnType,Of).OutputIL(into); } }
public override void OutputIL(NitroIL into) { if (!OutputTarget(into)) { return; } if (Field != null) { if (Field.IsLiteral) { // Special case - this field isn't actually a field at all! // Load it's literal value: object literalFieldValue = Field.GetValue(null); // Get ready to write out the literal value: CompiledFragment literalValue = new CompiledFragment(literalFieldValue); // It might even be from an enum - let's check: if (Field.FieldType.IsEnum) { // Ok great it's from an enum. What type is it? Type literalValueType = Enum.GetUnderlyingType(Field.FieldType); // Use that type to emit the value: literalValue.EmitValue(literalValueType, into); } else { literalValue.OutputIL(into); } } else if (ParentFragment != null && ParentFragment.IsMemberAccessor() && Field.FieldType.IsValueType) { // Are we followed by another PropertyOperation? // A following operation in this sitation ends up being the parent. // If we are, and we output a valuetype, Ldflda must be used. if (IsStatic) { into.Emit(OpCodes.Ldsflda, Field); } else { into.Emit(OpCodes.Ldflda, Field); } } else if (IsStatic) { into.Emit(OpCodes.Ldsfld, Field); } else { into.Emit(OpCodes.Ldfld, Field); } } else if (Property != null) { bool useVirtual = !IsStatic && !Property.PropertyType.IsValueType; into.Emit(useVirtual?OpCodes.Callvirt:OpCodes.Call, Property.GetGetMethod()); } else if (Methods != null) { // Extension property (hopefully!). Look for a get method lookalike. // Get types: Type[] argTypes = new Type[] { OfType() }; // Get the overload: MethodInfo getMethod = Types.GetOverload(Methods, argTypes); if (getMethod == null) { Error(Name + " is a 'write only' extension property."); } // Call the set method: into.Emit(OpCodes.Call, getMethod); } else { DynamicMethodCompiler.Compile(Method, Name, MethodReturnType, Of).OutputIL(into); } }
public override void OutputIL(NitroIL into) { Type type2 = Input1.OutputType(out Input1); // Is it something which is being ["indexed"]? May apply to properties too. bool indexOperation = (Input0.GetType() == typeof(IndexOperation)); bool propertyOperation = (Input0.GetType() == typeof(PropertyOperation)); if (indexOperation || propertyOperation) { // Hook up what we will be setting for the index to handle if it needs to. // Note that the object will not change as we have already run it's OutputType call above. ((Operation)Input0).Input0 = Input1; } // Update input0 by computing the type it outputs: Type type1 = Input0.OutputType(out Input0); object value = Input0.ActiveValue(); if (value.GetType() != typeof(LocalVariable)) { // Local vars can change type so this doesn't affect them. if (type1 == null) { Error("Can't set to nothing."); } if (type2 == null) { if (type1.IsValueType) { Error("Can't set " + type1 + " to null because it's a value type."); } } else if (!type1.IsAssignableFrom(type2)) { Error("Can't implicity convert " + type2 + " to " + type1 + "."); } } if (Types.IsTypeOf(value, typeof(ISettable))) { ISettable Value = (ISettable)value; Value.OutputTarget(into); Input1.OutputIL(into); Value.OutputSet(into, type2); if (Output) { // Daisy chaining these sets. Input0.OutputIL(into); } } else if (indexOperation && value.GetType() == typeof(MethodOperation)) { // This is ok! We've called something like obj["hello"]=input1; // Just output the method call: Input0.OutputIL(into); if (Output) { Error("Can't daisy chain with an indexer. Place your indexed object furthest left."); } } else if (propertyOperation && value.GetType() == typeof(MethodOperation) && ((MethodOperation)value).MethodName == "set_Item") { // This is also ok - we've done something like object.property=value; and it mapped to object["property"]=value; // Just output the method call: Input0.OutputIL(into); if (Output) { Error("Can't daisy chain with a property set here. Place your indexed object furthest left."); } } else { Error("Attempted to set to something (a " + value.GetType() + ") that isn't a variable."); } }
public override void OutputIL(NitroIL into){ Input0.OutputIL(into); Input1.OutputIL(into); into.Emit(OpCodes.Cgt); }
public override void OutputIL(NitroIL into) { // Emit any set operations before the block itself (e.g. i=0): for (int i = 0; i < Parameters.Length; i++) { CompiledFragment parameter = Parameters[i]; if (Types.IsTypeOf(parameter, typeof(SetOperation))) { // Make sure it isn't a self set - e.g. i++, i=i+10. SetOperation set = (SetOperation)parameter; if (!set.SelfReferencing()) { set.OutputIL(into); Parameters[i] = null; } else { set.Output = false; } } else { // Compute it's output type: // Note that this must NOT be done for the SET ops as it makes them think // We want to use their output, which isn't true! parameter.OutputType(out parameter); Parameters[i] = parameter; } } Label continuePoint = into.DefineLabel(); Label start = into.DefineLabel(); Label end = into.DefineLabel(); Method.AddBreakPoint(new BreakPoint(continuePoint, end)); into.MarkLabel(start); // Logical operations (e.g. i<10): for (int i = 0; i < Parameters.Length; i++) { CompiledFragment parameter = Parameters[i]; if (parameter == null) { continue; } if (Types.IsTypeOf(parameter, typeof(SetOperation))) { // Just checking for a logical operation will make an incremental (i++) operation think // It's being daisy chained. That's because its output type is checked for boolean in IsLogical. continue; } if (parameter.IsLogical()) { parameter.OutputIL(into); into.Emit(OpCodes.Brfalse, end); Parameters[i] = null; } } Body.CompileBody(Method); into.MarkLabel(continuePoint); // Increment/decrement ops (e.g. i++): for (int i = 0; i < Parameters.Length; i++) { CompiledFragment cfrag = Parameters[i]; if (cfrag == null) { continue; } cfrag.OutputIL(into); } into.Emit(OpCodes.Br, start); into.MarkLabel(end); Method.PopBreakPoint(); }
public CompiledMethod(CompiledClass parent, string name, BracketFragment parameterBlock, BracketFragment codeBlock, TypeFragment retType, bool isPublic) { Name = name; Parent = parent; CodeBlock = codeBlock; Script = Parent.Script; ParameterBlock = parameterBlock; Type returnType = null; if (retType != null) { returnType = retType.FindType(Script); if (returnType == null) { Error("Type '" + retType.Value + "' was not found."); } } string methodName = Name; MethodAttributes attrib = isPublic?MethodAttributes.Public:MethodAttributes.Private; if (methodName == "new") { methodName = ".ctor"; attrib |= MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; } // Does the parent base type define this method? // If so, use it's name. Type baseType = Parent.Builder.BaseType; // Parse the parameter set right away: ParseParameters(); MethodInfo mInfo = Types.GetOverload(baseType.GetMethods(), Name, ParameterTypes, true); if (mInfo != null) { methodName = mInfo.Name; attrib |= MethodAttributes.Virtual | MethodAttributes.HideBySig; //|MethodAttributes.NewSlot; } bool isVoid = Types.IsVoid(returnType); if (isVoid) { returnType = typeof(void); } Builder = Parent.Builder.DefineMethod( methodName, attrib, returnType, null ); ApplyParameters(); ILStream = new NitroIL(Builder.GetILGenerator()); EndOfMethod = ILStream.DefineLabel(); if (!isVoid) { ReturnBay = ILStream.DeclareLocal(returnType); } }
public override void OutputIL(NitroIL into){ into.Emit(OpCodes.Ldtoken,TypeObject); MethodInfo methodToCall=typeof(System.Type).GetMethod("GetTypeFromHandle"); into.Emit(OpCodes.Call,methodToCall); }
public override void OutputIL(NitroIL into){ Type type2=Input1.OutputType(out Input1); // Is it something which is being ["indexed"]? May apply to properties too. bool indexOperation=(Input0.GetType()==typeof(IndexOperation)); bool propertyOperation=(Input0.GetType()==typeof(PropertyOperation)); if(indexOperation || propertyOperation){ // Hook up what we will be setting for the index to handle if it needs to. // Note that the object will not change as we have already run it's OutputType call above. ((Operation)Input0).Input0=Input1; } // Update input0 by computing the type it outputs: Type type1=Input0.OutputType(out Input0); object value=Input0.ActiveValue(); if(value.GetType()!=typeof(LocalVariable)){ // Local vars can change type so this doesn't affect them. if(type1==null){ Error("Can't set to nothing."); } if(type2==null){ if(type1.IsValueType){ Error("Can't set "+type1+" to null because it's a value type."); } }else if(!type1.IsAssignableFrom(type2)){ Error("Can't implicity convert "+type2+" to "+type1+"."); } } if(Types.IsTypeOf(value,typeof(ISettable))){ ISettable Value=(ISettable)value; Value.OutputTarget(into); Input1.OutputIL(into); Value.OutputSet(into,type2); if(Output){ // Daisy chaining these sets. Input0.OutputIL(into); } }else if(indexOperation && value.GetType()==typeof(MethodOperation)){ // This is ok! We've called something like obj["hello"]=input1; // Just output the method call: Input0.OutputIL(into); if(Output){ Error("Can't daisy chain with an indexer. Place your indexed object furthest left."); } }else if(propertyOperation && value.GetType()==typeof(MethodOperation) && ((MethodOperation)value).MethodName=="set_Item"){ // This is also ok - we've done something like object.property=value; and it mapped to object["property"]=value; // Just output the method call: Input0.OutputIL(into); if(Output){ Error("Can't daisy chain with a property set here. Place your indexed object furthest left."); } }else{ Error("Attempted to set to something (a "+value.GetType()+") that isn't a variable."); } }
/// <summary>Outputs this variable to read its content.</summary> /// <param name="into">The IL stream it should be put into.</param> /// <param name="accessingMember">True if the variable is being outputted and immediately having /// a method/property/field accessed. This is important for value type fields.</param> public virtual void OutputIL(NitroIL into,bool accessingMember){}
public override void OutputIL(NitroIL into) { into.Emit(OpCodes.Ldarg_0); }
/// <summary>Outputs this variable to write its content.</summary> /// <param name="into">The IL stream a set should be put into.</param> /// <param name="setting">The type being set to this variable.</param> public virtual void OutputSet(NitroIL into,Type setting){}
/// <summary>Outputs the given argument set into the given IL stream.</summary> /// <param name="args">The compiled set of arguments to be outputted.</param> /// <param name="method">The method that they are being used in.</param> /// <param name="into">The IL stream to output the arguments into.</param> /// <param name="parameters">The parameter info used to correctly match the location of the parameters.</param> public static void OutputParameters(CompiledFragment[] args, CompiledMethod method, NitroIL into, ParameterInfo[] parameters) { int argID = 0; int argCount = 0; if (args != null) { argCount = args.Length; } for (int paramID = 0; paramID < parameters.Length; paramID++) { ParameterInfo param = parameters[paramID]; Type paramType = param.ParameterType; if (IsParams(param)) { // The rest are going into an array Operation. // Get the type we want to cast them all to (because paramType at this stage must be an array): paramType = paramType.GetElementType(); CompiledFragment[] ops = new CompiledFragment[argCount - argID]; int Index = 0; for (int i = argID; i < argCount; i++) { CompiledFragment frag = args[i]; Type fragType = frag.OutputType(out frag); if (fragType != paramType) { frag = TryCast(method, frag, paramType); if (frag == null) { args[i].Error("Unable to box or cast " + fragType + " to " + paramType + " at parameter " + argID + ". Note that you can't null a value type."); } } ops[Index++] = frag; } CompiledFragment arrayOp = new ArrayOperation(method, paramType, ops); arrayOp.OutputType(out arrayOp); arrayOp.OutputIL(into); return; } CompiledFragment argFrag = args[argID++]; Type argType = argFrag.OutputType(out argFrag); if (argType != paramType) { CompiledFragment originalFragment = argFrag; argFrag = TryCast(method, argFrag, paramType); if (argFrag == null) { originalFragment.Error("Unable to box or cast " + argType + " to " + paramType + " at parameter " + argID + " of method call " + param.Member.Name + ". Note that you can't null a value type."); } } argFrag.OutputIL(into); } }
/// <summary>Used with OutputSet, this outputs any additional information that 'targets' where this variable is located.</summary> /// <param name="into">The IL stream a set should be put into.</param> public virtual void OutputTarget(NitroIL into){}
/// <summary>Emits a continue - a jump to the start of the loop.</summary> /// <param name="into">The IL code to emit the instruction into.</param> public void Continue(NitroIL into) { into.Emit(OpCodes.Br, ContinuePoint); }
public override void OutputIL(NitroIL into){ if(!Method.Break(into,Depth)){ Error("Nothing to break from!"); } }