/// <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); }
/// <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]); }
/// <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)); }
/// <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); }
/// <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>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(); } }