diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj b/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj
index dd2fef1d06..4a65766564 100644
--- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj
@@ -100,6 +100,7 @@
+
diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/ConstructorInfo.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/ConstructorInfo.cs
index 415982fcfd..ba9ce7b48d 100644
--- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/ConstructorInfo.cs
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/ConstructorInfo.cs
@@ -9,45 +9,60 @@ namespace ICSharpCode.PythonBinding
{
public class PythonConstructorInfo
{
- ConstructorDeclaration constructor;
- List fields = new List();
-
- PythonConstructorInfo(ConstructorDeclaration constructor, List fields)
+ private ConstructorDeclaration constructor;
+ private List fields = new List();
+ private List properties = new List();
+
+ private PythonConstructorInfo(ConstructorDeclaration constructor,
+ List fields, List properties)
{
this.constructor = constructor;
this.fields = fields;
+ this.properties = properties;
}
-
+
///
- /// Gets the constructor information from a type declaration. Returns null if there is no
- /// constructor defined or if there are no fields defined.
+ /// Gets the constructor information from a type declaration.
///
+ /// Returns null if there is no constructor defined or
+ /// if there are no fields/properties defined.
public static PythonConstructorInfo GetConstructorInfo(TypeDeclaration type)
{
List fields = new List();
+ List properties = new List();
ConstructorDeclaration constructor = null;
foreach (INode node in type.Children) {
ConstructorDeclaration currentConstructor = node as ConstructorDeclaration;
FieldDeclaration field = node as FieldDeclaration;
+ PropertyDeclaration property = node as PropertyDeclaration;
if (currentConstructor != null) {
constructor = currentConstructor;
} else if (field != null) {
fields.Add(field);
+ } else if (property != null) {
+ if (property.HasGetRegion && property.GetRegion.Block.IsNull
+ && property.HasSetRegion && property.SetRegion.Block.IsNull) {
+ properties.Add(property); // basically anonymous backed property
+ }
}
}
-
- if ((fields.Count > 0) || (constructor != null)) {
- return new PythonConstructorInfo(constructor, fields);
+
+ if ((properties.Count > 0) || (fields.Count > 0) || (constructor != null)) {
+ return new PythonConstructorInfo(constructor, fields, properties);
}
return null;
}
-
+
public ConstructorDeclaration Constructor {
get { return constructor; }
}
-
+
public List Fields {
get { return fields; }
}
+
+ public List Properties {
+ get { return properties; }
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/NRefactoryToPythonConverter.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/NRefactoryToPythonConverter.cs
index 0b1455a6c6..8d882ca9fa 100644
--- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/NRefactoryToPythonConverter.cs
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/NRefactoryToPythonConverter.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
+using System.Text.RegularExpressions;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Parser;
@@ -21,43 +22,62 @@ namespace ICSharpCode.PythonBinding
{
string indentString = "\t";
PythonCodeBuilder codeBuilder;
-
+
// Holds the constructor for the class being converted. This is used to identify class fields.
PythonConstructorInfo constructorInfo;
-
+
// Holds the parameters of the current method. This is used to identify
// references to fields or parameters.
List methodParameters = new List();
MethodDeclaration currentMethod;
+ bool methodHasOutputParameters = false;
// Holds the names of any parameters defined for this class.
List propertyNames = new List();
-
+
SupportedLanguage language;
List entryPointMethods;
SpecialNodesInserter specialNodesInserter;
INode currentNode;
List xmlDocComments = new List();
-
+
+ // helpers for managing current types
+ bool clrImported = false;
+ TypeDeclaration currentType;
+ List importLibraries = new List();
+ Dictionary typeNameMap = new Dictionary();
+
+ // flag for accumulating statements which should generated before and
+ // after the current statement
+ bool accumulatePostfixStatements = false;
+ List postfixStatements = new List();
+ PrefixExpressionExtractor prefixExpressionExtractor = new PrefixExpressionExtractor();
+
+ // flag during yield statement to suppress child return statements
+ private bool suppressReturn = false;
+
+ // flag during case statement to suppress child break statements
+ private bool suppressBreak = false;
+
static readonly string Docstring = "\"\"\"";
public NRefactoryToPythonConverter(SupportedLanguage language)
{
this.language = language;
}
-
+
public NRefactoryToPythonConverter()
{
}
-
+
///
/// Gets or sets the source language that will be converted to python.
///
public SupportedLanguage SupportedLanguage {
get { return language; }
}
-
+
///
/// Creates either C# to Python or VB.NET to Python converter based on the filename extension that is to be converted.
///
@@ -69,7 +89,7 @@ namespace ICSharpCode.PythonBinding
}
return null;
}
-
+
///
/// Only C# (.cs) or VB.NET (.vb) files can be converted.
///
@@ -82,7 +102,7 @@ namespace ICSharpCode.PythonBinding
}
return false;
}
-
+
///
/// Gets or sets the string that will be used to indent the generated Python code.
///
@@ -108,7 +128,7 @@ namespace ICSharpCode.PythonBinding
return parser.CompilationUnit;
}
}
-
+
///
/// Converts the source code to Python.
///
@@ -116,7 +136,7 @@ namespace ICSharpCode.PythonBinding
{
return Convert(source, language);
}
-
+
///
/// Converts the source code to Python.
///
@@ -124,19 +144,39 @@ namespace ICSharpCode.PythonBinding
{
// Convert to NRefactory code DOM.
CompilationUnit unit = GenerateCompilationUnit(source, language);
-
+
SpecialOutputVisitor specialOutputVisitor = new SpecialOutputVisitor(this);
specialNodesInserter = new SpecialNodesInserter(unit.UserData as List, specialOutputVisitor);
-
+
+ clrImported = false;
+ importLibraries = new List();
+ typeNameMap = new Dictionary();
+
// Convert to Python code.
entryPointMethods = new List();
codeBuilder = new PythonCodeBuilder();
codeBuilder.IndentString = indentString;
+ InsertStandardImports();
unit.AcceptVisitor(this, null);
-
+
return codeBuilder.ToString().Trim();
}
-
+
+ ///
+ /// Standard imports to maximize code compatibility
+ ///
+ private void InsertStandardImports()
+ {
+ codeBuilder.AppendIndentedLine("import System");
+
+ typeNameMap.Add("System.Int32", "int");
+ typeNameMap.Add("System.String", "str");
+ typeNameMap.Add("System.Object", "object");
+ typeNameMap.Add("Int32", "int");
+ typeNameMap.Add("String", "str");
+ typeNameMap.Add("Object", "object");
+ }
+
///
/// Gets a list of possible entry point methods found when converting the
/// python source code.
@@ -144,7 +184,7 @@ namespace ICSharpCode.PythonBinding
public ReadOnlyCollection EntryPointMethods {
get { return entryPointMethods.AsReadOnly(); }
}
-
+
///
/// Generates code to call the main entry point.
///
@@ -159,7 +199,7 @@ namespace ICSharpCode.PythonBinding
code.Append("None");
}
code.Append(')');
-
+
return code.ToString();
}
@@ -212,30 +252,86 @@ namespace ICSharpCode.PythonBinding
return "==";
}
}
-
+
public override object TrackedVisitAddHandlerStatement(AddHandlerStatement addHandlerStatement, object data)
{
Console.WriteLine("VisitAddHandlerStatement");
return null;
}
-
+
public override object TrackedVisitAddressOfExpression(AddressOfExpression addressOfExpression, object data)
{
Console.WriteLine("VisitAddressOfExpression");
return null;
}
-
+
public override object TrackedVisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, object data)
{
- Console.WriteLine("VisitAnonymousMethodExpression");
+ bool isReference = accumulatePostfixStatements && !(anonymousMethodExpression.Parent is Statement);
+ if (!isReference)
+ Append("def ");
+
+ // handle known special cases. Namely variable initialize
+ if (anonymousMethodExpression.Parent is ObjectCreateExpression) {
+ // Use the CreateType type to generate the anonymous method name
+ var objectCreationExpr = anonymousMethodExpression.Parent as ObjectCreateExpression;
+ var match = Regex.Match(GetTypeName(objectCreationExpr.CreateType), @"\.?(\w+)$", RegexOptions.Singleline);
+ string methodName = (match.Success) ? match.Groups[0].ToString()
+ : Regex.Replace(GetTypeName(objectCreationExpr.CreateType), @"\W", "");
+ if (methodName.StartsWith("System")) methodName = methodName.Substring(6);
+ methodName += "_" + anonymousMethodExpression.StartLocation.Line.ToString()
+ + "_" + anonymousMethodExpression.StartLocation.Column.ToString();
+ Append(methodName);
+ } else if (anonymousMethodExpression.Parent is VariableDeclaration) {
+ // this will still generate a "func = func" statement after definition but is harmless in python
+ var varDecl = anonymousMethodExpression.Parent as VariableDeclaration;
+ Append(varDecl.Name);
+ //varDecl.Name.AcceptVisitor(this, data);
+ } else {
+ string methodName = "anonMethod_" + anonymousMethodExpression.StartLocation.Line.ToString()
+ + "_" + anonymousMethodExpression.StartLocation.Column.ToString();
+ Append(methodName);
+ }
+
+ // method name reference written during normal passes
+ // definition written in prefix pass
+ if (isReference)
+ return null;
+
+ // Add the parameters.
+ Append("(");
+ for (int i = 0; i < anonymousMethodExpression.Parameters.Count; ++i) {
+ if (i > 0) {
+ Append(", ");
+ }
+ Append(anonymousMethodExpression.Parameters[i].ParameterName);
+ }
+ Append("):");
+
+ // merge parameters with parent method with anonymous due to closures
+ // push old parameters on stack while we write out the inline method
+ var oldMethodParameters = methodParameters;
+ methodParameters = new List(anonymousMethodExpression.Parameters);
+ methodParameters.AddRange(methodParameters);
+ AppendLine();
+
+ IncreaseIndent();
+ AppendDocstring(xmlDocComments);
+ if (anonymousMethodExpression.Body.Children.Count > 0) {
+ anonymousMethodExpression.Body.AcceptVisitor(this, data);
+ } else {
+ AppendIndentedPassStatement();
+ }
+ DecreaseIndent();
+ methodParameters = oldMethodParameters;
return null;
}
-
+
public override object TrackedVisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression, object data)
{
string arrayType = GetTypeName(arrayCreateExpression.CreateType);
if (arrayCreateExpression.ArrayInitializer.CreateExpressions.Count == 0) {
- Append("Array.CreateInstance(" + arrayType);
+ Append(GetTypeName("System.Array") + ".CreateInstance(" + arrayType);
if (arrayCreateExpression.Arguments.Count > 0) {
foreach (Expression expression in arrayCreateExpression.Arguments) {
Append(", ");
@@ -246,8 +342,8 @@ namespace ICSharpCode.PythonBinding
Append(", 0)");
}
} else {
- Append("Array[" + arrayType + "]");
-
+ Append(GetTypeName("System.Array") + "[" + arrayType + "]");
+
// Add initializers.
Append("((");
bool firstItem = true;
@@ -263,11 +359,14 @@ namespace ICSharpCode.PythonBinding
}
return null;
}
-
+
public override object TrackedVisitAssignmentExpression(AssignmentExpression assignmentExpression, object data)
{
switch (assignmentExpression.Op) {
case AssignmentOperatorType.Assign:
+ if (assignmentExpression.Right is InvocationExpression) {
+ return CreateInvocationAssignment(assignmentExpression, data);
+ }
return CreateSimpleAssignment(assignmentExpression, "=", data);
case AssignmentOperatorType.Add:
if (IsAddEventHandler(assignmentExpression)) {
@@ -301,15 +400,15 @@ namespace ICSharpCode.PythonBinding
case AssignmentOperatorType.Power:
return CreateSimpleAssignment(assignmentExpression, "**=", data);
}
-
+
return null;
}
-
+
public override object TrackedVisitAttribute(ICSharpCode.NRefactory.Ast.Attribute attribute, object data)
{
return null;
}
-
+
public override object TrackedVisitAttributeSection(AttributeSection attributeSection, object data)
{
return null;
@@ -325,7 +424,7 @@ namespace ICSharpCode.PythonBinding
Append("self");
return null;
}
-
+
public override object TrackedVisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
{
binaryOperatorExpression.Left.AcceptVisitor(this, data);
@@ -335,7 +434,7 @@ namespace ICSharpCode.PythonBinding
binaryOperatorExpression.Right.AcceptVisitor(this, data);
return null;
}
-
+
///
/// Visits the statement's children.
///
@@ -343,13 +442,16 @@ namespace ICSharpCode.PythonBinding
{
return blockStatement.AcceptChildren(this, data);
}
-
+
public override object TrackedVisitBreakStatement(BreakStatement breakStatement, object data)
{
- AppendIndentedLine("break");
+ if (suppressBreak)
+ AppendIndentedLine("pass #break"); // use pass as noop
+ else
+ AppendIndentedLine("break");
return null;
}
-
+
public override object TrackedVisitCaseLabel(CaseLabel caseLabel, object data)
{
return null;
@@ -362,38 +464,38 @@ namespace ICSharpCode.PythonBinding
{
return castExpression.Expression.AcceptVisitor(this, data);
}
-
+
public override object TrackedVisitCatchClause(CatchClause catchClause, object data)
{
Console.WriteLine("VisitCatchClause");
return null;
}
-
+
public override object TrackedVisitCheckedExpression(CheckedExpression checkedExpression, object data)
{
Console.WriteLine("VisitCheckedExpression");
return null;
}
-
+
public override object TrackedVisitCheckedStatement(CheckedStatement checkedStatement, object data)
{
Console.WriteLine("VisitCheckedStatement");
return null;
}
-
+
public override object TrackedVisitClassReferenceExpression(ClassReferenceExpression classReferenceExpression, object data)
{
Console.WriteLine("VisitClassReferenceExpression");
return null;
}
-
+
public override object TrackedVisitCompilationUnit(CompilationUnit compilationUnit, object data)
{
// Visit the child items of the compilation unit.
compilationUnit.AcceptChildren(this, data);
return null;
}
-
+
///
/// An ternary operator expression:
///
@@ -407,53 +509,53 @@ namespace ICSharpCode.PythonBinding
{
// Add true part.
conditionalExpression.TrueExpression.AcceptVisitor(this, data);
-
+
// Add condition.
Append(" if ");
conditionalExpression.Condition.AcceptVisitor(this, data);
-
+
// Add false part.
Append(" else ");
conditionalExpression.FalseExpression.AcceptVisitor(this, data);
return null;
}
-
+
public override object TrackedVisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
{
CreateConstructor(constructorInfo);
return null;
}
-
+
public override object TrackedVisitConstructorInitializer(ConstructorInitializer constructorInitializer, object data)
{
Console.WriteLine("VisitConstructorInitializer");
return null;
}
-
+
public override object TrackedVisitContinueStatement(ContinueStatement continueStatement, object data)
{
AppendIndentedLine("continue");
return null;
}
-
+
public override object TrackedVisitDeclareDeclaration(DeclareDeclaration declareDeclaration, object data)
{
Console.WriteLine("VisitDeclareDeclaration");
return null;
}
-
+
public override object TrackedVisitDefaultValueExpression(DefaultValueExpression defaultValueExpression, object data)
{
Console.WriteLine("VisitDefaultValueExpression");
return null;
}
-
+
public override object TrackedVisitDelegateDeclaration(DelegateDeclaration delegateDeclaration, object data)
{
Console.WriteLine("VisitDelegateDeclaration");
return null;
}
-
+
public override object TrackedVisitDestructorDeclaration(DestructorDeclaration destructorDeclaration, object data)
{
AppendIndentedLine("def __del__(self):");
@@ -462,24 +564,27 @@ namespace ICSharpCode.PythonBinding
DecreaseIndent();
return null;
}
-
+
public override object TrackedVisitDirectionExpression(DirectionExpression directionExpression, object data)
{
- Console.WriteLine("VisitDirectionExpression");
+ directionExpression.Expression.AcceptVisitor(this, data);
return null;
}
-
+
public override object TrackedVisitDoLoopStatement(DoLoopStatement doLoopStatement, object data)
{
AppendIndented("while ");
- doLoopStatement.Condition.AcceptVisitor(this, data);
+ if (doLoopStatement.Condition.IsNull)
+ Append("True");
+ else
+ doLoopStatement.Condition.AcceptVisitor(this, data);
Append(":");
AppendLine();
-
+
IncreaseIndent();
doLoopStatement.EmbeddedStatement.AcceptVisitor(this, data);
DecreaseIndent();
-
+
return null;
}
@@ -490,69 +595,69 @@ namespace ICSharpCode.PythonBinding
elseIfSection.Condition.AcceptVisitor(this, data);
Append(":");
AppendLine();
-
+
// Convert else if body statements.
IncreaseIndent();
elseIfSection.EmbeddedStatement.AcceptVisitor(this, data);
DecreaseIndent();
-
+
return null;
}
-
+
public override object TrackedVisitEmptyStatement(EmptyStatement emptyStatement, object data)
{
Console.WriteLine("VisitEmptyStatement");
return null;
}
-
+
public override object TrackedVisitEndStatement(EndStatement endStatement, object data)
{
Console.WriteLine("VistEndStatement");
return null;
}
-
+
public override object TrackedVisitEraseStatement(EraseStatement eraseStatement, object data)
{
Console.WriteLine("VisitEraseStatement");
return null;
}
-
+
public override object TrackedVisitErrorStatement(ErrorStatement errorStatement, object data)
{
Console.WriteLine("VisitErrorStatement");
return null;
}
-
+
public override object TrackedVisitEventAddRegion(EventAddRegion eventAddRegion, object data)
{
Console.WriteLine("VisitEventAddRegion");
return null;
}
-
+
public override object TrackedVisitEventDeclaration(EventDeclaration eventDeclaration, object data)
{
Console.WriteLine("VisitEventDeclaration");
return null;
}
-
+
public override object TrackedVisitEventRaiseRegion(EventRaiseRegion eventRaiseRegion, object data)
{
Console.WriteLine("VisitEventRaiseRegion");
return null;
}
-
+
public override object TrackedVisitEventRemoveRegion(EventRemoveRegion eventRemoveRegion, object data)
{
Console.WriteLine("VisitEventRemoveRegion");
return null;
}
-
+
public override object TrackedVisitExitStatement(ExitStatement exitStatement, object data)
{
AppendIndentedLine("break");
return null;
}
-
+
public override object TrackedVisitExpressionStatement(ExpressionStatement expressionStatement, object data)
{
// Convert the expression.
@@ -561,40 +666,44 @@ namespace ICSharpCode.PythonBinding
AppendLine();
return null;
}
-
+
public override object TrackedVisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data)
{
return null;
}
-
+
public override object TrackedVisitFixedStatement(FixedStatement fixedStatement, object data)
{
Console.WriteLine("VisitFixedStatement");
return null;
}
-
+
+ ///
+ /// Convert `foreach (var x in items)` to `for x in items:`
+ ///
+ ///
+ ///
+ ///
public override object TrackedVisitForeachStatement(ForeachStatement foreachStatement, object data)
{
- // Convert the for loop's initializers.
+ // while statement does not work with lambda expressions
+ // and is more pythonic
AppendIndented(String.Empty);
- CreateInitStatement(foreachStatement);
+ Append("for ");
+ Append(foreachStatement.VariableName);
+ Append(" in ");
+ AppendForeachVariableName(foreachStatement);
+ Append(":");
AppendLine();
-
- // Convert the for loop's test expression.
- AppendIndentedLine("while enumerator.MoveNext():");
-
- // Move the initializer in the foreach loop to the
- // first line of the for loop's body.
IncreaseIndent();
- AppendIndentedLine(foreachStatement.VariableName + " = enumerator.Current");
-
+
// Visit the for loop's body.
foreachStatement.EmbeddedStatement.AcceptVisitor(this, data);
DecreaseIndent();
return null;
}
-
+
///
/// Converts from an NRefactory VB.NET for next loop:
///
@@ -614,7 +723,7 @@ namespace ICSharpCode.PythonBinding
Append(" = ");
forNextStatement.Start.AcceptVisitor(this, data);
AppendLine();
-
+
// Convert the for loop's test expression.
AppendIndented("while ");
Append(variableName);
@@ -622,11 +731,11 @@ namespace ICSharpCode.PythonBinding
forNextStatement.End.AcceptVisitor(this, data);
Append(":");
AppendLine();
-
+
// Visit the for loop's body.
IncreaseIndent();
forNextStatement.EmbeddedStatement.AcceptVisitor(this, data);
-
+
// Convert the for loop's increment statement.
AppendIndented(variableName);
Append(" = ");
@@ -639,63 +748,271 @@ namespace ICSharpCode.PythonBinding
}
AppendLine();
DecreaseIndent();
-
+
return null;
}
-
+
///
/// Converts from an NRefactory for loop:
///
/// for (int i = 0; i < 5; i = i + 1)
///
/// to Python's:
- ///
- /// i = 0
- /// while i < 5:
+ /// for i in xrange(0,5,1):
+ /// or
+ /// i = 0
+ /// while i < 5:
///
public override object TrackedVisitForStatement(ForStatement forStatement, object data)
{
- // Convert the for loop's initializers.
- foreach (Statement statement in forStatement.Initializers) {
- statement.AcceptVisitor(this, data);
+ // Check if forStatement can be represented as simple range
+ if (!TryWriteSimpleForStatement(forStatement, data)) {
+ // Convert the for loop's initializers.
+ foreach (Statement statement in forStatement.Initializers) {
+ statement.AcceptVisitor(this, data);
+ }
+
+ // Convert the for loop's test expression.
+ AppendIndented("while ");
+ if (forStatement.Condition.IsNull)
+ Append("True");
+ else
+ forStatement.Condition.AcceptVisitor(this, data);
+ Append(":");
+ AppendLine();
+
+ // Visit the for loop's body.
+ IncreaseIndent();
+ forStatement.EmbeddedStatement.AcceptVisitor(this, data);
+
+ // Convert the for loop's increment statement.
+ foreach (Statement statement in forStatement.Iterator) {
+ statement.AcceptVisitor(this, data);
+ }
+ DecreaseIndent();
+ }
+ return null;
+ }
+
+ ///
+ /// Handle the fairly common integer increment loop
+ ///
+ /// The complexity of this method is to guarantee that
+ /// it is only used on integer based variables and that we know that
+ /// its one of the common loop conditions
+ /// Statement to handle
+ /// Additional value for visitor
+ /// Returns true if the simple for statement was written
+ private bool TryWriteSimpleForStatement(ForStatement forStatement, object data)
+ {
+ if (forStatement.Initializers.Count != 1
+ || forStatement.Iterator.Count != 1
+ || forStatement.Condition.IsNull
+ ) {
+ return false;
}
+ string variableName = null;
+ Expression variableExpression = null;
+ Expression startExpression = null;
+ Expression endExpression = null;
+ object stepExpression = null;
+ bool negateStepExpression = false;
- // Convert the for loop's test expression.
- AppendIndented("while ");
- forStatement.Condition.AcceptVisitor(this, data);
- Append(":");
+ // Locate the initializer variable and determine if xrange applies
+ var localVariableDecl = forStatement.Initializers[0] as LocalVariableDeclaration;
+ var initializerStatement = forStatement.Initializers[0] as ExpressionStatement;
+ if (localVariableDecl != null && localVariableDecl.Variables.Count == 1) {
+ // validate the data type is an integer
+ var variableDecl = localVariableDecl.Variables[0] as VariableDeclaration;
+ if (!IsIntegerValue(localVariableDecl.TypeReference))
+ return false;
+ variableName = variableDecl.Name;
+ startExpression = variableDecl.Initializer;
+ } else if (initializerStatement != null) {
+ var initializerExpression = initializerStatement.Expression as AssignmentExpression;
+ if (initializerExpression == null || initializerExpression.Op != AssignmentOperatorType.Assign)
+ return false;
+ var initializerVariable = initializerExpression.Left as IdentifierExpression;
+ if (initializerVariable == null)
+ return false;
+ variableName = initializerVariable.Identifier;
+ variableExpression = initializerVariable;
+ if (initializerExpression.Right is PrimitiveExpression) {
+ var primativeExpr = initializerExpression.Right as PrimitiveExpression;
+ if (!IsIntegerValue(primativeExpr.Value.GetType())) return false;
+ }
+ startExpression = initializerExpression.Right;
+ } else {
+ return false;
+ }
+ // get the step size from the iterator statement and determine increment direction
+ var iteratorStatement = forStatement.Iterator[0] as ExpressionStatement;
+ if (iteratorStatement == null)
+ return false;
+ var iteratorExpression = iteratorStatement.Expression as UnaryOperatorExpression;
+ if (iteratorExpression != null) {
+ switch (iteratorExpression.Op) {
+ case UnaryOperatorType.Increment:
+ case UnaryOperatorType.PostIncrement:
+ stepExpression = "1";
+ break;
+ case UnaryOperatorType.Decrement:
+ case UnaryOperatorType.PostDecrement:
+ stepExpression = "1";
+ negateStepExpression = true;
+ break;
+ default:
+ return false;
+ }
+ var iteratorVariable = iteratorExpression.Expression as IdentifierExpression;
+ if (iteratorVariable == null || iteratorVariable.Identifier != variableName)
+ return false;
+ } else {
+ var stepAssignmentExpression = iteratorStatement.Expression as AssignmentExpression;
+ if (stepAssignmentExpression == null ||
+ (stepAssignmentExpression.Op != AssignmentOperatorType.Add &&
+ stepAssignmentExpression.Op != AssignmentOperatorType.Subtract &&
+ stepAssignmentExpression.Op != AssignmentOperatorType.Assign))
+ return false;
+ negateStepExpression = stepAssignmentExpression.Op == AssignmentOperatorType.Subtract;
+
+ var iteratorVariable = stepAssignmentExpression.Left as IdentifierExpression;
+ if (iteratorVariable == null || iteratorVariable.Identifier != variableName)
+ return false;
+ if (stepAssignmentExpression.Right is PrimitiveExpression
+ || stepAssignmentExpression.Right is IdentifierExpression
+ || stepAssignmentExpression.Right is MemberReferenceExpression
+ ) {
+ // handles += and -=
+ stepExpression = stepAssignmentExpression.Right;
+ } else if (stepAssignmentExpression.Op == AssignmentOperatorType.Assign
+ && stepAssignmentExpression.Right is BinaryOperatorExpression
+ ) {
+ // Handle i = i +/- step
+ var stepRightSubCondition = stepAssignmentExpression.Right as BinaryOperatorExpression;
+ if ((stepRightSubCondition.Op != BinaryOperatorType.Add &&
+ stepRightSubCondition.Op != BinaryOperatorType.Subtract)
+ ) {
+ return false;
+ }
+ var stepLastVariable = stepRightSubCondition.Left as IdentifierExpression;
+ if (stepLastVariable == null || stepLastVariable.Identifier != variableName) {
+ return false;
+ }
+ negateStepExpression = (stepRightSubCondition.Op == BinaryOperatorType.Subtract);
+ if (!(stepRightSubCondition.Right is PrimitiveExpression
+ || stepRightSubCondition.Right is IdentifierExpression
+ || stepRightSubCondition.Right is MemberReferenceExpression
+ )) {
+ return false;
+ }
+ stepExpression = stepRightSubCondition.Right;
+
+ } else {
+ return false;
+ }
+ }
+
+ // determine the max value from the condition test
+ var condition = forStatement.Condition as BinaryOperatorExpression;
+ if (condition == null)
+ return false;
+
+ // verify simple inequality and step direct is correct
+ if (!((condition.Op == BinaryOperatorType.GreaterThan && negateStepExpression)
+ || (condition.Op == BinaryOperatorType.LessThan && !negateStepExpression)))
+ return false;
+
+ var compareVariable = condition.Left as IdentifierExpression;
+ if (compareVariable == null || compareVariable.Identifier != variableName)
+ return false;
+ endExpression = condition.Right;
+
+ // Write out the for loop
+ AppendIndented("for ");
+ if (variableExpression != null)
+ variableExpression.AcceptVisitor(this, null);
+ else
+ Append(variableName);
+ Append(" in xrange(");
+ startExpression.AcceptVisitor(this, null);
+ Append(",");
+ endExpression.AcceptVisitor(this, null);
+ Append(",");
+ if (negateStepExpression) Append("-");
+ if (stepExpression is string) {
+ Append(stepExpression.ToString());
+ } else {
+ ((Expression)stepExpression).AcceptVisitor(this, null);
+ }
+ Append("):");
AppendLine();
-
+
// Visit the for loop's body.
IncreaseIndent();
forStatement.EmbeddedStatement.AcceptVisitor(this, data);
-
- // Convert the for loop's increment statement.
- foreach (Statement statement in forStatement.Iterator) {
- statement.AcceptVisitor(this, data);
- }
DecreaseIndent();
-
- return null;
+ return true;
+ }
+
+ ///
+ /// Test if the TypeReference is an integer type
+ ///
+ /// TypeReference to test
+ /// True if the type is an integer type
+ private static bool IsIntegerValue(TypeReference typeReference)
+ {
+ if (typeReference.IsArrayType)
+ return false;
+ if (!typeReference.Type.StartsWith("System."))
+ return false;
+ return IsIntegerValue(Type.GetType(typeReference.Type, false, true));
+ }
+
+ ///
+ /// Test if the Type is an integer type
+ ///
+ /// Type to test
+ /// True if the type is an integer type
+ private static bool IsIntegerValue(Type type)
+ {
+ if (type == null || !type.IsValueType || !type.IsPrimitive || type.IsArray || type.IsGenericType)
+ return false;
+ TypeCode code = Type.GetTypeCode(type);
+ switch (code) {
+ case TypeCode.Byte:
+ case TypeCode.Char:
+ case TypeCode.Int16:
+ case TypeCode.Int32:
+ case TypeCode.Int64:
+ case TypeCode.SByte:
+ case TypeCode.UInt16:
+ case TypeCode.UInt32:
+ case TypeCode.UInt64:
+ break;
+ default:
+ return false;
+ }
+ return true;
}
-
+
public override object TrackedVisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement, object data)
{
Console.WriteLine("VisitGotoCaseStatement");
return null;
}
-
+
public override object TrackedVisitGotoStatement(GotoStatement gotoStatement, object data)
{
Console.WriteLine("VisitGotoStatement");
return null;
}
-
+
public override object TrackedVisitIdentifierExpression(IdentifierExpression identifierExpression, object data)
{
string name = identifierExpression.Identifier;
if (IsField(name)) {
- Append("self._" + name);
+ AppendFieldReferenceName(name);
} else if (IsProperty(name) && !IsMethodParameter(name)) {
Append("self." + name);
} else {
@@ -703,7 +1020,7 @@ namespace ICSharpCode.PythonBinding
}
return null;
}
-
+
public override object TrackedVisitIfElseStatement(IfElseStatement ifElseStatement, object data)
{
// Convert condition.
@@ -711,7 +1028,7 @@ namespace ICSharpCode.PythonBinding
ifElseStatement.Condition.AcceptVisitor(this, data);
Append(":");
AppendLine();
-
+
// Convert true statements.
IncreaseIndent();
foreach (Statement statement in ifElseStatement.TrueStatement) {
@@ -725,7 +1042,7 @@ namespace ICSharpCode.PythonBinding
elseIfSection.AcceptVisitor(this, data);
}
}
-
+
// Convert false statements.
if (ifElseStatement.HasElseStatements) {
AppendIndentedLine("else:");
@@ -738,7 +1055,7 @@ namespace ICSharpCode.PythonBinding
return null;
}
-
+
public override object TrackedVisitIndexerExpression(IndexerExpression indexerExpression, object data)
{
indexerExpression.TargetObject.AcceptVisitor(this, data);
@@ -752,26 +1069,77 @@ namespace ICSharpCode.PythonBinding
return null;
}
-
+
public override object TrackedVisitInnerClassTypeReference(InnerClassTypeReference innerClassTypeReference, object data)
{
Console.WriteLine("VisitInnerClassTypeReference");
return null;
}
-
+
public override object TrackedVisitInterfaceImplementation(InterfaceImplementation interfaceImplementation, object data)
{
Console.WriteLine("VisitInterfaceImplementation");
return null;
}
+ private object CreateInvocationAssignment(AssignmentExpression assignmentExpression, object data)
+ {
+ assignmentExpression.Left.AcceptVisitor(this, data);
+ var invocationExpression = assignmentExpression.Right as InvocationExpression;
+ if (invocationExpression == null) {
+ Append(" = ");
+ assignmentExpression.Right.AcceptVisitor(this, data);
+ return null;
+ }
+
+ CreateInvocationAssignmentParameters(invocationExpression, data, false);
+ invocationExpression.AcceptVisitor(this, data);
+ return null;
+ }
+
+ private void CreateInvocationAssignmentParameters(InvocationExpression invocationExpression, object data, bool firstArg)
+ {
+ // out and ref values are passed via return tuple
+ // should verify that the objects are not clr.Reference
+ foreach (var param in invocationExpression.Arguments) {
+ var directionExpression = param as DirectionExpression;
+ if (directionExpression == null) continue;
+ if (directionExpression.FieldDirection == FieldDirection.Ref ||
+ directionExpression.FieldDirection == FieldDirection.Out) {
+ if (!firstArg) Append(", ");
+ directionExpression.AcceptVisitor(this, data);
+ firstArg = false;
+ }
+ }
+ Append(" = ");
+ }
+
+ private bool HasReferences(IEnumerable parameters)
+ {
+ foreach (var param in parameters) {
+ var expression = param as DirectionExpression;
+ if (expression == null) continue;
+ if (expression.FieldDirection == FieldDirection.Out || expression.FieldDirection == FieldDirection.Ref)
+ return true;
+ }
+ return false;
+ }
+
public override object TrackedVisitInvocationExpression(InvocationExpression invocationExpression, object data)
{
+ // Special case for searching if single line statement with
+ if (HasReferences(invocationExpression.Arguments)) {
+ var expression = invocationExpression.Parent as ExpressionStatement;
+ if (expression != null && expression.Parent is BlockStatement) {
+ CreateInvocationAssignmentParameters(invocationExpression, data, true);
+ }
+ }
+
MemberReferenceExpression memberRefExpression = invocationExpression.TargetObject as MemberReferenceExpression;
IdentifierExpression identifierExpression = invocationExpression.TargetObject as IdentifierExpression;
if (memberRefExpression != null) {
memberRefExpression.TargetObject.AcceptVisitor(this, data);
- Append("." + memberRefExpression.MemberName);
+ Append("." + memberRefExpression.MemberName);
} else if (identifierExpression != null) {
if ((currentMethod != null) && IsStatic(currentMethod)) {
Append(GetTypeName(currentMethod) + ".");
@@ -780,11 +1148,15 @@ namespace ICSharpCode.PythonBinding
}
Append(identifierExpression.Identifier);
}
-
+
// Create method parameters
Append("(");
bool firstParam = true;
foreach (Expression param in invocationExpression.Arguments) {
+ if (param is DirectionExpression) {
+ if (((DirectionExpression)param).FieldDirection == FieldDirection.Out)
+ continue;
+ }
if (firstParam) {
firstParam = false;
} else {
@@ -795,13 +1167,13 @@ namespace ICSharpCode.PythonBinding
Append(")");
return null;
}
-
+
public override object TrackedVisitLabelStatement(LabelStatement labelStatement, object data)
{
Console.WriteLine("VisitLabelStatement");
return null;
}
-
+
///
/// The variable declaration is not created if the variable has no initializer.
///
@@ -809,12 +1181,12 @@ namespace ICSharpCode.PythonBinding
{
foreach (VariableDeclaration variableDeclaration in localVariableDeclaration.Variables) {
if (!variableDeclaration.Initializer.IsNull) {
-
+
AddTypeToArrayInitializerIfMissing(variableDeclaration);
-
+
// Create variable declaration.
AppendIndented(variableDeclaration.Name + " = ");
-
+
// Generate the variable initializer.
variableDeclaration.Initializer.AcceptVisitor(this, data);
AppendLine();
@@ -822,13 +1194,32 @@ namespace ICSharpCode.PythonBinding
}
return null;
}
-
+
public override object TrackedVisitLockStatement(LockStatement lockStatement, object data)
{
- Console.WriteLine("VisitLockStatement");
+ AppendIndented(GetTypeName("System.Threading.Monitor"));
+ Append(".Enter(");
+ lockStatement.LockExpression.AcceptVisitor(this, data);
+ Append(")");
+ AppendLine();
+
+ AppendIndentedLine("try:");
+ IncreaseIndent();
+ lockStatement.EmbeddedStatement.AcceptVisitor(this, data);
+ DecreaseIndent();
+
+ // Convert finally block.
+ AppendIndentedLine("finally:");
+ IncreaseIndent();
+ AppendIndented(GetTypeName("System.Threading.Monitor"));
+ Append(".Exit(");
+ lockStatement.LockExpression.AcceptVisitor(this, data);
+ Append(")");
+ AppendLine();
+ DecreaseIndent();
return null;
}
-
+
public override object TrackedVisitMemberInitializerExpression(MemberInitializerExpression memberInitializerExpression, object data)
{
Append(memberInitializerExpression.Name);
@@ -836,7 +1227,7 @@ namespace ICSharpCode.PythonBinding
memberInitializerExpression.Expression.AcceptVisitor(this, data);
return null;
}
-
+
///
/// Adds a CodeMemberMethod to the current class being visited.
///
@@ -844,14 +1235,19 @@ namespace ICSharpCode.PythonBinding
{
// Add method name.
currentMethod = methodDeclaration;
+
+ var oldMethodHasOutputParameters = methodHasOutputParameters;
+ methodHasOutputParameters = false;
+
string methodName = methodDeclaration.Name;
AppendIndented("def " + methodName);
-
+
// Add the parameters.
AddParameters(methodDeclaration);
+ var oldMethodParameters = methodParameters;
methodParameters = methodDeclaration.Parameters;
AppendLine();
-
+
IncreaseIndent();
AppendDocstring(xmlDocComments);
if (methodDeclaration.Body.Children.Count > 0) {
@@ -859,23 +1255,25 @@ namespace ICSharpCode.PythonBinding
} else {
AppendIndentedPassStatement();
}
-
+
DecreaseIndent();
AppendLine();
-
+
if (IsStatic(methodDeclaration)) {
AppendIndentedLine(methodDeclaration.Name + " = staticmethod(" + methodDeclaration.Name + ")");
AppendLine();
-
+
// Save Main entry point method.
SaveMethodIfMainEntryPoint(methodDeclaration);
}
-
+
+ methodParameters = oldMethodParameters;
+ methodHasOutputParameters = oldMethodHasOutputParameters;
currentMethod = null;
-
+
return null;
}
-
+
public override object TrackedVisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression, object data)
{
Append(namedArgumentExpression.Name);
@@ -883,7 +1281,7 @@ namespace ICSharpCode.PythonBinding
namedArgumentExpression.Expression.AcceptVisitor(this, data);
return null;
}
-
+
///
/// Visits the namespace declaration and all child nodes.
///
@@ -891,14 +1289,14 @@ namespace ICSharpCode.PythonBinding
{
return namespaceDeclaration.AcceptChildren(this, data);
}
-
+
///
/// Converts an NRefactory's ObjectCreateExpression to a code dom's
/// CodeObjectCreateExpression.
///
public override object TrackedVisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data)
{
- Append(objectCreateExpression.CreateType.Type);
+ Append(GetTypeName(objectCreateExpression.CreateType));
if (IsGenericType(objectCreateExpression)) {
AppendGenericTypes(objectCreateExpression);
}
@@ -913,7 +1311,7 @@ namespace ICSharpCode.PythonBinding
expression.AcceptVisitor(this, data);
firstParameter = false;
}
-
+
// Add object initializers.
bool firstInitializer = true;
foreach (Expression expression in objectCreateExpression.ObjectInitializer.CreateExpressions) {
@@ -923,166 +1321,214 @@ namespace ICSharpCode.PythonBinding
expression.AcceptVisitor(this, data);
firstInitializer = false;
}
-
+
Append(")");
return null;
}
-
+
public override object TrackedVisitOnErrorStatement(OnErrorStatement onErrorStatement, object data)
{
return null;
}
-
+
public override object TrackedVisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data)
{
Console.WriteLine("VisitOperatorDeclaration");
return null;
}
-
+
public override object TrackedVisitOptionDeclaration(OptionDeclaration optionDeclaration, object data)
{
Console.WriteLine("VisitOptionDeclaration");
return null;
}
-
+
public override object TrackedVisitExternAliasDirective(ExternAliasDirective externAliasDirective, object data)
{
Console.WriteLine("ExternAliasDirective");
return null;
}
-
+
public override object TrackedVisitParameterDeclarationExpression(ParameterDeclarationExpression parameterDeclarationExpression, object data)
{
Console.WriteLine("VisitParameterDeclarationExpression");
return null;
}
-
+
public override object TrackedVisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data)
{
- Append("(" );
+ Append("(");
parenthesizedExpression.Expression.AcceptVisitor(this, data);
Append(")");
return null;
}
-
+
public override object TrackedVisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, object data)
{
Console.WriteLine("VisitPointerReferenceExpression");
return null;
}
-
+
public override object TrackedVisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data)
{
if (primitiveExpression.Value == null) {
Append("None");
} else if (primitiveExpression.Value is Boolean) {
Append(primitiveExpression.Value.ToString());
+ } else if (primitiveExpression.Value is Single
+ || primitiveExpression.Value is UInt16
+ || primitiveExpression.Value is UInt32
+ || primitiveExpression.Value is Byte
+ ) // special handling for primatives that do not directly map to Python
+ {
+ var t = primitiveExpression.Value.GetType();
+ Append(string.Format("{0}({1})", t.Name, primitiveExpression.Value));
} else {
Append(primitiveExpression.StringValue);
}
return null;
}
-
+
public override object TrackedVisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data)
{
string propertyName = propertyDeclaration.Name;
propertyNames.Add(propertyName);
+ bool isAnonymous = (propertyDeclaration.HasGetRegion && propertyDeclaration.GetRegion.Block.IsNull
+ && propertyDeclaration.HasSetRegion && propertyDeclaration.SetRegion.Block.IsNull);
+
// Add get statements.
if (propertyDeclaration.HasGetRegion) {
AppendIndentedLine("def get_" + propertyName + "(self):");
IncreaseIndent();
- propertyDeclaration.GetRegion.Block.AcceptVisitor(this, data);
+ if (isAnonymous) {
+ AppendIndentedLine("return self._" + propertyDeclaration.Name.ToLower()); // maybe do some type casting?
+ } else if (propertyDeclaration.GetRegion.Block.IsNull) {
+ AppendIndentedLine("pass");
+ } else {
+ propertyDeclaration.GetRegion.Block.AcceptVisitor(this, data);
+ }
DecreaseIndent();
AppendLine();
}
-
+
// Add set statements.
if (propertyDeclaration.HasSetRegion) {
AppendIndentedLine("def set_" + propertyName + "(self, value):");
IncreaseIndent();
- propertyDeclaration.SetRegion.Block.AcceptVisitor(this, data);
+ if (isAnonymous) {
+ AppendIndentedLine("self._" + propertyDeclaration.Name.ToLower() + " = value"); // maybe do some type casting?
+ } else if (propertyDeclaration.GetRegion.Block.IsNull) {
+ AppendIndentedLine("pass");
+ } else {
+ propertyDeclaration.SetRegion.Block.AcceptVisitor(this, data);
+ }
DecreaseIndent();
AppendLine();
}
-
+
AppendPropertyDecorator(propertyDeclaration);
AppendLine();
-
+
return null;
}
-
+
public override object TrackedVisitPropertyGetRegion(PropertyGetRegion propertyGetRegion, object data)
{
Console.WriteLine("VisitPropertyGetRegion");
return null;
}
-
+
public override object TrackedVisitPropertySetRegion(PropertySetRegion propertySetRegion, object data)
{
Console.WriteLine("VisitPropertySetRegion");
return null;
}
-
+
public override object TrackedVisitRaiseEventStatement(RaiseEventStatement raiseEventStatement, object data)
{
Console.WriteLine("VisitRaiseEventStatement");
return null;
}
-
+
public override object TrackedVisitReDimStatement(ReDimStatement reDimStatement, object data)
{
Console.WriteLine("VisitReDimStatement");
return null;
}
-
+
public override object TrackedVisitRemoveHandlerStatement(RemoveHandlerStatement removeHandlerStatement, object data)
{
Console.WriteLine("VisitRemoveHandlerStatement");
return null;
}
-
+
public override object TrackedVisitResumeStatement(ResumeStatement resumeStatement, object data)
{
Console.WriteLine("VisitResumeStatement");
return null;
}
-
+
///
/// Converts a NRefactory ReturnStatement to a code dom's
/// CodeMethodReturnStatement.
///
public override object TrackedVisitReturnStatement(ReturnStatement returnStatement, object data)
{
- AppendIndented("return ");
- returnStatement.Expression.AcceptVisitor(this, data);
- AppendLine();
+ // yield statements will generate the correct line start and end
+ if (suppressReturn) {
+ returnStatement.Expression.AcceptVisitor(this, data);
+ } else {
+ AppendIndented("return ");
+
+ // python returns out and ref generally as a return tuple
+ if (methodHasOutputParameters)
+ Append("(");
+
+ returnStatement.Expression.AcceptVisitor(this, data);
+
+ if (methodHasOutputParameters) {
+ if (currentMethod != null) {
+ foreach (var param in currentMethod.Parameters) {
+ if (param.ParamModifier == ParameterModifiers.Out
+ || param.ParamModifier == ParameterModifiers.Ref) {
+ Append(", ");
+ Append(param.ParameterName);
+ }
+ }
+ }
+ Append(")");
+ }
+ AppendLine();
+ }
return null;
}
-
+
public override object TrackedVisitSizeOfExpression(SizeOfExpression sizeOfExpression, object data)
{
Console.WriteLine("VisitSizeOfExpression");
return null;
}
-
+
public override object TrackedVisitStackAllocExpression(StackAllocExpression stackAllocExpression, object data)
{
return null;
}
-
+
public override object TrackedVisitStopStatement(StopStatement stopStatement, object data)
{
return null;
}
-
+
public override object TrackedVisitSwitchSection(SwitchSection switchSection, object data)
{
return null;
}
-
+
public override object TrackedVisitSwitchStatement(SwitchStatement switchStatement, object data)
{
+ var oldSuppressBreak = suppressBreak;
+ this.suppressBreak = true;
bool firstSection = true;
foreach (SwitchSection section in switchStatement.SwitchSections) {
// Create if/elif/else condition.
@@ -1092,17 +1538,19 @@ namespace ICSharpCode.PythonBinding
IncreaseIndent();
CreateSwitchCaseBody(section);
DecreaseIndent();
-
+
firstSection = false;
}
+
+ suppressBreak = oldSuppressBreak;
return null;
}
-
+
public override object TrackedVisitTemplateDefinition(TemplateDefinition templateDefinition, object data)
{
return null;
}
-
+
public override object TrackedVisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, object data)
{
Append("self");
@@ -1119,7 +1567,7 @@ namespace ICSharpCode.PythonBinding
AppendLine();
return null;
}
-
+
///
/// Converts an NRefactory try-catch statement to a code dom
/// try-catch statement.
@@ -1131,29 +1579,29 @@ namespace ICSharpCode.PythonBinding
IncreaseIndent();
tryCatchStatement.StatementBlock.AcceptVisitor(this, data);
DecreaseIndent();
-
+
// Convert catches.
foreach (CatchClause catchClause in tryCatchStatement.CatchClauses) {
AppendIndented("except ");
- Append(catchClause.TypeReference.Type);
+ Append(GetTypeName(catchClause.TypeReference));
Append(", " + catchClause.VariableName + ":");
AppendLine();
-
+
// Convert catch child statements.
IncreaseIndent();
catchClause.StatementBlock.AcceptVisitor(this, data);
DecreaseIndent();
}
-
+
// Convert finally block.
AppendIndentedLine("finally:");
IncreaseIndent();
tryCatchStatement.FinallyBlock.AcceptVisitor(this, data);
DecreaseIndent();
-
+
return null;
}
-
+
///
/// Visits a class.
///
@@ -1165,63 +1613,80 @@ namespace ICSharpCode.PythonBinding
AppendLine();
IncreaseIndent();
AppendDocstring(xmlDocComments);
- if (typeDeclaration.Children.Count > 0) {
- // Look for fields or a constructor for the type.
- constructorInfo = PythonConstructorInfo.GetConstructorInfo(typeDeclaration);
- if (constructorInfo != null) {
- if (constructorInfo.Constructor != null) {
- // Generate constructor later when VisitConstructorDeclaration method is called.
- // This allows the constructor comments to be converted in the right place.
- } else {
- CreateConstructor(constructorInfo);
+
+ this.currentType = typeDeclaration;
+ if (typeDeclaration.Type == ClassType.Enum) {
+ CreateEnumeration(typeDeclaration);
+ } else {
+ if (typeDeclaration.Children.Count > 0) {
+ // Look for fields or a constructor for the type.
+ constructorInfo = PythonConstructorInfo.GetConstructorInfo(typeDeclaration);
+ if (constructorInfo != null) {
+ if (constructorInfo.Constructor != null) {
+ // Generate constructor later when VisitConstructorDeclaration method is called.
+ // This allows the constructor comments to be converted in the right place.
+ } else {
+ CreateConstructor(constructorInfo);
+ }
}
+
+ // Visit the rest of the class.
+ typeDeclaration.AcceptChildren(this, data);
+ } else {
+ AppendIndentedPassStatement();
}
-
- // Visit the rest of the class.
- typeDeclaration.AcceptChildren(this, data);
- } else {
- AppendIndentedPassStatement();
}
+ this.currentType = null;
DecreaseIndent();
return null;
}
-
+
public override object TrackedVisitTypeOfExpression(TypeOfExpression typeOfExpression, object data)
{
- codeBuilder.InsertIndentedLine("import clr\r\n");
+ // clr was added to list of standard imports
+ if (!clrImported) {
+ codeBuilder.InsertIndentedLine("import clr");
+ clrImported = true;
+ }
Append("clr.GetClrType(");
Append(GetTypeName(typeOfExpression.TypeReference));
Append(")");
return null;
}
-
+
public override object TrackedVisitTypeOfIsExpression(TypeOfIsExpression typeOfIsExpression, object data)
{
- Console.WriteLine("VisitTypeOfIsExpression");
+ Append("isinstance(");
+ typeOfIsExpression.Expression.AcceptVisitor(this, data);
+ Append(",");
+ typeOfIsExpression.TypeReference.AcceptVisitor(this, data);
+ Append(")");
return null;
}
-
+
public override object TrackedVisitTypeReference(TypeReference typeReference, object data)
{
Console.WriteLine("VisitTypeReference");
return null;
}
-
+
public override object TrackedVisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, object data)
{
Append(GetTypeName(typeReferenceExpression.TypeReference));
return null;
}
-
+
public override object TrackedVisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data)
{
switch (unaryOperatorExpression.Op) {
+ // Change i++ or ++i to i += 1
case UnaryOperatorType.PostIncrement:
- case UnaryOperatorType.Increment:
- // Change i++ or ++i to i += 1
return CreateIncrementStatement(unaryOperatorExpression);
+ case UnaryOperatorType.Increment:
+ return CreateIncrementStatement(unaryOperatorExpression, prefix: true);
case UnaryOperatorType.Decrement:
+ return CreateDecrementStatement(unaryOperatorExpression, prefix: true);
case UnaryOperatorType.PostDecrement:
// Change --i or i-- to i -= 1.
return CreateDecrementStatement(unaryOperatorExpression);
@@ -1236,27 +1701,27 @@ namespace ICSharpCode.PythonBinding
}
return null;
}
-
+
public override object TrackedVisitUncheckedExpression(UncheckedExpression uncheckedExpression, object data)
{
return null;
}
-
+
public override object TrackedVisitUncheckedStatement(UncheckedStatement uncheckedStatement, object data)
{
return null;
}
-
+
public override object TrackedVisitUnsafeStatement(UnsafeStatement unsafeStatement, object data)
{
return null;
}
-
+
public override object TrackedVisitUsing(Using @using, object data)
{
return null;
}
-
+
///
/// Converts using declarations into Python import statements.
///
@@ -1264,16 +1729,83 @@ namespace ICSharpCode.PythonBinding
{
// Add import statements for each using.
foreach (Using @using in usingDeclaration.Usings) {
- AppendIndentedLine("from " + @using.Name + " import *");
+ if (@using.IsAlias) {
+ typeNameMap[@using.Alias.Type] = @using.Name;
+ var match = Regex.Match(@using.Alias.Type, @"^(?.*)\.(?\w+)$", RegexOptions.Singleline);
+ if (match.Success)
+ AppendIndentedLine("from " + match.Groups["lib"] + " import "
+ + match.Groups["name"] + " as " + @using.Name);
+ else
+ AppendIndentedLine(@using.Name + " = " + @using.Alias.Type);
+ } else {
+ AppendIndentedLine("from " + @using.Name + " import *");
+ importLibraries.Insert(0, @using.Name + "."); // insert in reverse order
+ }
+
}
return null;
}
-
+
public override object TrackedVisitUsingStatement(UsingStatement usingStatement, object data)
{
+ // first check if using is either LocalVariable or Variable assignment and try to get the variable name
+ string variableName = null;
+ bool skipInitializer = false;
+ var localVariableDecl = usingStatement.ResourceAcquisition as LocalVariableDeclaration;
+ var initializerStatement = usingStatement.ResourceAcquisition as ExpressionStatement;
+ if (localVariableDecl != null && localVariableDecl.Variables.Count == 1) {
+ // validate the data type is an integer
+ var variableDecl = localVariableDecl.Variables[0];
+ variableName = variableDecl.Name;
+ } else if (initializerStatement != null) {
+ var initializerExpression = initializerStatement.Expression as AssignmentExpression;
+ if (initializerExpression != null && initializerExpression.Op == AssignmentOperatorType.Assign) {
+ var initializerVariable = initializerExpression.Left as IdentifierExpression;
+ if (initializerVariable != null)
+ variableName = initializerVariable.Identifier;
+ } else if (initializerStatement.Expression is ObjectCreateExpression) {
+ var createObjectStatement = initializerStatement.Expression as ObjectCreateExpression;
+ // create an anonymous variable placeholder
+ variableName = "anon" + createObjectStatement.StartLocation.Line.ToString();
+ AppendIndented(variableName);
+ Append(" = ");
+ createObjectStatement.AcceptVisitor(this, data);
+ AppendLine();
+ skipInitializer = true;
+ }
+ }
+
+ if (!skipInitializer)
+ usingStatement.ResourceAcquisition.AcceptVisitor(this, data);
+
+ AppendIndentedLine("try:");
+ IncreaseIndent();
+ if (IsEmptyStatement(usingStatement.EmbeddedStatement))
+ AppendIndentedLine("pass");
+ else
+ usingStatement.EmbeddedStatement.AcceptVisitor(this, data);
+ DecreaseIndent();
+
+ // Convert finally block.
+ AppendIndentedLine("finally:");
+ IncreaseIndent();
+ if (!string.IsNullOrEmpty(variableName)) {
+ AppendIndented(variableName);
+ Append(".Dispose()");
+ AppendLine();
+ } else {
+ AppendIndentedLine("pass");
+ }
+ DecreaseIndent();
return null;
}
-
+
+ private static bool IsEmptyStatement(Statement statement)
+ {
+ return statement.IsNull
+ || (statement is BlockStatement && statement.Children.Count == 0);
+ }
+
public override object TrackedVisitVariableDeclaration(VariableDeclaration variableDeclaration, object data)
{
AppendIndented(variableDeclaration.Name + " = ");
@@ -1281,24 +1813,91 @@ namespace ICSharpCode.PythonBinding
AppendLine();
return null;
}
-
+
public override object TrackedVisitWithStatement(WithStatement withStatement, object data)
{
return null;
}
-
+
public override object TrackedVisitYieldStatement(YieldStatement yieldStatement, object data)
{
+ if (yieldStatement.IsYieldBreak)
+ AppendIndentedLine("raise StopIteration");
+ else if (yieldStatement.IsYieldReturn) {
+ // suppress the return in child statement
+ var oldSuppressReturn = suppressReturn;
+ suppressReturn = true;
+ AppendIndented("yield ");
+ yieldStatement.Statement.AcceptVisitor(this, data);
+ suppressReturn = oldSuppressReturn;
+ AppendLine();
+ }
return null;
}
-
+
public override object TrackedVisitCollectionInitializerExpression(CollectionInitializerExpression collectionInitializerExpression, object data)
{
return null;
}
-
+
public override object TrackedVisitLambdaExpression(LambdaExpression lambdaExpression, object data)
{
+ if (!lambdaExpression.ExpressionBody.IsNull) // simple lambda otherwise anonymous method
+ {
+ Append("lambda ");
+ for (int i = 0; i < lambdaExpression.Parameters.Count; ++i) {
+ if (i > 0) {
+ Append(", ");
+ }
+ Append(lambdaExpression.Parameters[i].ParameterName);
+ }
+ Append(": ");
+
+ // merge parameters with parent method with lambda due to closures
+ var oldMethodParameters = methodParameters;
+ methodParameters = new List(lambdaExpression.Parameters);
+ methodParameters.AddRange(methodParameters);
+
+ lambdaExpression.ExpressionBody.AcceptVisitor(this, null);
+
+ methodParameters = oldMethodParameters;
+ } else if (!lambdaExpression.StatementBody.IsNull) {
+ // handle known special cases. Namely variable initialize
+ string methodName = "lambdaMethod_" + lambdaExpression.StartLocation.Line.ToString()
+ + "_" + lambdaExpression.StartLocation.Column.ToString();
+
+ // method name reference written during normal passes
+ // definition written in prefix pass
+ if (accumulatePostfixStatements && !(lambdaExpression.Parent is Statement)) {
+ Append(methodName);
+ } else {
+ // merge parameters with parent method with lambda due to closures
+ var oldMethodParameters = methodParameters;
+ methodParameters = new List(lambdaExpression.Parameters);
+ methodParameters.AddRange(methodParameters);
+
+ Append("def ");
+ Append(methodName);
+ Append("(");
+ // Add the parameters.
+ for (int i = 0; i < lambdaExpression.Parameters.Count; ++i) {
+ if (i > 0) {
+ Append(", ");
+ }
+ Append(lambdaExpression.Parameters[i].ParameterName);
+ }
+ Append("):");
+ AppendLine();
+
+ IncreaseIndent();
+ AppendDocstring(xmlDocComments);
+ lambdaExpression.StatementBody.AcceptVisitor(this, data);
+ DecreaseIndent();
+
+ methodParameters = oldMethodParameters;
+ }
+ }
+
return null;
}
@@ -1313,102 +1912,102 @@ namespace ICSharpCode.PythonBinding
Append(memberReferenceExpression.MemberName);
return null;
}
-
+
public override object TrackedVisitQueryExpression(QueryExpression queryExpression, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionFromClause(QueryExpressionFromClause queryExpressionFromClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionGroupClause(QueryExpressionGroupClause queryExpressionGroupClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionJoinClause(QueryExpressionJoinClause queryExpressionJoinClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionLetClause(QueryExpressionLetClause queryExpressionLetClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionOrderClause(QueryExpressionOrderClause queryExpressionOrderClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionOrdering(QueryExpressionOrdering queryExpressionOrdering, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionSelectClause(QueryExpressionSelectClause queryExpressionSelectClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionWhereClause(QueryExpressionWhereClause queryExpressionWhereClause, object data)
{
return null;
}
-
+
public override object TrackedVisitExpressionRangeVariable(ExpressionRangeVariable expressionRangeVariable, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionAggregateClause(QueryExpressionAggregateClause queryExpressionAggregateClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionDistinctClause(QueryExpressionDistinctClause queryExpressionDistinctClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionGroupJoinVBClause(QueryExpressionGroupJoinVBClause queryExpressionGroupJoinVBClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionGroupVBClause(QueryExpressionGroupVBClause queryExpressionGroupVBClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionJoinConditionVB(QueryExpressionJoinConditionVB queryExpressionJoinConditionVB, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionJoinVBClause(QueryExpressionJoinVBClause queryExpressionJoinVBClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionLetVBClause(QueryExpressionLetVBClause queryExpressionLetVBClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionPartitionVBClause(QueryExpressionPartitionVBClause queryExpressionPartitionVBClause, object data)
{
return null;
}
-
+
public override object TrackedVisitQueryExpressionSelectVBClause(QueryExpressionSelectVBClause queryExpressionSelectVBClause, object data)
{
return null;
}
-
+
///
/// Appends any comments that appear before this node.
///
@@ -1417,33 +2016,64 @@ namespace ICSharpCode.PythonBinding
xmlDocComments.Clear();
currentNode = node;
specialNodesInserter.AcceptNodeStart(node);
+
+ // Search the Method Statements for prefix/postfix/lambda expressions
+ // and move the prefix/lambda to line before current statement
+ // move the postfix statements to line after current statement
+ if (node is MethodDeclaration) {
+ accumulatePostfixStatements = true;
+ }
+ if (accumulatePostfixStatements && (node is Statement) && !(node is BlockStatement)) {
+ bool oldAccumulatePostfixStatements = accumulatePostfixStatements;
+ accumulatePostfixStatements = false;
+ node.AcceptVisitor(prefixExpressionExtractor, null);
+ if (prefixExpressionExtractor.Statements.Count > 0) {
+ CreatePostfixStatements(prefixExpressionExtractor.Statements);
+ prefixExpressionExtractor.Statements.Clear();
+ }
+ accumulatePostfixStatements = oldAccumulatePostfixStatements;
+ }
}
-
+
+ protected override void EndVisit(INode node)
+ {
+ if (node is MethodDeclaration) {
+ accumulatePostfixStatements = false;
+ if (this.postfixStatements.Count > 0)
+ this.postfixStatements.Clear();
+ } else if (node is Statement) {
+ if (this.postfixStatements.Count > 0) {
+ CreatePostfixStatements(this.postfixStatements);
+ this.postfixStatements.Clear();
+ }
+ }
+ }
+
#region IOutputFormatter
-
+
int IOutputFormatter.IndentationLevel {
get { return codeBuilder.Indent; }
set { ; }
}
-
+
string IOutputFormatter.Text {
get { return String.Empty; }
}
-
+
bool IOutputFormatter.IsInMemberBody {
get { return false; }
set { ; }
}
-
+
void IOutputFormatter.NewLine()
{
}
-
+
void IOutputFormatter.Indent()
{
-
+
}
-
+
void IOutputFormatter.PrintComment(Comment comment, bool forceWriteInPreviousBlock)
{
if (comment.CommentType == CommentType.SingleLine) {
@@ -1458,17 +2088,17 @@ namespace ICSharpCode.PythonBinding
}
}
}
-
+
void IOutputFormatter.PrintPreprocessingDirective(PreprocessingDirective directive, bool forceWriteInPreviousBlock)
{
}
-
+
void IOutputFormatter.PrintBlankLine(bool forceWriteInPreviousBlock)
{
}
-
+
#endregion
-
+
///
/// Checks that the field declaration has an initializer that
/// sets an initial value.
@@ -1484,9 +2114,9 @@ namespace ICSharpCode.PythonBinding
/// This converts "i++" and "++i" to "i = i + 1" since python
/// does not support post increment expressions.
///
- object CreateIncrementStatement(UnaryOperatorExpression unaryOperatorExpression)
+ object CreateIncrementStatement(UnaryOperatorExpression unaryOperatorExpression, bool prefix = false)
{
- return CreateIncrementStatement(unaryOperatorExpression, 1, GetBinaryOperator(BinaryOperatorType.Add));
+ return CreateIncrementStatement(unaryOperatorExpression, 1, GetBinaryOperator(BinaryOperatorType.Add), prefix);
}
///
@@ -1494,25 +2124,31 @@ namespace ICSharpCode.PythonBinding
/// This converts "i--" and "--i" to "i -= 1" since python
/// does not support post increment expressions.
///
- object CreateDecrementStatement(UnaryOperatorExpression unaryOperatorExpression)
+ object CreateDecrementStatement(UnaryOperatorExpression unaryOperatorExpression, bool prefix = false)
{
- return CreateIncrementStatement(unaryOperatorExpression, 1, GetBinaryOperator(BinaryOperatorType.Subtract));
+ return CreateIncrementStatement(unaryOperatorExpression, 1, GetBinaryOperator(BinaryOperatorType.Subtract), prefix);
}
-
+
///
/// Converts a post or pre increment expression to an assign statement.
/// This converts "i++" and "++i" to "i += 1" since python
/// does not support post increment expressions.
///
- object CreateIncrementStatement(UnaryOperatorExpression unaryOperatorExpression, int increment, string binaryOperator)
+ object CreateIncrementStatement(UnaryOperatorExpression unaryOperatorExpression, int increment, string binaryOperator, bool prefix = false)
{
- unaryOperatorExpression.Expression.AcceptVisitor(this, null);
- Append(" " + binaryOperator + "= ");
- Append(increment.ToString());
-
+ if (accumulatePostfixStatements && !(unaryOperatorExpression.Parent is Statement)) {
+ unaryOperatorExpression.Expression.AcceptVisitor(this, null);
+
+ // prefix handled by the PrefixExpressionExtractor
+ if (!prefix) postfixStatements.Add(unaryOperatorExpression);
+ } else {
+ unaryOperatorExpression.Expression.AcceptVisitor(this, null);
+ Append(" " + binaryOperator + "= ");
+ Append(increment.ToString());
+ }
return null;
}
-
+
///
/// Creates the statement used to initialize the for loop. The
/// initialize statement will be "enumerator = variableName.GetEnumerator()"
@@ -1526,7 +2162,7 @@ namespace ICSharpCode.PythonBinding
return null;
}
-
+
///
/// Gets the name of the variable that is used in the
/// foreach loop as the item being iterated and appends the code.
@@ -1544,7 +2180,7 @@ namespace ICSharpCode.PythonBinding
memberRefExpression.AcceptVisitor(this, null);
}
}
-
+
///
/// Determines whether the identifier refers to a field in the
/// current class.
@@ -1568,7 +2204,61 @@ namespace ICSharpCode.PythonBinding
}
return false;
}
-
+
+ void AppendFieldReferenceName(string name)
+ {
+ // Check the current class's fields.
+ bool nameWritten = false;
+ if (constructorInfo != null) {
+ foreach (FieldDeclaration field in constructorInfo.Fields) {
+ foreach (VariableDeclaration variable in field.Fields) {
+ if (variable.Name == name) {
+ var fieldDecl = field.TypeReference.Parent as FieldDeclaration;
+ if (fieldDecl == null && ((field.Modifier & Modifiers.Const) != 0)) {
+ variable.Initializer.AcceptVisitor(this, null);
+ } else {
+ var typeDecl = fieldDecl.Parent as TypeDeclaration;
+ if (typeDecl == null) typeDecl = currentType; // use current type
+ if (typeDecl != null) {
+ if (field.TypeReference.IsNull || IsStatic(field))
+ Append(typeDecl.Name + "." + name);
+ else if (IsPrivate(field))
+ Append("self._" + name);
+ else
+ Append("self." + name); // no underscore for public methods
+ }
+ }
+ nameWritten = true;
+ }
+ }
+ }
+ }
+ if (!nameWritten) {
+ Append("self._" + name);
+ }
+ }
+
+ bool IsStaticField(string name)
+ {
+ // Check the current method's parameters.
+ if (IsMethodParameter(name)) {
+ return false;
+ }
+
+ // Check the current class's fields.
+ if (constructorInfo != null) {
+ foreach (FieldDeclaration field in constructorInfo.Fields) {
+ foreach (VariableDeclaration variable in field.Fields) {
+ if (variable.Name == name) {
+ if (field.TypeReference.IsNull || (field.Modifier & (Modifiers.Const | Modifiers.Static)) != 0)
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
bool IsMethodParameter(string name)
{
foreach (ParameterDeclarationExpression param in methodParameters) {
@@ -1578,12 +2268,12 @@ namespace ICSharpCode.PythonBinding
}
return false;
}
-
+
bool IsProperty(string name)
{
return propertyNames.Contains(name);
}
-
+
///
/// Creates an attach statement (i.e. button.Click += ButtonClick)
/// or remove statement (i.e. button.Click -= ButtonClick)
@@ -1595,7 +2285,7 @@ namespace ICSharpCode.PythonBinding
CreateDelegateCreateExpression(eventHandlerExpression);
return null;
}
-
+
///
/// Converts an expression to a CodeEventReferenceExpression
/// (i.e. the "button.Click" part of "button.Click += ButtonClick".
@@ -1607,7 +2297,7 @@ namespace ICSharpCode.PythonBinding
memberRef.AcceptVisitor(this, null);
return null;
}
-
+
///
/// Creates an event handler expression
/// (i.e. the "ButtonClick" part of "button.Click += ButtonClick")
@@ -1627,15 +2317,23 @@ namespace ICSharpCode.PythonBinding
}
return null;
}
-
+
///
/// Determines whether the assignment expression is actually an
/// event handler attach statement.
///
static bool IsAddEventHandler(AssignmentExpression assignmentExpression)
{
- return (assignmentExpression.Op == AssignmentOperatorType.Add) &&
- (assignmentExpression.Left is MemberReferenceExpression);
+ if ((assignmentExpression.Op == AssignmentOperatorType.Add)
+ && (assignmentExpression.Left is MemberReferenceExpression)
+ && ((assignmentExpression.Right is IdentifierExpression)
+ || (assignmentExpression.Right is ObjectCreateExpression)
+ || (assignmentExpression.Right is MemberReferenceExpression)
+ )
+ ) {
+ return true;
+ }
+ return false;
}
///
@@ -1644,47 +2342,60 @@ namespace ICSharpCode.PythonBinding
///
static bool IsRemoveEventHandler(AssignmentExpression assignmentExpression)
{
- return (assignmentExpression.Op == AssignmentOperatorType.Subtract) &&
- (assignmentExpression.Left is MemberReferenceExpression);
+ if ((assignmentExpression.Op == AssignmentOperatorType.Subtract)
+ && (assignmentExpression.Left is MemberReferenceExpression)
+ && ((assignmentExpression.Right is IdentifierExpression)
+ || (assignmentExpression.Right is ObjectCreateExpression)
+ || (assignmentExpression.Right is MemberReferenceExpression)
+ )
+ ) {
+ return true;
+ }
+ return false;
}
-
+
void Append(string code)
{
codeBuilder.Append(code);
}
-
+
void AppendIndented(string code)
{
codeBuilder.AppendIndented(code);
}
-
+
void AppendIndentedPassStatement()
{
AppendIndentedLine("pass");
}
-
+
void AppendIndentedLine(string code)
{
codeBuilder.AppendIndentedLine(code);
}
-
+
void AppendLine()
{
codeBuilder.AppendLine();
}
-
+
void IncreaseIndent()
{
codeBuilder.IncreaseIndent();
}
-
+
void DecreaseIndent()
{
codeBuilder.DecreaseIndent();
}
-
+
void CreateConstructor(PythonConstructorInfo constructorInfo)
{
+ // handle static fields
+ foreach (var field in constructorInfo.Fields) {
+ CreateStaticFieldInitialization(field, null);
+ }
+
if (constructorInfo.Constructor != null) {
AppendIndented("def __init__");
AddParameters(constructorInfo.Constructor);
@@ -1693,28 +2404,27 @@ namespace ICSharpCode.PythonBinding
AppendIndented("def __init__(self):");
}
AppendLine();
-
+
// Add fields at start of constructor.
IncreaseIndent();
AppendDocstring(xmlDocComments);
- if (constructorInfo.Fields.Count > 0) {
- foreach (FieldDeclaration field in constructorInfo.Fields) {
- CreateFieldInitialization(field);
- }
+ foreach (var field in constructorInfo.Fields) {
+ CreateFieldInitialization(field);
+ }
+ foreach (var property in constructorInfo.Properties) {
+ CreatePropertyInitialization(property);
}
-
+
if (!IsEmptyConstructor(constructorInfo.Constructor)) {
constructorInfo.Constructor.Body.AcceptVisitor(this, null);
AppendLine();
- } else if (constructorInfo.Fields.Count == 0) {
- AppendIndentedPassStatement();
} else {
- AppendLine();
+ AppendIndentedPassStatement();
}
-
+
DecreaseIndent();
}
-
+
///
/// Returns true if the constructor has no statements in its body.
///
@@ -1725,25 +2435,125 @@ namespace ICSharpCode.PythonBinding
}
return true;
}
-
+
+ void CreateEnumeration(TypeDeclaration typeDeclaration)
+ {
+ object current = 0;
+ foreach (INode node in typeDeclaration.Children) {
+ var field = node as FieldDeclaration;
+ if (field != null) {
+ object last = CreateStaticFieldInitialization(field, current);
+ if (last != null) current = last;
+ }
+ }
+ if (current.Equals(0)) {
+ AppendIndentedLine("pass");
+ }
+ }
+
///
/// Creates a field initialization statement.
///
void CreateFieldInitialization(FieldDeclaration field)
{
- foreach (VariableDeclaration variable in field.Fields) {
+ if (field.TypeReference.IsNull || (field.Modifier & (Modifiers.Const | Modifiers.Static)) != 0)
+ return;
+ foreach (VariableDeclaration variable in field.Fields) {
// Ignore field if it has no initializer.
if (FieldHasInitialValue(variable)) {
AddTypeToArrayInitializerIfMissing(variable);
-
+
string oldVariableName = variable.Name;
- variable.Name = "self._" + variable.Name;
+ if (IsPrivate(field))
+ variable.Name = "self._" + variable.Name;
+ else
+ variable.Name = "self." + variable.Name;
VisitVariableDeclaration(variable, null);
variable.Name = oldVariableName;
}
}
}
-
+ ///
+ /// Creates a field initialization statement.
+ ///
+ object CreateStaticFieldInitialization(FieldDeclaration field, object value)
+ {
+ if (!field.TypeReference.IsNull && (field.Modifier & (Modifiers.Const | Modifiers.Static)) == 0)
+ return value;
+
+ foreach (VariableDeclaration variable in field.Fields) {
+ // Ignore field if it has no initializer.
+ if (FieldHasInitialValue(variable)) {
+ AddTypeToArrayInitializerIfMissing(variable);
+ VisitVariableDeclaration(variable, null);
+ value = variable;
+ } else {
+ var line = variable.Name + " = ";
+ if (variable.TypeReference.IsNull && value != null) {
+ var declaration = value as VariableDeclaration;
+ if (declaration != null) {
+ line += declaration.Name;
+ line += " + 1";
+ } else {
+ line += value.ToString();
+ }
+ value = variable;
+ } else if (variable.TypeReference.IsArrayType || !variable.TypeReference.Type.StartsWith("System.")) {
+ line += "None";
+ } else {
+ Type type = Type.GetType(variable.TypeReference.Type, false, true);
+ if (type != null && type.IsValueType) {
+ //object default_value = Activator.CreateInstance(type);
+ line += GetTypeName(variable.TypeReference) + "()";
+ value = variable;
+ } else {
+ line += "None";
+ }
+ }
+ AppendIndentedLine(line);
+ }
+ }
+ return value;
+ }
+
+ bool IsValueType(TypeReference typeRef)
+ {
+ if (typeRef.IsArrayType)
+ return true;
+ if (!typeRef.Type.StartsWith("System."))
+ return false;
+ Type type = Type.GetType(typeRef.Type, false, true);
+ return (type != null && type.IsValueType);
+ }
+
+ ///
+ /// Creates a property initialization statement.
+ ///
+ void CreatePropertyInitialization(PropertyDeclaration property)
+ {
+
+ if (property.Initializer == null || property.Initializer.IsNull) {
+ AppendIndented("self._" + property.Name.ToLower() + " = ");
+ if (property.TypeReference.IsArrayType || !property.TypeReference.Type.StartsWith("System.")) {
+ Append("None");
+ } else {
+ Type type = Type.GetType(property.TypeReference.Type, false, true);
+ if (type != null && type.IsValueType) {
+ //object default_value = Activator.CreateInstance(type);
+ Append(GetTypeName(property.TypeReference));
+ Append("()");
+ } else {
+ Append("None");
+ }
+ }
+ AppendLine();
+ } else {
+ AppendIndented("self._" + property.Name.ToLower() + " = ");
+ property.Initializer.AcceptVisitor(this, null);
+ AppendLine();
+ }
+ }
+
void AddTypeToArrayInitializerIfMissing(VariableDeclaration variable)
{
ArrayCreateExpression arrayCreate = variable.Initializer as ArrayCreateExpression;
@@ -1751,7 +2561,7 @@ namespace ICSharpCode.PythonBinding
arrayCreate.CreateType = variable.TypeReference;
}
}
-
+
bool IsArrayMissingTypeToCreate(ArrayCreateExpression arrayCreate)
{
if (arrayCreate != null) {
@@ -1759,7 +2569,7 @@ namespace ICSharpCode.PythonBinding
}
return false;
}
-
+
///
/// Adds the method or constructor parameters.
///
@@ -1772,10 +2582,19 @@ namespace ICSharpCode.PythonBinding
Append("self, ");
}
for (int i = 0; i < parameters.Count; ++i) {
+ var param = parameters[i];
+ if (param.ParamModifier == ParameterModifiers.Out
+ || param.ParamModifier == ParameterModifiers.Ref) {
+ // track both ref and output for return statement
+ methodHasOutputParameters = true;
+ // drop output parameters from declarations
+ if (param.ParamModifier == ParameterModifiers.Out)
+ continue;
+ }
if (i > 0) {
Append(", ");
}
- Append(parameters[i].ParameterName);
+ Append(param.ParameterName);
}
} else {
if (!IsStatic(method)) {
@@ -1784,21 +2603,32 @@ namespace ICSharpCode.PythonBinding
}
Append("):");
}
-
- bool IsStatic(ParametrizedNode method)
+
+ bool IsStatic(AttributedNode method)
{
- return (method.Modifier & Modifiers.Static) == Modifiers.Static;
+ return method == null || (method.Modifier & (Modifiers.Const | Modifiers.Static)) != 0;
}
-
+
+ bool IsPrivate(AttributedNode node)
+ {
+ return node != null && (((node.Modifier & (Modifiers.Private)) == Modifiers.Private)
+ || ((node.Modifier & (Modifiers.Public | Modifiers.Internal)) == 0));
+ }
+
///
/// Creates assignments of the form:
/// i = 1
///
object CreateSimpleAssignment(AssignmentExpression assignmentExpression, string op, object data)
{
- assignmentExpression.Left.AcceptVisitor(this, data);
- Append(" " + op + " ");
- assignmentExpression.Right.AcceptVisitor(this, data);
+ if (accumulatePostfixStatements && !(assignmentExpression.Parent is Statement)) {
+ assignmentExpression.Left.AcceptVisitor(this, null);
+ postfixStatements.Add(assignmentExpression);
+ } else {
+ assignmentExpression.Left.AcceptVisitor(this, data);
+ Append(" " + op + " ");
+ assignmentExpression.Right.AcceptVisitor(this, data);
+ }
return null;
}
@@ -1813,7 +2643,7 @@ namespace ICSharpCode.PythonBinding
expression.AcceptVisitor(this, null);
return null;
}
-
+
///
/// Converts a switch case statement to an if/elif/else in Python.
///
@@ -1843,11 +2673,11 @@ namespace ICSharpCode.PythonBinding
}
firstLabel = false;
}
-
+
Append(":");
AppendLine();
}
-
+
///
/// Creates the switch test condition
///
@@ -1859,7 +2689,7 @@ namespace ICSharpCode.PythonBinding
Append(" == ");
label.Label.AcceptVisitor(this, null);
}
-
+
///
/// Creates the statements inside a switch case statement.
///
@@ -1880,7 +2710,7 @@ namespace ICSharpCode.PythonBinding
AppendIndentedLine("pass");
}
}
-
+
///
/// Gets the supported language either C# or VB.NET
///
@@ -1892,7 +2722,7 @@ namespace ICSharpCode.PythonBinding
}
return SupportedLanguage.CSharp;
}
-
+
///
/// Saves the method declaration if it is a main entry point.
///
@@ -1902,7 +2732,7 @@ namespace ICSharpCode.PythonBinding
entryPointMethods.Add(method);
}
}
-
+
///
/// Returns true if the object being created is a generic.
///
@@ -1910,7 +2740,7 @@ namespace ICSharpCode.PythonBinding
{
return expression.CreateType.GenericTypes.Count > 0;
}
-
+
///
/// Appends the types used when creating a generic surrounded by square brackets.
///
@@ -1924,14 +2754,14 @@ namespace ICSharpCode.PythonBinding
}
TypeReference typeRef = typeRefs[i];
if (typeRef.IsArrayType) {
- Append("Array[" + GetTypeName(typeRef) + "]");
+ Append(GetTypeName("System.Array") + "[" + GetTypeName(typeRef) + "]");
} else {
Append(GetTypeName(typeRef));
}
}
Append("]");
}
-
+
///
/// If the type is String or Int32 then it returns "str" and "int".
///
@@ -1942,6 +2772,14 @@ namespace ICSharpCode.PythonBinding
string GetTypeName(TypeReference typeRef)
{
string name = typeRef.Type;
+
+ if (typeNameMap.ContainsKey(name)) {
+ return typeNameMap[name];
+ }
+ foreach (string library in importLibraries) {
+ if (name.StartsWith(library))
+ return name.Substring(library.Length);
+ }
if (name == typeof(String).FullName) {
return "str";
} else if ((name == typeof(int).FullName) || ((name == typeof(int).Name))) {
@@ -1955,19 +2793,46 @@ namespace ICSharpCode.PythonBinding
}
return name;
}
-
+
+ ///
+ /// Converts name to appropriately scoped version based on imports
+ ///
+ /// If the type is a keyword (e.g. uint) then the TypeRef.Type returns
+ /// the full type name. It returns the short type name if the type is not a keyword. So
+ /// this method will strip the namespace from the name.
+ ///
+ private string GetTypeName(string name)
+ {
+ if (typeNameMap.ContainsKey(name)) {
+ return typeNameMap[name];
+ }
+ foreach (string library in importLibraries) {
+ if (name.StartsWith(library))
+ return name.Substring(library.Length);
+ }
+ return name;
+ }
+
///
/// Gets the type name that defines the method.
///
- static string GetTypeName(MethodDeclaration methodDeclaration)
+ string GetTypeName(MethodDeclaration methodDeclaration)
{
TypeDeclaration type = methodDeclaration.Parent as TypeDeclaration;
- return type.Name;
+ string name = type.Name;
+ if (typeNameMap.ContainsKey(name)) {
+ return typeNameMap[name];
+ }
+ foreach (string library in importLibraries) {
+ if (name.StartsWith(library))
+ return name.Substring(library.Length);
+ }
+ return name;
}
-
+
void AppendMultilineComment(Comment comment)
{
- string[] lines = comment.CommentText.Split(new char[] {'\n'});
+ string[] lines = comment.CommentText.Split(new char[] { '\n' });
for (int i = 0; i < lines.Length; ++i) {
string line = "# " + lines[i].Trim();
if ((i == 0) && !comment.CommentStartsLine) {
@@ -1986,7 +2851,7 @@ namespace ICSharpCode.PythonBinding
codeBuilder.AppendToPreviousLine(" #" + comment.CommentText);
}
}
-
+
void AppendDocstring(List xmlDocComments)
{
if (xmlDocComments.Count > 1) {
@@ -2007,7 +2872,7 @@ namespace ICSharpCode.PythonBinding
AppendIndentedLine(Docstring + xmlDocComments[0].CommentText + Docstring);
}
}
-
+
///
/// Returns true if the node is a type declaration or a method since these can have
/// python docstrings.
@@ -2016,19 +2881,19 @@ namespace ICSharpCode.PythonBinding
{
return (node is TypeDeclaration) || (node is MethodDeclaration) || (node is ConstructorDeclaration);
}
-
+
void AppendPropertyDecorator(PropertyDeclaration propertyDeclaration)
{
string propertyName = propertyDeclaration.Name;
AppendIndented(propertyName);
Append(" = property(");
-
+
bool addedParameter = false;
if (propertyDeclaration.HasGetRegion) {
Append("fget=get_" + propertyName);
addedParameter = true;
}
-
+
if (propertyDeclaration.HasSetRegion) {
if (addedParameter) {
Append(", ");
@@ -2038,7 +2903,7 @@ namespace ICSharpCode.PythonBinding
Append(")");
AppendLine();
}
-
+
void AppendBaseTypes(List baseTypes)
{
Append("(");
@@ -2047,6 +2912,8 @@ namespace ICSharpCode.PythonBinding
} else {
for (int i = 0; i < baseTypes.Count; ++i) {
TypeReference typeRef = baseTypes[i];
+ if (IsValueType(typeRef)) // fix for enumerations
+ continue;
if (i > 0) {
Append(", ");
}
@@ -2055,5 +2922,22 @@ namespace ICSharpCode.PythonBinding
}
Append("):");
}
+
+ ///
+ /// Generate the PostFix increment statements
+ ///
+ /// list of statements to write
+ private void CreatePostfixStatements(IEnumerable list)
+ {
+ bool oldAccumulatePostfixStatements = accumulatePostfixStatements;
+ accumulatePostfixStatements = false;
+ foreach (var expression in list) {
+ AppendIndented(String.Empty);
+ expression.AcceptVisitor(this, null);
+ AppendLine();
+ }
+ accumulatePostfixStatements = oldAccumulatePostfixStatements;
+ }
+
}
}
diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PrefixExpressionExtractor.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PrefixExpressionExtractor.cs
new file mode 100644
index 0000000000..e9f360e512
--- /dev/null
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PrefixExpressionExtractor.cs
@@ -0,0 +1,69 @@
+using System.Collections.Generic;
+using ICSharpCode.NRefactory.Ast;
+using ICSharpCode.NRefactory.Visitors;
+
+namespace ICSharpCode.PythonBinding
+{
+ ///
+ /// This Vistor is used to locate Prefix expressions and insert them
+ /// in statement block prior to owned statement. This is probably expensive
+ /// but without caching on statement writes no easy way to do it.
+ /// May be faster to do once per Method to see if any Prefix exist at all
+ /// and then disable checks while in that method
+ ///
+ internal class PrefixExpressionExtractor : NodeTrackingAstVisitor
+ {
+ readonly List statements = new List();
+ private int statementRecursion;
+ public List Statements
+ {
+ get { return statements; }
+ }
+
+ public void Reset()
+ {
+ statementRecursion = 0;
+ }
+
+ protected override void BeginVisit(INode node)
+ {
+ if (node is Statement)
+ statementRecursion++;
+ base.BeginVisit(node);
+ }
+ protected override void EndVisit(INode node)
+ {
+ if (node is Statement)
+ statementRecursion--;
+ base.EndVisit(node);
+ }
+ public override object TrackedVisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data)
+ {
+ // only accumulate if current statement is active. And also not immediate parent
+ if (statementRecursion == 1 && !(unaryOperatorExpression.Parent is Statement)) {
+ switch (unaryOperatorExpression.Op) {
+ case UnaryOperatorType.Increment:
+ case UnaryOperatorType.Decrement:
+ statements.Add(unaryOperatorExpression);
+ break;
+ }
+ }
+ return base.TrackedVisitUnaryOperatorExpression(unaryOperatorExpression, data);
+ }
+ public override object TrackedVisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, object data)
+ {
+ if (statementRecursion == 1 && !(anonymousMethodExpression.Parent is Statement)) {
+ statements.Add(anonymousMethodExpression);
+ }
+ return null;
+ }
+ public override object TrackedVisitLambdaExpression(LambdaExpression lambdaExpression, object data)
+ {
+ if (statementRecursion == 1 && !(lambdaExpression.Parent is Statement)) {
+ if (!lambdaExpression.StatementBody.IsNull)
+ statements.Add(lambdaExpression);
+ }
+ return base.TrackedVisitLambdaExpression(lambdaExpression, data);
+ }
+ }
+}
\ No newline at end of file