BOO-999
[boo.git] / src / Boo.Lang.Compiler / Steps / ImplementICallableOnCallableDefinitions.cs
blob1e6057fc47112564bb717dfa8e27e1a45510eac2
1 #region license
2 // Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Rodrigo B. de Oliveira nor the names of its
14 // contributors may be used to endorse or promote products derived from this
15 // software without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #endregion
29 namespace Boo.Lang.Compiler.Steps
31 using System.Diagnostics;
32 using Boo.Lang.Compiler.Ast;
33 using Boo.Lang.Compiler.TypeSystem;
35 public class ImplementICallableOnCallableDefinitions : AbstractVisitorCompilerStep
37 override public void Run()
39 Visit(CompileUnit);
42 override public void OnModule(Module node)
44 Visit(node.Members, NodeType.ClassDefinition);
47 override public void OnClassDefinition(ClassDefinition node)
49 Visit(node.Members, NodeType.ClassDefinition);
51 InternalCallableType type = node.Entity as InternalCallableType;
52 if (null != type)
54 ImplementICallableCall(type, node);
58 int GetByRefParamCount(CallableSignature signature)
60 int count = 0;
61 foreach (IParameter param in signature.Parameters)
63 if (param.IsByRef) ++count;
65 return count;
68 void ImplementICallableCall(InternalCallableType type, ClassDefinition node)
70 Method call = (Method)node.Members["Call"];
71 Debug.Assert(null != call);
72 Debug.Assert(0 == call.Body.Statements.Count);
74 CallableSignature signature = type.GetSignature();
75 int byRefCount = GetByRefParamCount(signature);
76 if (byRefCount > 0)
78 ImplementByRefICallableCall(call, type, node, signature, byRefCount);
80 else
82 ImplementRegularICallableCall(call, type, node, signature);
86 void ImplementByRefICallableCall(
87 Method call,
88 InternalCallableType type,
89 ClassDefinition node,
90 CallableSignature signature,
91 int byRefCount)
93 MethodInvocationExpression mie = CreateInvokeInvocation(type);
94 IParameter[] parameters = signature.Parameters;
95 ReferenceExpression args = CodeBuilder.CreateReference(call.Parameters[0]);
96 InternalLocal[] temporaries = new InternalLocal[byRefCount];
98 int byRefIndex = 0;
99 for (int i=0; i<parameters.Length; ++i)
101 SlicingExpression slice = CodeBuilder.CreateSlicing(args.CloneNode(), i);
103 IParameter parameter = parameters[i];
104 if (parameter.IsByRef)
106 IType tempType = parameter.Type;
107 if (tempType.IsByRef)
109 tempType = tempType.GetElementType();
111 temporaries[byRefIndex] = CodeBuilder.DeclareLocal(call,
112 "__temp_" + parameter.Name,
113 tempType);
115 call.Body.Add(
116 CodeBuilder.CreateAssignment(
117 CodeBuilder.CreateReference(temporaries[byRefIndex]),
118 CodeBuilder.CreateCast(
119 tempType,
120 slice)));
122 mie.Arguments.Add(
123 CodeBuilder.CreateReference(
124 temporaries[byRefIndex]));
126 ++byRefIndex;
128 else
130 mie.Arguments.Add(slice);
134 if (TypeSystemServices.VoidType == signature.ReturnType)
136 call.Body.Add(mie);
137 PropagateByRefParameterChanges(call, parameters, temporaries);
139 else
141 InternalLocal invokeReturnValue = CodeBuilder.DeclareLocal(call,
142 "__returnValue", signature.ReturnType);
143 call.Body.Add(
144 CodeBuilder.CreateAssignment(
145 CodeBuilder.CreateReference(invokeReturnValue),
146 mie));
147 PropagateByRefParameterChanges(call, parameters, temporaries);
148 call.Body.Add(
149 new ReturnStatement(
150 CodeBuilder.CreateReference(invokeReturnValue)));
154 void PropagateByRefParameterChanges(Method call, IParameter[] parameters, InternalLocal[] temporaries)
156 int byRefIndex = 0;
157 for (int i=0; i<parameters.Length; ++i)
159 if (!parameters[i].IsByRef) continue;
161 SlicingExpression slice = CodeBuilder.CreateSlicing(
162 CodeBuilder.CreateReference(call.Parameters[0]),
163 i);
164 call.Body.Add(
165 CodeBuilder.CreateAssignment(
166 slice,
167 CodeBuilder.CreateReference(temporaries[byRefIndex])));
168 ++byRefIndex;
172 void ImplementRegularICallableCall(
173 Method call,
174 InternalCallableType type,
175 ClassDefinition node,
176 CallableSignature signature)
178 MethodInvocationExpression mie = CreateInvokeInvocation(type);
179 IParameter[] parameters = signature.Parameters;
180 int fixedParametersLength = signature.AcceptVarArgs ? parameters.Length - 1 : parameters.Length;
181 for (int i=0; i<fixedParametersLength; ++i)
183 SlicingExpression slice = CodeBuilder.CreateSlicing(
184 CodeBuilder.CreateReference(call.Parameters[0]),
186 mie.Arguments.Add(slice);
189 if (signature.AcceptVarArgs)
191 if (parameters.Length == 1)
193 mie.Arguments.Add(CodeBuilder.CreateReference(call.Parameters[0]));
195 else
197 mie.Arguments.Add(
198 CodeBuilder.CreateMethodInvocation(
199 RuntimeServices_GetRange1,
200 CodeBuilder.CreateReference(call.Parameters[0]),
201 CodeBuilder.CreateIntegerLiteral(fixedParametersLength)));
205 if (TypeSystemServices.VoidType == signature.ReturnType)
207 call.Body.Add(mie);
209 else
211 call.Body.Add(new ReturnStatement(mie));
215 MethodInvocationExpression CreateInvokeInvocation(InternalCallableType type)
217 return CodeBuilder.CreateMethodInvocation(
218 CodeBuilder.CreateSelfReference(type),
219 type.GetInvokeMethod());
222 IMethod _RuntimeServices_GetRange1;
224 IMethod RuntimeServices_GetRange1
228 if (null == _RuntimeServices_GetRange1)
230 _RuntimeServices_GetRange1 = NameResolutionService.ResolveMethod(TypeSystemServices.RuntimeServicesType, "GetRange1");
232 return _RuntimeServices_GetRange1;