/// <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);
			}
		}
Beispiel #4
0
        /// <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);
            }
        }
Beispiel #6
0
        /// <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);
            }
        }