#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

403 lines
12 KiB

// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Text;
using System.Windows.Forms;
using ICSharpCode.Core;
using ICSharpCode.Scripting;
using ICSharpCode.SharpDevelop;
using IronPython.Compiler.Ast;
namespace ICSharpCode.PythonBinding
{
/// <summary>
/// Visits the code's Python AST and creates a Windows Form.
/// </summary>
public class PythonComponentWalker : PythonWalker, IComponentWalker
{
IComponent component;
PythonControlFieldExpression fieldExpression;
IComponentCreator componentCreator;
bool walkingAssignment;
string componentName = String.Empty;
PythonCodeDeserializer deserializer;
ClassDefinition classDefinition;
public PythonComponentWalker(IComponentCreator componentCreator)
{
this.componentCreator = componentCreator;
deserializer = new PythonCodeDeserializer(componentCreator);
}
/// <summary>
/// Creates a control either a UserControl or Form from the python code.
/// </summary>
public IComponent CreateComponent(string pythonCode)
{
PythonParser parser = new PythonParser();
PythonAst ast = parser.CreateAst(@"Control.py", new StringTextBuffer(pythonCode));
ast.Walk(this);
// Did we find the InitializeComponent method?
if (!FoundInitializeComponentMethod) {
throw new PythonComponentWalkerException("Unable to find InitializeComponents method.");
}
return component;
}
/// <summary>
/// Gets the fully qualified name of the base class.
/// </summary>
public static string GetBaseClassName(ClassDefinition classDefinition)
{
if (classDefinition.Bases.Count > 0) {
Expression baseClassExpression = classDefinition.Bases[0];
NameExpression nameExpression = baseClassExpression as NameExpression;
MemberExpression memberExpression = baseClassExpression as MemberExpression;
if (nameExpression != null) {
return nameExpression.Name;
}
return PythonControlFieldExpression.GetMemberName(memberExpression);
}
return String.Empty;
}
public override bool Walk(ClassDefinition node)
{
classDefinition = node;
componentName = node.Name;
node.Body.Walk(this);
return false;
}
public override bool Walk(FunctionDefinition node)
{
if (IsInitializeComponentMethod(node)) {
Type type = GetComponentType();
component = componentCreator.CreateComponent(type, componentName);
IResourceReader reader = componentCreator.GetResourceReader(CultureInfo.InvariantCulture);
if (reader != null) {
reader.Dispose();
}
node.Body.Walk(this);
}
return false;
}
public override bool Walk(AssignmentStatement node)
{
if (!FoundInitializeComponentMethod) {
return false;
}
if (node.Left.Count > 0) {
MemberExpression lhsMemberExpression = node.Left[0] as MemberExpression;
NameExpression lhsNameExpression = node.Left[0] as NameExpression;
if (lhsMemberExpression != null) {
fieldExpression = PythonControlFieldExpression.Create(lhsMemberExpression);
WalkMemberExpressionAssignmentRhs(node.Right);
} else if (lhsNameExpression != null) {
CallExpression callExpression = node.Right as CallExpression;
if (callExpression != null) {
object instance = CreateInstance(lhsNameExpression.Name.ToString(), callExpression);
if (instance == null) {
ThrowCouldNotFindTypeException(callExpression.Target as MemberExpression);
}
}
}
}
return false;
}
public override bool Walk(ConstantExpression node)
{
if (!FoundInitializeComponentMethod) {
return false;
}
fieldExpression.SetPropertyValue(componentCreator, node.Value);
return false;
}
public override bool Walk(CallExpression node)
{
if (!FoundInitializeComponentMethod) {
return false;
}
if (walkingAssignment) {
WalkAssignmentRhs(node);
} else {
WalkMethodCall(node);
}
return false;
}
public override bool Walk(NameExpression node)
{
if (!FoundInitializeComponentMethod) {
return false;
}
fieldExpression.SetPropertyValue(componentCreator, node);
return false;
}
/// <summary>
/// Walks a statement of the form:
///
/// self.a += self.b
/// </summary>
public override bool Walk(AugmentedAssignStatement node)
{
if (!FoundInitializeComponentMethod) {
return false;
}
MemberExpression eventExpression = node.Left as MemberExpression;
string eventName = eventExpression.Name.ToString();
fieldExpression = PythonControlFieldExpression.Create(eventExpression);
MemberExpression eventHandlerExpression = node.Right as MemberExpression;
string eventHandlerName = eventHandlerExpression.Name.ToString();
IComponent currentComponent = fieldExpression.GetObject(componentCreator) as IComponent;
EventDescriptor eventDescriptor = TypeDescriptor.GetEvents(currentComponent).Find(eventName, false);
PropertyDescriptor propertyDescriptor = componentCreator.GetEventProperty(eventDescriptor);
propertyDescriptor.SetValue(currentComponent, eventHandlerName);
return false;
}
/// <summary>
/// Walks the binary expression which is the right hand side of an assignment statement.
/// </summary>
void WalkAssignment(BinaryExpression binaryExpression)
{
object value = deserializer.Deserialize(binaryExpression);
fieldExpression.SetPropertyValue(componentCreator, value);
}
/// <summary>
/// Walks the right hand side of an assignment to a member expression.
/// </summary>
void WalkMemberExpressionAssignmentRhs(Expression rhs)
{
MemberExpression rhsMemberExpression = rhs as MemberExpression;
if (rhsMemberExpression != null) {
object propertyValue = GetPropertyValueFromAssignmentRhs(rhsMemberExpression);
fieldExpression.SetPropertyValue(componentCreator, propertyValue);
} else {
walkingAssignment = true;
BinaryExpression binaryExpression = rhs as BinaryExpression;
if (binaryExpression != null) {
WalkAssignment(binaryExpression);
} else {
rhs.Walk(this);
}
walkingAssignment = false;
}
}
static bool IsInitializeComponentMethod(FunctionDefinition node)
{
string name = node.Name.ToString().ToLowerInvariant();
return name == "initializecomponent" || name == "initializecomponents";
}
/// <summary>
/// Adds a component to the list of created objects.
/// </summary>
void AddComponent(string name, object obj)
{
IComponent component = obj as IComponent;
if (component != null) {
string variableName = PythonControlFieldExpression.GetVariableName(name);
componentCreator.Add(component, variableName);
}
}
/// <summary>
/// Gets the type for the control being walked.
/// </summary>
Type GetComponentType()
{
string baseClass = GetBaseClassName(classDefinition);
Type type = componentCreator.GetType(baseClass);
if (type != null) {
return type;
}
if (baseClass.Contains("UserControl")) {
return typeof(UserControl);
}
return typeof(Form);
}
/// <summary>
/// Gets the property value from the member expression. The member expression is taken from the
/// right hand side of an assignment.
/// </summary>
object GetPropertyValueFromAssignmentRhs(MemberExpression memberExpression)
{
return deserializer.Deserialize(memberExpression);
}
/// <summary>
/// Walks the right hand side of an assignment where the assignment expression is a call expression.
/// Typically the call expression will be a constructor call.
///
/// Constructor call: System.Windows.Forms.Form()
/// </summary>
void WalkAssignmentRhs(CallExpression node)
{
MemberExpression memberExpression = node.Target as MemberExpression;
if (memberExpression != null) {
string name = fieldExpression.GetInstanceName(componentCreator);
object instance = CreateInstance(name, node);
if (instance != null) {
if (!fieldExpression.SetPropertyValue(componentCreator, instance)) {
AddComponent(fieldExpression.MemberName, instance);
}
} else {
object obj = deserializer.Deserialize(node);
if (obj != null) {
fieldExpression.SetPropertyValue(componentCreator, obj);
} else if (IsResource(memberExpression)) {
fieldExpression.SetPropertyValue(componentCreator, GetResource(node));
} else {
ThrowCouldNotFindTypeException(memberExpression);
}
}
} else if (node.Target is IndexExpression) {
WalkArrayAssignmentRhs(node);
}
}
/// <summary>
/// Walks a method call. Typical method calls are:
///
/// self._menuItem1.Items.AddRange(...)
///
/// This method will execute the method call.
/// </summary>
void WalkMethodCall(CallExpression node)
{
// Try to get the object being called. Try the form first then
// look for other controls.
object member = PythonControlFieldExpression.GetMember(component, node);
PythonControlFieldExpression field = PythonControlFieldExpression.Create(node);
if (member == null) {
member = field.GetMember(componentCreator);
}
// Execute the method on the object.
if (member != null) {
object[] args = deserializer.GetArguments(node).ToArray();
InvokeMethod(member, field.MethodName, args);
}
}
void InvokeMethod(object obj, string name, object[] args)
{
Type type = obj.GetType();
try {
type.InvokeMember(name, BindingFlags.InvokeMethod, Type.DefaultBinder, obj, args);
} catch (MissingMethodException ex) {
// Look for an explicitly implemented interface.
MethodInfo method = FindInterfaceMethod(type, name);
if (method != null) {
method.Invoke(obj, args);
} else {
throw ex;
}
}
}
/// <summary>
/// Looks for an explicitly implemented interface.
/// </summary>
MethodInfo FindInterfaceMethod(Type type, string name)
{
string nameMatch = "." + name;
foreach (MethodInfo method in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)) {
if (method.Name.EndsWith(nameMatch)) {
return method;
}
}
return null;
}
/// <summary>
/// Creates a new instance with the specified name.
/// </summary>
object CreateInstance(string name, CallExpression node)
{
MemberExpression memberExpression = node.Target as MemberExpression;
if (memberExpression != null) {
string typeName = PythonControlFieldExpression.GetMemberName(memberExpression);
Type type = componentCreator.GetType(typeName);
if (type != null) {
if (type.IsAssignableFrom(typeof(ComponentResourceManager))) {
return componentCreator.CreateInstance(type, new object[0], name, false);
}
List<object> args = deserializer.GetArguments(node);
return componentCreator.CreateInstance(type, args, name, false);
}
}
return null;
}
bool FoundInitializeComponentMethod {
get { return component != null; }
}
/// <summary>
/// Returns true if the expression is of the form:
///
/// resources.GetObject(...) or
/// resources.GetString(...)
/// </summary>
bool IsResource(MemberExpression memberExpression)
{
string fullName = PythonControlFieldExpression.GetMemberName(memberExpression);
return fullName.StartsWith("resources.", StringComparison.InvariantCultureIgnoreCase);
}
object GetResource(CallExpression callExpression)
{
IResourceReader reader = componentCreator.GetResourceReader(CultureInfo.InvariantCulture);
if (reader != null) {
using (ResourceSet resources = new ResourceSet(reader)) {
List<object> args = deserializer.GetArguments(callExpression);
return resources.GetObject(args[0] as String);
}
}
return null;
}
/// <summary>
/// Walks the right hand side of an assignment when the assignment is an array creation.
/// </summary>
void WalkArrayAssignmentRhs(CallExpression callExpression)
{
object array = deserializer.Deserialize(callExpression);
fieldExpression.SetPropertyValue(componentCreator, array);
}
void ThrowCouldNotFindTypeException(MemberExpression memberExpression)
{
string typeName = PythonControlFieldExpression.GetMemberName(memberExpression);
throw new PythonComponentWalkerException(String.Format(StringParser.Parse("${res:ICSharpCode.PythonBinding.UnknownTypeName}"), typeName));
}
}
}