/// <summary>If this is a method, this attempts to find the correct overload /// by using the set of arguments given in the method call.</summary> /// <param name="arguments">The set of arguments given in the method call.</param> /// <returns>The MethodInfo if found; null otherwise.</returns> public MethodInfo GetOverload(CompiledFragment[] arguments) { Type fragType = OfType(); if (Types.IsDynamic(fragType)) { CompiledClass cc = Method.Script.GetClass(fragType); return((cc == null)?null:cc.FindMethodOverload(Name, arguments)); } else if (Name == "gettype" && (arguments == null || arguments.Length == 0)) { return(fragType.GetMethod("GetType", new Type[0])); } else { if (!Method.Script.AllowUse(fragType)) { Error("Unable to call methods on type " + fragType.Name + " as it is restricted."); } Type[] paramTypes = Types.GetTypes(arguments); MethodInfo result = Types.GetOverload(fragType.GetMethods(), Name, paramTypes, true); if (IsStatic && result != null && !result.IsStatic) { // Special case! This is where we're calling e.g. ToString on a straight type, for example int.ToString(); // Another example is actually the call below! We're getting a type, then calling a method on the type - not a static method of it. // The method is not static yet we're 'expecting' one. // So, look for the same method on System.Type and return that instead. return(Types.GetOverload(typeof(System.Type).GetMethods(), Name, paramTypes, true)); } return(result); } }
/// <summary>If this is a method, this attempts to find the correct overload /// by using the set of arguments given in the method call.</summary> /// <param name="arguments">The set of arguments given in the method call.</param> /// <returns>The MethodInfo if found; null otherwise.</returns> public MethodInfo GetOverload(Type[] paramTypes) { // Get the parent type: Type fragType = OfType(); if (Methods != null) { // Extension methods. int count = 0; if (paramTypes != null) { count = paramTypes.Length; } // Get types: Type[] argTypes = new Type[count + 1]; if (paramTypes != null) { Array.Copy(paramTypes, 0, argTypes, 1, count); } // Get the overload: return(Types.GetOverload(Methods, argTypes)); } if (Types.IsDynamic(fragType)) { CompiledClass cc = Method.Script.GetClass(fragType); return((cc == null)?null:cc.FindMethodOverload(Name, paramTypes)); } else if (Name == "gettype" && (paramTypes == null || paramTypes.Length == 0)) { return(fragType.GetMethod("GetType", new Type[0])); } if (!Method.Script.AllowUse(fragType)) { Error("Unable to call methods on type " + fragType.Name + " as it is restricted."); } MethodInfo result = Types.GetOverload(fragType.GetMethods(), Name, paramTypes, true); if (IsStatic && result != null && !result.IsStatic) { // Special case! This is where we're calling e.g. ToString on a straight type, for example int.ToString(); // Another example is actually the call below! We're getting a type, then calling a method on the type - not a static method of it. // The method is not static yet we're 'expecting' one. // So, look for the same method on System.Type and return that instead. return(Types.GetOverload(typeof(System.Type).GetMethods(), Name, paramTypes, true)); } return(result); }
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>Attempts to find the type named here and resolve it to a system type.</summary> /// <param name="script">The script that should also be checked for types and acts as the security domain.</param> /// <returns>A system type if the type could be resolved and allowed successfully; null otherwise.</returns> public Type FindType(NitroCode script) { string name = Value; if (GenericSet != null) { name += "`" + GenericSet.Length; } Type baseType = script.GetType(name); if (baseType == null) { CompiledClass cClass = script.GetClass(Value); if (cClass == null) { return(null); } baseType = cClass.GetAsType(); } if (GenericSet != null) { if (!baseType.IsGenericTypeDefinition) { Error(Value + " is not a generic type."); } Type[] genericTypes = new Type[GenericSet.Length]; for (int i = GenericSet.Length - 1; i >= 0; i--) { if ((genericTypes[i] = GenericSet[i].FindType(script)) == null) { return(null); } } baseType = baseType.MakeGenericType(genericTypes); } if (IsArray) { if (Dimensions == 1) { baseType = baseType.MakeArrayType(); } else { baseType = baseType.MakeArrayType(Dimensions); } } return(baseType); }
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>Compiles the given code now deriving from the given object.</summary> /// <param name="code">The code to compile</param> /// <param name="baseType">The type to inherit from. If null, the code will inherit from the default Script type.</param> /// <param name="aotFile">A DLL path to write the compiled code to (For e.g. AOT compilation).</param> public void Compile(string code, Type baseType, string aotFile, string aotAssemblyName) { Code = code; if (baseType == null) { baseType = typeof(Script); } // Are we compiling to a file? string aotFilename = ""; string assemblyPath = null; bool aot = !string.IsNullOrEmpty(aotFile); // The assembly name: AssemblyName assemblyName = null; if (aot) { // Grab the file name (used below too): aotFilename = System.IO.Path.GetFileName(aotFile); // Setup the assembly name: assemblyName = new AssemblyName(aotAssemblyName); } else { assemblyName = new AssemblyName("$SS_" + ModuleCounter); } // Assembly access: AssemblyBuilderAccess access = AssemblyBuilderAccess.Run; if (aot) { // We're ahead-of-time compiling this to a file. // Grab the directory the file must go in: assemblyPath = System.IO.Path.GetDirectoryName(aotFile); if (assemblyPath != null) { if (!Directory.Exists(assemblyPath)) { Directory.CreateDirectory(assemblyPath); } } access = AssemblyBuilderAccess.Save; } // Create the assembly builder. If we're AOT compiling, it's saveable. AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, access, assemblyPath); if (aot) { // Create the module: Builder = assemblyBuilder.DefineDynamicModule("SS-DMOD", aotFilename); } else { Builder = assemblyBuilder.DefineDynamicModule("SS-DMOD"); } ModuleCounter++; // Ok - let's start compiling. Define a base class that all code goes into: BaseClass = new CompiledClass(); // That class will be known as.. BaseClass.StartType("NitroScriptCode", this, baseType); // Start parsing the code into a tree of fragments: CodeLexer sr = new CodeLexer(Code); BaseClass.ClassFragment = new BaseFragment(sr); // Search the fragments for any classes: FindClasses(BaseClass.ClassFragment); // Compile the classes we found: foreach (KeyValuePair <string, CompiledClass> kvp in Types) { kvp.Value.Compile(); } // Compile the base class: BaseClass.Compile(); CompiledType = BaseClass.compiledType; Types = null; BaseClass = null; #if !UNITY_WEBPLAYER if (aot) { // Great - overwrite it. if (File.Exists(aotFile)) { if (OnAotFileExists == null) { File.Delete(aotFile); } else { OnAotFileExists(aotFile); } } assemblyBuilder.Save(aotFilename); } #endif }
/// <summary>Compiles the given code now deriving from the given object.</summary> /// <param name="code">The code to compile</param> /// <param name="baseType">The type to inherit from. If null, the code will inherit from the default Script type.</param> /// <param name="aotFile">A DLL path to write the compiled code to (For e.g. AOT compilation).</param> public void Compile(string code,Type baseType,string aotFile,string aotAssemblyName){ Code=code; if(baseType==null){ baseType=typeof(Script); } // Are we compiling to a file? string aotFilename=""; string assemblyPath=null; bool aot=!string.IsNullOrEmpty(aotFile); // The assembly name: AssemblyName assemblyName=null; if(aot){ // Grab the file name (used below too): aotFilename=System.IO.Path.GetFileName(aotFile); // Setup the assembly name: assemblyName=new AssemblyName(aotAssemblyName); }else{ assemblyName=new AssemblyName("$SS_"+ModuleCounter); } // Assembly access: AssemblyBuilderAccess access=AssemblyBuilderAccess.Run; if(aot){ // We're ahead-of-time compiling this to a file. // Grab the directory the file must go in: assemblyPath=System.IO.Path.GetDirectoryName(aotFile); if(assemblyPath!=null){ if(!Directory.Exists(assemblyPath)){ Directory.CreateDirectory(assemblyPath); } } access=AssemblyBuilderAccess.Save; } // Create the assembly builder. If we're AOT compiling, it's saveable. AssemblyBuilder assemblyBuilder=AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,access,assemblyPath); if(aot){ // Create the module: Builder=assemblyBuilder.DefineDynamicModule("SS-DMOD",aotFilename); }else{ Builder=assemblyBuilder.DefineDynamicModule("SS-DMOD"); } ModuleCounter++; // Ok - let's start compiling. Define a base class that all code goes into: BaseClass=new CompiledClass(); // That class will be known as.. BaseClass.StartType("NitroScriptCode",this,baseType); // Start parsing the code into a tree of fragments: CodeLexer sr=new CodeLexer(Code); BaseClass.ClassFragment=new BaseFragment(sr); // Search the fragments for any classes: FindClasses(BaseClass.ClassFragment); // Compile the classes we found: foreach(KeyValuePair<string,CompiledClass>kvp in Types){ kvp.Value.Compile(); } // Compile the base class: BaseClass.Compile(); CompiledType=BaseClass.compiledType; Types=null; BaseClass=null; if(aot){ // Great - overwrite it. if(File.Exists(aotFile)){ if(OnAotFileExists==null){ File.Delete(aotFile); }else{ OnAotFileExists(aotFile); } } assemblyBuilder.Save(aotFilename); } }
public override Type OutputType(out CompiledFragment v) { v = this; Type type = OfType(); // Map to functionality: CompiledClass Class = null; bool isDynamic = Types.IsDynamic(type); // (Constant) binding flags: BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static; if (Name == "length" && type.IsGenericType && !isDynamic) { // Does length actually exist as a field/ property? Field = type.GetField(Name, flags); if (Field == null) { Property = type.GetProperty(Name, flags); if (Property == null) { // Assume we meant count instead: Name = "Count"; } } } if (isDynamic) { Class = Method.Script.GetClass(type); } else if (!Method.Script.AllowUse(type)) { Error("Unable to access properties of type " + type + " as it has not been made accessible."); } if (isDynamic) { Field = Class.GetField(Name); } else { Field = type.GetField(Name, flags); } if (Field != null) { if (IsStatic && !Field.IsStatic) { Error("Property " + Name + " is not static. You must use an object reference to access it."); } return(Field.FieldType); } if (isDynamic) { Property = Class.GetProperty(Name); } else { Property = type.GetProperty(Name, flags); } if (Property != null) { if (IsStatic) { MethodInfo staticTest = Property.GetGetMethod(); if (staticTest == null) { staticTest = Property.GetSetMethod(); } if (!staticTest.IsStatic) { Error("Property " + Name + " is not static. You must use an object reference to access it."); } } return(Property.PropertyType); } if (isDynamic) { MethodReturnType = Class.MethodReturnType(Name); } else { MethodReturnType = Types.MethodReturnType(type, Name); } if (MethodReturnType != null) { if (Types.IsVoid(MethodReturnType)) { MethodReturnType = typeof(Void); } return(DynamicMethodCompiler.TypeFor(MethodReturnType)); } if (Of.GetType() == typeof(ThisOperation)) { // This was the first property - it can potentially be a static type name too. Type staticType = Method.Script.GetType(Name); if (staticType != null) { // It's a static type! Generate a new type operation to replace this one and return the type. v = new TypeOperation(Method, staticType); return(v.OutputType(out v)); } } if (Name == "this") { // This is handled here as it allows variables called "This". Use case: PowerUI. v = new ThisOperation(Method); return(v.OutputType(out v)); } // Does it support indexing? If so, Do Parent["property"] instead. MethodOperation mOp = null; if (Input0 != null) { // This is a set. Input0 is the object we're setting. Type setType = Input0.OutputType(out Input0); // Get the set method: MethodInfo mInfo; if (isDynamic) { mInfo = Class.FindMethodOverload("set_Item", new Type[] { typeof(string), setType }); } else { // Grab all the methods of the type: MethodInfo[] allMethods = type.GetMethods(); mInfo = Types.GetOverload(allMethods, "set_Item", new Type[] { typeof(string), setType }); } if (mInfo == null) { // Try finding the extension method: mInfo = FindExtensionMethod(type, "set"); if (mInfo == null) { // It doesn't exist! // Error("Property '"+ToString()+"' is not a property or extension of "+type.ToString()+"."); // Create as a global: Field = Method.Script.MainClass.DefineField(Name, true, setType); return(setType); } // Extension property or method. // -> We only know which based on MethodOperation later calling GetOverload. // Or OutputSet/ OutputIL being called. return(mInfo.ReturnType); } // It exists - create the method operation now. mOp = new MethodOperation(Method, mInfo, new CompiledFragment(Name), Input0); v = mOp; mOp.CalledOn = Of; return(setType); } else { // Get. // Get the get method: MethodInfo mInfo; if (isDynamic) { mInfo = Class.FindMethodOverload("get_Item", new Type[] { typeof(string) }); } else { // Grab all the methods of the type: MethodInfo[] allMethods = type.GetMethods(); mInfo = Types.GetOverload(allMethods, "get_Item", new Type[] { typeof(string) }); } if (mInfo == null) { // Try finding the extension method: mInfo = FindExtensionMethod(type, "get"); if (mInfo == null) { // It doesn't exist! // Error("Property '"+ToString()+"' is not a property or extension of "+type.ToString()+"."); // Create as a global: Field = Method.Script.MainClass.DefineField(Name, true, typeof(object)); return(typeof(object)); } // Extension property or method. // -> We only know which based on MethodOperation later calling GetOverload. // Or OutputSet/ OutputIL being called. return(mInfo.ReturnType); } // It exists - create the method operation now: mOp = new MethodOperation(Method, mInfo, new CompiledFragment(Name)); v = mOp; mOp.CalledOn = Of; return(mInfo.ReturnType); } }