BOO-988: Added else block to the for and while statements, and include a suite of...
[boo.git] / src / Boo.Lang.Compiler / Steps / ExpandDuckTypedExpressions.cs
blob8e50ea4e72f2eb273301fb164820c2b75ac66e9a
1 #region license
2 // Copyright (c) 2003, 2004, 2005 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.
16 //
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
30 using Boo.Lang.Compiler.Ast;
31 using Boo.Lang.Compiler.TypeSystem;
33 namespace Boo.Lang.Compiler.Steps
35 /// <summary>
36 /// </summary>
37 public class ExpandDuckTypedExpressions : AbstractTransformerCompilerStep
39 protected IMethod RuntimeServices_Invoke;
40 protected IMethod RuntimeServices_InvokeCallable;
41 protected IMethod RuntimeServices_InvokeBinaryOperator;
42 protected IMethod RuntimeServices_InvokeUnaryOperator;
43 protected IMethod RuntimeServices_SetProperty;
44 protected IMethod RuntimeServices_GetProperty;
45 protected IMethod RuntimeServices_SetSlice;
46 protected IMethod RuntimeServices_GetSlice;
47 protected IType _duckTypingServicesType;
49 public ExpandDuckTypedExpressions()
53 public override void Initialize(CompilerContext context)
55 base.Initialize(context);
56 InitializeDuckTypingServices();
59 protected virtual void InitializeDuckTypingServices()
61 _duckTypingServicesType = GetDuckTypingServicesType();
62 RuntimeServices_Invoke = ResolveInvokeMethod();
63 RuntimeServices_InvokeCallable = ResolveMethod(_duckTypingServicesType, "InvokeCallable");
64 RuntimeServices_InvokeBinaryOperator = ResolveMethod(_duckTypingServicesType, "InvokeBinaryOperator");
65 RuntimeServices_InvokeUnaryOperator = ResolveMethod(_duckTypingServicesType, "InvokeUnaryOperator");
66 RuntimeServices_SetProperty = ResolveSetPropertyMethod();
67 RuntimeServices_GetProperty = ResolveGetPropertyMethod();
68 RuntimeServices_SetSlice = ResolveMethod(_duckTypingServicesType, "SetSlice");
69 RuntimeServices_GetSlice = ResolveMethod(_duckTypingServicesType, "GetSlice");
72 protected virtual IMethod ResolveInvokeMethod()
74 return ResolveMethod(_duckTypingServicesType, "Invoke");
77 protected virtual IMethod ResolveGetPropertyMethod()
79 return ResolveMethod(_duckTypingServicesType, "GetProperty");
82 protected virtual IMethod ResolveSetPropertyMethod()
84 return ResolveMethod(_duckTypingServicesType, "SetProperty");
87 protected virtual IType GetDuckTypingServicesType()
89 return TypeSystemServices.Map(typeof(Boo.Lang.Runtime.RuntimeServices));
92 protected virtual IMethod GetGetPropertyMethod()
94 return RuntimeServices_GetProperty;
97 protected virtual IMethod GetSetPropertyMethod()
99 return RuntimeServices_SetProperty;
102 protected IMethod ResolveMethod(IType type, string name)
104 IMethod method = NameResolutionService.ResolveMethod(type, name);
105 if (null == method) throw new System.ArgumentException(string.Format("Method '{0}' not found in type '{1}'", type, name));
106 return method;
109 public override void Run()
111 if (0 == Errors.Count)
113 Visit(CompileUnit);
117 override public void OnMethodInvocationExpression(MethodInvocationExpression node)
119 if (!IsDuckTyped(node.Target))
121 base.OnMethodInvocationExpression(node);
122 return;
125 if (TypeSystemServices.IsQuackBuiltin(node.Target))
127 ExpandQuackInvocation(node);
128 return;
131 base.OnMethodInvocationExpression(node);
133 if(node.GetAncestor(NodeType.Constructor) == null
134 || (node.Target.NodeType != NodeType.SelfLiteralExpression
135 && node.Target.NodeType != NodeType.SuperLiteralExpression)
136 || TypeSystemServices.GetOptionalEntity(node.Target) as IConstructor == null)
137 ExpandCallableInvocation(node);
140 private void ExpandCallableInvocation(MethodInvocationExpression node)
142 MethodInvocationExpression invoke = CodeBuilder.CreateMethodInvocation(
143 node.LexicalInfo,
144 RuntimeServices_InvokeCallable,
145 node.Target,
146 CodeBuilder.CreateObjectArray(node.Arguments));
148 Replace(invoke);
151 override public void LeaveSlicingExpression(SlicingExpression node)
153 if (!IsDuckTyped(node.Target)) return;
154 if (AstUtil.IsLhsOfAssignment(node)) return;
156 // todo
157 // a[foo]
158 // RuntimeServices.GetSlice(a, "", (foo,))
160 MethodInvocationExpression mie = CodeBuilder.CreateMethodInvocation(
161 node.LexicalInfo,
162 RuntimeServices_GetSlice,
163 GetSlicingTarget(node),
164 CodeBuilder.CreateStringLiteral(GetSlicingMemberName(node)),
165 GetArrayForIndices(node));
167 Replace(mie);
170 private static string GetSlicingMemberName(SlicingExpression node)
172 if (NodeType.MemberReferenceExpression == node.Target.NodeType)
174 MemberReferenceExpression mre = ((MemberReferenceExpression)node.Target);
175 return mre.Name;
177 return "";
180 private static Expression GetSlicingTarget(SlicingExpression node)
182 Expression target = node.Target;
183 if (NodeType.MemberReferenceExpression == target.NodeType)
185 MemberReferenceExpression mre = ((MemberReferenceExpression)target);
186 return mre.Target;
188 return target;
191 private ArrayLiteralExpression GetArrayForIndices(SlicingExpression node)
193 ArrayLiteralExpression args = new ArrayLiteralExpression();
194 foreach (Slice index in node.Indices)
196 if (AstUtil.IsComplexSlice(index))
198 throw CompilerErrorFactory.NotImplemented(index, "complex slice for duck");
200 args.Items.Add(index.Begin);
202 BindExpressionType(args, TypeSystemServices.ObjectArrayType);
203 return args;
206 override public void LeaveUnaryExpression(UnaryExpression node)
208 if (IsDuckTyped(node.Operand) &&
209 node.Operator == UnaryOperatorType.UnaryNegation)
211 MethodInvocationExpression mie = CodeBuilder.CreateMethodInvocation(
212 node.LexicalInfo,
213 RuntimeServices_InvokeUnaryOperator,
214 CodeBuilder.CreateStringLiteral(
215 AstUtil.GetMethodNameForOperator(node.Operator)),
216 node.Operand);
218 Replace(mie);
222 override public void LeaveBinaryExpression(BinaryExpression node)
224 if (BinaryOperatorType.Assign == node.Operator)
226 ProcessAssignment(node);
227 return;
230 if (!AstUtil.IsOverloadableOperator(node.Operator)) return;
231 if (!IsDuckTyped(node.Left) && !IsDuckTyped(node.Right)) return;
233 MethodInvocationExpression mie = CodeBuilder.CreateMethodInvocation(
234 node.LexicalInfo,
235 RuntimeServices_InvokeBinaryOperator,
236 CodeBuilder.CreateStringLiteral(
237 AstUtil.GetMethodNameForOperator(node.Operator)),
238 node.Left, node.Right);
239 Replace(mie);
242 private void ProcessAssignment(BinaryExpression node)
244 if (NodeType.SlicingExpression == node.Left.NodeType)
246 SlicingExpression slice = (SlicingExpression)node.Left;
247 if (IsDuckTyped(slice.Target))
249 ProcessDuckSlicingPropertySet(node);
252 else if (TypeSystemServices.IsQuackBuiltin(node.Left))
254 ProcessQuackPropertySet(node);
258 override public void LeaveMemberReferenceExpression(MemberReferenceExpression node)
260 if (!TypeSystemServices.IsQuackBuiltin(node)) return;
262 if (AstUtil.IsLhsOfAssignment(node)
263 || AstUtil.IsTargetOfSlicing(node)) return;
265 MethodInvocationExpression mie = CodeBuilder.CreateMethodInvocation(
266 node.LexicalInfo,
267 GetGetPropertyMethod(),
268 node.Target,
269 CodeBuilder.CreateStringLiteral(node.Name));
270 Replace(mie);
273 void ProcessDuckSlicingPropertySet(BinaryExpression node)
275 SlicingExpression slice = (SlicingExpression)node.Left;
277 ArrayLiteralExpression args = GetArrayForIndices(slice);
278 args.Items.Add(node.Right);
280 MethodInvocationExpression mie = CodeBuilder.CreateMethodInvocation(
281 node.LexicalInfo,
282 RuntimeServices_SetSlice,
283 GetSlicingTarget(slice),
284 CodeBuilder.CreateStringLiteral(GetSlicingMemberName(slice)),
285 args);
286 Replace(mie);
289 void ProcessQuackPropertySet(BinaryExpression node)
291 MemberReferenceExpression target = (MemberReferenceExpression)node.Left;
292 MethodInvocationExpression mie = CodeBuilder.CreateMethodInvocation(
293 node.LexicalInfo,
294 GetSetPropertyMethod(),
295 target.Target,
296 CodeBuilder.CreateStringLiteral(target.Name),
297 node.Right);
298 Replace(mie);
301 protected virtual void ExpandQuackInvocation(MethodInvocationExpression node)
303 ExpandQuackInvocation(node, RuntimeServices_Invoke);
306 protected virtual void ExpandQuackInvocation(MethodInvocationExpression node, IMethod runtimeInvoke)
308 Visit(node.Arguments);
309 Visit(node.NamedArguments);
311 MemberReferenceExpression target = node.Target as MemberReferenceExpression;
312 if (target == null) return;
314 ExpandMemberInvocation(node, target, runtimeInvoke);
317 private void ExpandMemberInvocation(MethodInvocationExpression node, MemberReferenceExpression target, IMethod runtimeInvoke)
319 target.Target = (Expression)VisitNode(target.Target);
320 node.Target = CodeBuilder.CreateMemberReference(runtimeInvoke);
322 Expression args = CodeBuilder.CreateObjectArray(node.Arguments);
323 node.Arguments.Clear();
324 node.Arguments.Add(target.Target);
325 node.Arguments.Add(CodeBuilder.CreateStringLiteral(target.Name));
326 node.Arguments.Add(args);
329 bool IsDuckTyped(Expression expression)
331 IType type = expression.ExpressionType;
332 return null != type && TypeSystemServices.IsDuckType(type);
335 private void BindDuck(Expression node)
337 BindExpressionType(node, TypeSystemServices.DuckType);
340 void Replace(Expression node)
342 BindDuck(node);
343 ReplaceCurrentNode(node);