示例#1
0
        /// <summary>Adds a method that was found into this classes set of methods to compile.</summary>
        /// <param name="fragment">The first fragment of the method, used for generating errors. This gives a valid line number.</param>
        /// <param name="body">The block of code for this method.</param>
        /// <param name="name">The name of the method. Null if anonymous is true.</param>
        /// <param name="anonymous">True if this method is an anonymous one and requires a name.</param>
        /// <param name="parameters">The set of parameters for this method.</param>
        /// <param name="returnType">The type that this method returns.</param>
        /// <param name="isPublic">True if this is a public method; false for private.</param>
        /// <returns>The first fragment following the method, if there is one.</returns>
        protected virtual CodeFragment AddFoundMethod(CodeFragment fragment, CodeFragment body, string name, bool anonymous, BracketFragment parameters, TypeFragment returnType, bool isPublic)
        {
            if (body == null)
            {
                fragment.Error("Invalid function definition (" + name + "). The content block {} is missing or isnt valid.");
            }

            if (anonymous)
            {
                name = "Compiler-Generated-$" + AnonymousCount;
                AnonymousCount++;
            }

            // The following is the explicit code block for this function:
            BracketFragment codeBlock = (BracketFragment)body;
            CompiledMethod  cMethod   = new CompiledMethod(this, name, parameters, codeBlock, returnType, isPublic);
            MethodOverloads set       = MakeOrFind(name, cMethod.Builder.ReturnType);
            CodeFragment    next      = body.NextChild;

            if (anonymous)
            {
                CodeFragment newChild = DynamicMethodCompiler.Compile(cMethod, name, set.ReturnType, new ThisOperation(cMethod));
                newChild.AddAfter(body);
            }

            body.Remove();
            set.AddMethod(cMethod);
            FindMethods(codeBlock);

            return(next);
        }
示例#2
0
        /// <summary>Gets the init method. May create it if it's not already available.</summary>
        /// <returns>The init method.</returns>
        private CompiledMethod GetInit()
        {
            MethodOverloads set = MakeOrFind(".init", null);

            if (set.Methods.Count == 0)
            {
                set.AddMethod(new CompiledMethod(this, ".init", null, new BracketFragment(), null, true));
            }
            return(set.Methods[0]);
        }
示例#3
0
        /// <summary>Gets a particular method (it may be overloaded) from this class.</summary>
        /// <param name="name">The name of the method.</param>
        /// <param name=arguments">The types of the set of arguments being used in calling this method.</param>
        /// <returns>The MethodInfo for the method if found; null otherwise.</returns>
        public MethodInfo FindMethodOverload(string name, Type[] arguments)
        {
            MethodOverloads set = FindMethodSet(name);

            if (set == null)
            {
                return(Types.GetOverload(Builder.BaseType.GetMethods(), name, arguments, true));
            }
            return(set.GetOverload(arguments));
        }
示例#4
0
        /// <summary>Gets the OnScriptReady method. May create it if it's not available.</summary>
        /// <returns>The start method. All code outside of functions that isn't a variable goes into this.</returns>
        private CompiledMethod GetStartMethod()
        {
            MethodOverloads set = MakeOrFind("OnScriptReady", null);

            if (set.Methods.Count == 0)
            {
                set.AddMethod(new CompiledMethod(this, "OnScriptReady", null, new BracketFragment(), null, true));
            }
            CompiledMethod method = set.Methods[0];

            method.GloballyScoped = true;
            return(method);
        }
示例#5
0
        /// <summary>Finds the method overload set with the given name and creates it if it doesn't exist.</summary>
        /// <param name="name">The name of the method.</param>
        /// <param name="returnType">The type that this method returns.</param>
        /// <returns>The method overload set.</returns>
        private MethodOverloads MakeOrFind(string name, Type returnType)
        {
            MethodOverloads set;

            if (!Methods.TryGetValue(name, out set))
            {
                if (Types.IsVoid(returnType))
                {
                    returnType = typeof(Void);
                }
                set = new MethodOverloads(returnType);
                Methods.Add(name, set);
            }
            return(set);
        }
