~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonComponentWalker.cs

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
 
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
 
3
 
 
4
using System;
 
5
using System.Collections.Generic;
 
6
using System.ComponentModel;
 
7
using System.ComponentModel.Design;
 
8
using System.Drawing;
 
9
using System.Globalization;
 
10
using System.Reflection;
 
11
using System.Resources;
 
12
using System.Text;
 
13
using System.Windows.Forms;
 
14
 
 
15
using ICSharpCode.Core;
 
16
using ICSharpCode.Scripting;
 
17
using ICSharpCode.SharpDevelop;
 
18
using IronPython.Compiler.Ast;
 
19
 
 
20
namespace ICSharpCode.PythonBinding
 
21
{
 
22
        /// <summary>
 
23
        /// Visits the code's Python AST and creates a Windows Form.
 
24
        /// </summary>
 
25
        public class PythonComponentWalker : PythonWalker, IComponentWalker
 
26
        {
 
27
                IComponent component;
 
28
                PythonControlFieldExpression fieldExpression;
 
29
                IComponentCreator componentCreator;
 
30
                bool walkingAssignment;
 
31
                string componentName = String.Empty;
 
32
                PythonCodeDeserializer deserializer;
 
33
                ClassDefinition classDefinition;
 
34
                
 
35
                public PythonComponentWalker(IComponentCreator componentCreator)
 
36
                {
 
37
                        this.componentCreator = componentCreator;
 
38
                        deserializer = new PythonCodeDeserializer(componentCreator);
 
39
                }
 
40
                
 
41
                /// <summary>
 
42
                /// Creates a control either a UserControl or Form from the python code.
 
43
                /// </summary>
 
44
                public IComponent CreateComponent(string pythonCode)
 
45
                {                       
 
46
                        PythonParser parser = new PythonParser();
 
47
                        PythonAst ast = parser.CreateAst(@"Control.py", new StringTextBuffer(pythonCode));
 
48
                        ast.Walk(this);
 
49
                        
 
50
                        // Did we find the InitializeComponent method?
 
51
                        if (!FoundInitializeComponentMethod) {
 
52
                                throw new PythonComponentWalkerException("Unable to find InitializeComponents method.");
 
53
                        }
 
54
                        return component;
 
55
                }
 
56
                
 
57
                /// <summary>
 
58
                /// Gets the fully qualified name of the base class.
 
59
                /// </summary>
 
60
                public static string GetBaseClassName(ClassDefinition classDefinition)
 
61
                {
 
62
                        if (classDefinition.Bases.Count > 0) {
 
63
                                Expression baseClassExpression = classDefinition.Bases[0];
 
64
                                NameExpression nameExpression = baseClassExpression as NameExpression;
 
65
                                MemberExpression memberExpression = baseClassExpression as MemberExpression;
 
66
                                if (nameExpression != null) {
 
67
                                        return nameExpression.Name;
 
68
                                }
 
69
                                return PythonControlFieldExpression.GetMemberName(memberExpression);
 
70
                        }
 
71
                        return String.Empty;
 
72
                }
 
73
 
 
74
                public override bool Walk(ClassDefinition node)
 
75
                {
 
76
                        classDefinition = node;
 
77
                        componentName = node.Name;
 
78
                        node.Body.Walk(this);
 
79
                        return false;
 
80
                }
 
81
                                
 
82
                public override bool Walk(FunctionDefinition node)
 
83
                {
 
84
                        if (IsInitializeComponentMethod(node)) {
 
85
                                Type type = GetComponentType();
 
86
                                component = componentCreator.CreateComponent(type, componentName);
 
87
                                IResourceReader reader = componentCreator.GetResourceReader(CultureInfo.InvariantCulture);
 
88
                                if (reader != null) {
 
89
                                        reader.Dispose();
 
90
                                }
 
91
                                node.Body.Walk(this);
 
92
                        }
 
93
                        return false;
 
94
                }
 
95
                
 
96
                public override bool Walk(AssignmentStatement node)
 
97
                {                       
 
98
                        if (!FoundInitializeComponentMethod) {
 
99
                                return false;
 
100
                        }
 
101
                        
 
102
                        if (node.Left.Count > 0) {
 
103
                                MemberExpression lhsMemberExpression = node.Left[0] as MemberExpression;
 
104
                                NameExpression lhsNameExpression = node.Left[0] as NameExpression;
 
105
                                if (lhsMemberExpression != null) {
 
106
                                        fieldExpression = PythonControlFieldExpression.Create(lhsMemberExpression);
 
107
                                        WalkMemberExpressionAssignmentRhs(node.Right);
 
108
                                } else if (lhsNameExpression != null) {
 
109
                                        CallExpression callExpression = node.Right as CallExpression;
 
110
                                        if (callExpression != null) {
 
111
                                                object instance = CreateInstance(lhsNameExpression.Name.ToString(), callExpression);
 
112
                                                if (instance == null) {
 
113
                                                        ThrowCouldNotFindTypeException(callExpression.Target as MemberExpression);
 
114
                                                }
 
115
                                        }
 
116
                                }
 
117
                        }
 
118
                        return false;
 
119
                }
 
120
                
 
121
                public override bool Walk(ConstantExpression node)
 
122
                {
 
123
                        if (!FoundInitializeComponentMethod) {
 
124
                                return false;
 
125
                        }
 
126
                        
 
127
                        fieldExpression.SetPropertyValue(componentCreator, node.Value);
 
128
                        return false;
 
129
                }
 
130
                
 
131
                public override bool Walk(CallExpression node)
 
132
                {                       
 
133
                        if (!FoundInitializeComponentMethod) {
 
134
                                return false;
 
135
                        }
 
136
                                
 
137
                        if (walkingAssignment) {
 
138
                                WalkAssignmentRhs(node);
 
139
                        } else {
 
140
                                WalkMethodCall(node);
 
141
                        }
 
142
                        return false;
 
143
                }
 
144
                
 
145
                public override bool Walk(NameExpression node)
 
146
                {
 
147
                        if (!FoundInitializeComponentMethod) {
 
148
                                return false;
 
149
                        }
 
150
                        
 
151
                        fieldExpression.SetPropertyValue(componentCreator, node);
 
152
                        return false;
 
153
                }
 
154
                
 
155
                /// <summary>
 
156
                /// Walks a statement of the form:
 
157
                /// 
 
158
                /// self.a += self.b
 
159
                /// </summary>
 
160
                public override bool Walk(AugmentedAssignStatement node)
 
161
                {
 
162
                        if (!FoundInitializeComponentMethod) {
 
163
                                return false;
 
164
                        }
 
165
                        
 
166
                        MemberExpression eventExpression = node.Left as MemberExpression;
 
167
                        string eventName = eventExpression.Name.ToString();
 
168
                        PythonControlFieldExpression field = PythonControlFieldExpression.Create(eventExpression);
 
169
                        
 
170
                        MemberExpression eventHandlerExpression = node.Right as MemberExpression;
 
171
                        string eventHandlerName = eventHandlerExpression.Name.ToString();
 
172
                        
 
173
                        IComponent currentComponent = fieldExpression.GetObject(componentCreator) as IComponent;
 
174
                        
 
175
                        EventDescriptor eventDescriptor = TypeDescriptor.GetEvents(currentComponent).Find(eventName, false);
 
176
                        PropertyDescriptor propertyDescriptor = componentCreator.GetEventProperty(eventDescriptor);
 
177
                        propertyDescriptor.SetValue(currentComponent, eventHandlerName);
 
178
                        return false;
 
179
                }               
 
180
                
 
181
                /// <summary>
 
182
                /// Walks the binary expression which is the right hand side of an assignment statement.
 
183
                /// </summary>
 
184
                void WalkAssignment(BinaryExpression binaryExpression)
 
185
                {
 
186
                        object value = deserializer.Deserialize(binaryExpression);
 
187
                        fieldExpression.SetPropertyValue(componentCreator, value);
 
188
                }
 
189
 
 
190
                /// <summary>
 
191
                /// Walks the right hand side of an assignment to a member expression.
 
192
                /// </summary>
 
193
                void WalkMemberExpressionAssignmentRhs(Expression rhs)
 
194
                {
 
195
                        MemberExpression rhsMemberExpression = rhs as MemberExpression;
 
196
                        if (rhsMemberExpression != null) {
 
197
                                object propertyValue = GetPropertyValueFromAssignmentRhs(rhsMemberExpression);
 
198
                                fieldExpression.SetPropertyValue(componentCreator, propertyValue);
 
199
                        } else {
 
200
                                walkingAssignment = true;
 
201
                                BinaryExpression binaryExpression = rhs as BinaryExpression;
 
202
                                if (binaryExpression != null) {
 
203
                                        WalkAssignment(binaryExpression);
 
204
                                } else {
 
205
                                        rhs.Walk(this);
 
206
                                }
 
207
                                walkingAssignment = false;
 
208
                        }
 
209
                }
 
210
                
 
211
                static bool IsInitializeComponentMethod(FunctionDefinition node)
 
212
                {
 
213
                        string name = node.Name.ToString().ToLowerInvariant();
 
214
                        return name == "initializecomponent" || name == "initializecomponents";
 
215
                }
 
216
 
 
217
                /// <summary>
 
218
                /// Adds a component to the list of created objects.
 
219
                /// </summary>
 
220
                void AddComponent(string name, object obj)
 
221
                {
 
222
                        IComponent component = obj as IComponent;
 
223
                        if (component != null) {
 
224
                                string variableName = PythonControlFieldExpression.GetVariableName(name);
 
225
                                componentCreator.Add(component, variableName);
 
226
                        }
 
227
                }
 
228
                
 
229
                /// <summary>
 
230
                /// Gets the type for the control being walked.
 
231
                /// </summary>
 
232
                Type GetComponentType()
 
233
                {
 
234
                        string baseClass = GetBaseClassName(classDefinition);
 
235
                        Type type = componentCreator.GetType(baseClass);
 
236
                        if (type != null) {
 
237
                                return type;
 
238
                        }
 
239
                        
 
240
                        if (baseClass.Contains("UserControl")) {
 
241
                                return typeof(UserControl);
 
242
                        }
 
243
                        return typeof(Form);
 
244
                }
 
245
                
 
246
                /// <summary>
 
247
                /// Gets the property value from the member expression. The member expression is taken from the
 
248
                /// right hand side of an assignment.
 
249
                /// </summary>
 
250
                object GetPropertyValueFromAssignmentRhs(MemberExpression memberExpression)
 
251
                {
 
252
                        return deserializer.Deserialize(memberExpression);
 
253
                }
 
254
                
 
255
                /// <summary>
 
256
                /// Walks the right hand side of an assignment where the assignment expression is a call expression.
 
257
                /// Typically the call expression will be a constructor call.
 
258
                /// 
 
259
                /// Constructor call: System.Windows.Forms.Form()
 
260
                /// </summary>
 
261
                void WalkAssignmentRhs(CallExpression node)
 
262
                {
 
263
                        MemberExpression memberExpression = node.Target as MemberExpression;
 
264
                        if (memberExpression != null) {
 
265
                                string name = fieldExpression.GetInstanceName(componentCreator);
 
266
                                object instance = CreateInstance(name, node);
 
267
                                if (instance != null) {
 
268
                                        if (!fieldExpression.SetPropertyValue(componentCreator, instance)) {
 
269
                                                AddComponent(fieldExpression.MemberName, instance);
 
270
                                        }
 
271
                                } else {
 
272
                                        object obj = deserializer.Deserialize(node);
 
273
                                        if (obj != null) {
 
274
                                                fieldExpression.SetPropertyValue(componentCreator, obj);
 
275
                                        } else if (IsResource(memberExpression)) {
 
276
                                                fieldExpression.SetPropertyValue(componentCreator, GetResource(node));
 
277
                                        } else {
 
278
                                                ThrowCouldNotFindTypeException(memberExpression);
 
279
                                        }
 
280
                                }
 
281
                        } else if (node.Target is IndexExpression) {
 
282
                                WalkArrayAssignmentRhs(node);
 
283
                        }
 
284
                }
 
285
                
 
286
                /// <summary>
 
287
                /// Walks a method call. Typical method calls are:
 
288
                /// 
 
289
                /// self._menuItem1.Items.AddRange(...)
 
290
                /// 
 
291
                /// This method will execute the method call.
 
292
                /// </summary>
 
293
                void WalkMethodCall(CallExpression node)
 
294
                {
 
295
                        // Try to get the object being called. Try the form first then
 
296
                        // look for other controls.
 
297
                        object member = PythonControlFieldExpression.GetMember(component, node);
 
298
                        PythonControlFieldExpression field = PythonControlFieldExpression.Create(node);
 
299
                        if (member == null) {
 
300
                                member = field.GetMember(componentCreator);
 
301
                        }
 
302
                        
 
303
                        // Execute the method on the object.
 
304
                        if (member != null) {
 
305
                                object[] args = deserializer.GetArguments(node).ToArray();
 
306
                                InvokeMethod(member, field.MethodName, args);
 
307
                        }
 
308
                }
 
309
                
 
310
                void InvokeMethod(object obj, string name, object[] args)
 
311
                {
 
312
                        Type type = obj.GetType();
 
313
                        try {
 
314
                                type.InvokeMember(name, BindingFlags.InvokeMethod, Type.DefaultBinder, obj, args);
 
315
                        } catch (MissingMethodException ex) {
 
316
                                // Look for an explicitly implemented interface.
 
317
                                MethodInfo method = FindInterfaceMethod(type, name);
 
318
                                if (method != null) {
 
319
                                        method.Invoke(obj, args);
 
320
                                } else {
 
321
                                        throw ex;
 
322
                                }
 
323
                        }
 
324
                }
 
325
                
 
326
                /// <summary>
 
327
                /// Looks for an explicitly implemented interface.
 
328
                /// </summary>
 
329
                MethodInfo FindInterfaceMethod(Type type, string name)
 
330
                {
 
331
                        string nameMatch = "." + name;
 
332
                        foreach (MethodInfo method in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)) {
 
333
                                if (method.Name.EndsWith(nameMatch)) {
 
334
                                        return method;
 
335
                                }
 
336
                        }
 
337
                        return null;
 
338
                }
 
339
                
 
340
                /// <summary>
 
341
                /// Creates a new instance with the specified name.
 
342
                /// </summary>
 
343
                object CreateInstance(string name, CallExpression node)
 
344
                {
 
345
                        MemberExpression memberExpression = node.Target as MemberExpression;
 
346
                        if (memberExpression != null) {
 
347
                                string typeName = PythonControlFieldExpression.GetMemberName(memberExpression);
 
348
                                Type type = componentCreator.GetType(typeName);
 
349
                                if (type != null) {
 
350
                                        if (type.IsAssignableFrom(typeof(ComponentResourceManager))) {
 
351
                                                return componentCreator.CreateInstance(type, new object[0], name, false);
 
352
                                        }
 
353
                                        List<object> args = deserializer.GetArguments(node);
 
354
                                        return componentCreator.CreateInstance(type, args, name, false);
 
355
                                }
 
356
                        }
 
357
                        return null;
 
358
                }
 
359
                
 
360
                bool FoundInitializeComponentMethod {
 
361
                        get { return component != null; }
 
362
                }
 
363
                
 
364
                /// <summary>
 
365
                /// Returns true if the expression is of the form:
 
366
                /// 
 
367
                /// resources.GetObject(...) or
 
368
                /// resources.GetString(...)
 
369
                /// </summary>
 
370
                bool IsResource(MemberExpression memberExpression)
 
371
                {
 
372
                        string fullName = PythonControlFieldExpression.GetMemberName(memberExpression);
 
373
                        return fullName.StartsWith("resources.", StringComparison.InvariantCultureIgnoreCase);
 
374
                }
 
375
                
 
376
                object GetResource(CallExpression callExpression)
 
377
                {
 
378
                        IResourceReader reader = componentCreator.GetResourceReader(CultureInfo.InvariantCulture);
 
379
                        if (reader != null) {
 
380
                                using (ResourceSet resources = new ResourceSet(reader)) {
 
381
                                        List<object> args = deserializer.GetArguments(callExpression);
 
382
                                        return resources.GetObject(args[0] as String);
 
383
                                }
 
384
                        }
 
385
                        return null;
 
386
                }
 
387
                
 
388
                /// <summary>
 
389
                /// Walks the right hand side of an assignment when the assignment is an array creation.
 
390
                /// </summary>
 
391
                void WalkArrayAssignmentRhs(CallExpression callExpression)
 
392
                {
 
393
                        object array = deserializer.Deserialize(callExpression);
 
394
                        fieldExpression.SetPropertyValue(componentCreator, array);      
 
395
                }
 
396
                
 
397
                void ThrowCouldNotFindTypeException(MemberExpression memberExpression)
 
398
                {
 
399
                        string typeName = PythonControlFieldExpression.GetMemberName(memberExpression);
 
400
                        throw new PythonComponentWalkerException(String.Format(StringParser.Parse("${res:ICSharpCode.PythonBinding.UnknownTypeName}"), typeName));
 
401
                }
 
402
        }
 
403
}