示例#6
0
        /// <summary>Gets the return type of a given method by name. Note all overloads must return the same thing.</summary>
        /// <returns>The type of object this method returns.</returns>
        public Type MethodReturnType(string name)
        {
            MethodOverloads set = FindMethodSet(name);

            if (set != null)
            {
                return(set.ReturnType);
            }
            MethodInfo[] methods = Builder.BaseType.GetMethods();
            for (int i = 0; i < methods.Length; i++)
            {
                MethodInfo method = methods[i];
                if (method.Name.ToLower() == name)
                {
                    return(method.ReturnType);
                }
            }
            return(null);
        }
		/// <summary>Finds the method overload set with the given name and creates it if it doesn't exist.</summary>
		/// <param name="name">The name of the method.</param>
		/// <param name="returnType">The type that this method returns.</param>
		/// <returns>The method overload set.</returns>
		private MethodOverloads MakeOrFind(string name,Type returnType){
			MethodOverloads set;
			if(!Methods.TryGetValue(name,out set)){
				if(Types.IsVoid(returnType)){
					returnType=typeof(Void);
				}
				set=new MethodOverloads(returnType);
				Methods.Add(name,set);
			}
			return set;
		}
		/// <summary>Compiles the body of all methods in this set.</summary>
		public void CompileBody(){
			if(Methods.Count==0){
				return;
			}
			MethodInfo initInfo=null;
			// Grab the first method so we can find the name:
			CompiledMethod tempMethod=Methods[0];
			if(tempMethod.Name=="new"){
				// Do we have INIT? if yes, output a call to it immediately.
				MethodOverloads set=tempMethod.Parent.FindMethodSet(".init");
				if(set!=null){
					initInfo=set.Methods[0].getMethodInfo();
				}
			}else if(tempMethod.Name==".init"){
				// Got constructors? if not make one now into a set so the above occurs.
				MethodOverloads set=tempMethod.Parent.FindMethodSet("new");
				if(set==null){
					set=new MethodOverloads(typeof(Void));
					set.AddMethod(new CompiledMethod(tempMethod.Parent,"new",null,new BracketFragment(),null,true));
					set.CompileBody();
				}
			}
			
			foreach(CompiledMethod method in Methods){
				if(method.Name=="new"){
					// This is a constructor. If the constructor body doesn't contain a base constructor call, add one like so.
					if(!NewBaseCall(method.CodeBlock)){
						// Call the base constructor.
						method.ILStream.Emit(OpCodes.Ldarg_0);
						// Find the constructor with no parameters:
						ConstructorInfo baseConstructor=method.Parent.BaseType.GetConstructor(new Type[0]);
						
						if(baseConstructor==null){
							method.CodeBlock.Error("You must call base.new(...); as "+method.Parent.BaseType+" doesn't have a constructor for 0 args.");
						}
						
						// Emit the call:
						method.ILStream.Emit(OpCodes.Call,baseConstructor);
					}
				}
				
				if(initInfo!=null){
					method.ILStream.Emit(OpCodes.Ldarg_0);
					method.ILStream.Emit(OpCodes.Call,initInfo);
				}
				
				bool returns=method.CodeBlock.CompileBody(method);
				if(!returns){
					if(!Types.IsVoid(ReturnType)){
						method.CodeBlock.Error("Not all code paths return a value in '"+method.Name+"'");	
					}
				}
				method.ILStream.MarkLabel(method.EndOfMethod);
				if(!Types.IsVoid(ReturnType)){
					method.ILStream.Emit(OpCodes.Ldloc,method.ReturnBay);
				}
				method.ILStream.Emit(OpCodes.Ret);
				method.Done();
			}
		}
        /// <summary>Compiles the body of all methods in this set.</summary>
        public void CompileBody()
        {
            if (Methods.Count == 0)
            {
                return;
            }
            MethodInfo initInfo = null;
            // Grab the first method so we can find the name:
            CompiledMethod tempMethod = Methods[0];

            if (tempMethod.Name == "new")
            {
                // Do we have INIT? if yes, output a call to it immediately.
                MethodOverloads set = tempMethod.Parent.FindMethodSet(".init");
                if (set != null)
                {
                    initInfo = set.Methods[0].getMethodInfo();
                }
            }
            else if (tempMethod.Name == ".init")
            {
                // Got constructors? if not make one now into a set so the above occurs.
                MethodOverloads set = tempMethod.Parent.FindMethodSet("new");
                if (set == null)
                {
                    set = new MethodOverloads(typeof(Void));
                    set.AddMethod(new CompiledMethod(tempMethod.Parent, "new", null, new BracketFragment(), null, true));
                    set.CompileBody();
                }
            }

            foreach (CompiledMethod method in Methods)
            {
                if (method.Name == "new")
                {
                    // This is a constructor. If the constructor body doesn't contain a base constructor call, add one like so.
                    if (!NewBaseCall(method.CodeBlock))
                    {
                        // Call the base constructor.
                        method.ILStream.Emit(OpCodes.Ldarg_0);
                        // Find the constructor with no parameters:
                        ConstructorInfo baseConstructor = method.Parent.BaseType.GetConstructor(new Type[0]);

                        if (baseConstructor == null)
                        {
                            method.CodeBlock.Error("You must call base.new(...); as " + method.Parent.BaseType + " doesn't have a constructor for 0 args.");
                        }

                        // Emit the call:
                        method.ILStream.Emit(OpCodes.Call, baseConstructor);
                    }
                }

                if (initInfo != null)
                {
                    method.ILStream.Emit(OpCodes.Ldarg_0);
                    method.ILStream.Emit(OpCodes.Call, initInfo);
                }

                bool returns = method.CodeBlock.CompileBody(method);
                if (!returns)
                {
                    if (!Types.IsVoid(ReturnType))
                    {
                        method.CodeBlock.Error("Not all code paths return a value in '" + method.Name + "'");
                    }
                }
                method.ILStream.MarkLabel(method.EndOfMethod);
                if (!Types.IsVoid(ReturnType))
                {
                    method.ILStream.Emit(OpCodes.Ldloc, method.ReturnBay);
                }
                method.ILStream.Emit(OpCodes.Ret);
                method.Done();
            }
        }