From 4efdaf8eddaac72c8c71b65f12780d282071e15d Mon Sep 17 00:00:00 2001 From: mrward Date: Wed, 29 Sep 2010 22:50:31 +0100 Subject: [PATCH] Refactor PythonAstWalker. --- .../Project/PythonBinding.csproj | 9 + .../Project/Src/PythonAstWalker.cs | 205 ++++-------------- .../PythonBinding/Project/Src/PythonClass.cs | 91 ++++++++ .../Project/Src/PythonCompilationUnit.cs | 18 ++ .../Project/Src/PythonConstructor.cs | 17 ++ .../PythonBinding/Project/Src/PythonMethod.cs | 98 +++++++++ .../Project/Src/PythonMethodDefinition.cs | 33 +++ .../Src/PythonMethodOrClassBodyRegion.cs | 39 ++++ .../PythonBinding/Project/Src/PythonModule.cs | 17 ++ .../Project/Src/PythonProperty.cs | 26 +++ .../Project/Src/PythonPropertyAssignment.cs | 38 ++-- .../Project/Src/PythonUsingScope.cs | 18 ++ .../Parsing/PythonParserParsePropertyTests.cs | 56 +++++ 13 files changed, 479 insertions(+), 186 deletions(-) create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonClass.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonCompilationUnit.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConstructor.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethod.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethodDefinition.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethodOrClassBodyRegion.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonModule.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonProperty.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonUsingScope.cs diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj b/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj index 6085bbc5cf..5686e7fafd 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj @@ -93,22 +93,30 @@ + + + + + + + + @@ -125,6 +133,7 @@ + diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs index e9024e3266..fad6d2aca5 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs @@ -18,32 +18,16 @@ namespace ICSharpCode.PythonBinding /// public class PythonAstWalker : PythonWalker { - DefaultCompilationUnit compilationUnit; + PythonCompilationUnit compilationUnit; IClass currentClass; - IClass globalClass; + PythonModule module; /// /// All classes in a file take the namespace of the filename. /// public PythonAstWalker(IProjectContent projectContent, string fileName) { - CreateCompilationUnit(projectContent, fileName); - } - - void CreateCompilationUnit(IProjectContent projectContent, string fileName) - { - compilationUnit = new DefaultCompilationUnit(projectContent); - compilationUnit.FileName = fileName; - - CreateUsingScopeForCompilationUnit(fileName); - } - - void CreateUsingScopeForCompilationUnit(string fileName) - { - DefaultUsingScope usingScope = new DefaultUsingScope(); - usingScope.NamespaceName = Path.GetFileNameWithoutExtension(fileName); - usingScope.Parent = new DefaultUsingScope(); - compilationUnit.UsingScope = usingScope; + compilationUnit = new PythonCompilationUnit(projectContent, fileName); } /// @@ -62,184 +46,73 @@ namespace ICSharpCode.PythonBinding statement.Walk(this); } - /// - /// Walks a class definition. - /// - public override bool Walk(ClassDefinition node) + public override bool Walk(ClassDefinition classDefinition) + { + PythonClass c = new PythonClass(compilationUnit, classDefinition); + WalkClassBody(c, classDefinition.Body); + return false; + } + + void WalkClassBody(IClass c, Statement classBody) { - DefaultClass c = new DefaultClass(compilationUnit, GetFullyQualifiedClassName(node)); - c.Region = GetRegion(node); - c.BodyRegion = GetBodyRegion(node.Body, node.Header); - AddBaseTypes(c, node.Bases); - - // Save the class. - compilationUnit.Classes.Add(c); - - // Walk through all the class items. currentClass = c; - node.Body.Walk(this); + classBody.Walk(this); currentClass = null; - - return false; } - /// - /// Walks a function definition. - /// public override bool Walk(FunctionDefinition node) { if (node.Body == null) { return false; } - bool ignoreFirstMethodParameter = true; - IClass c = currentClass; - if (currentClass == null) { - // Walking a global method. - CreateGlobalClass(); - c = globalClass; - ignoreFirstMethodParameter = false; - } + IClass c = GetClassBeingWalked(); - // Create method. - string methodName = node.Name; - DomRegion bodyRegion = GetBodyRegion(node.Body, node.Header); - DomRegion region = GetMethodRegion(node); - - DefaultMethod method; - if (methodName == "__init__") { - method = new Constructor(ModifierEnum.Public, region, bodyRegion, c); - } else { - method = new DefaultMethod(methodName, new DefaultReturnType(c), ModifierEnum.Public, region, bodyRegion, c); - } - foreach (IParameter parameter in ConvertParameters(node.Parameters, ignoreFirstMethodParameter)) { - method.Parameters.Add(parameter); - } - c.Methods.Add(method); - return false; - } - - /// - /// Walks an import statement and adds it to the compilation unit's - /// Usings. - /// - public override bool Walk(ImportStatement node) - { - PythonImport import = new PythonImport(compilationUnit.ProjectContent, node); - compilationUnit.UsingScope.Usings.Add(import); - return false; - } - - public override bool Walk(FromImportStatement node) - { - PythonFromImport import = new PythonFromImport(compilationUnit.ProjectContent, node); - compilationUnit.UsingScope.Usings.Add(import); + PythonMethodDefinition methodDefinition = new PythonMethodDefinition(node); + methodDefinition.CreateMethod(c); return false; } - - /// - /// Gets the body region for a class or a method. - /// - /// - /// Note that SharpDevelop line numbers are zero based but the - /// DomRegion values are one based. IronPython columns and lines are one based. - /// - /// The body statement. - /// The location of the header. This gives the end location for the - /// method or class definition up to the colon. - DomRegion GetBodyRegion(Statement body, SourceLocation header) - { - int columnAfterColonCharacter = header.Column + 1; - return new DomRegion(header.Line, header.Column + 1, body.End.Line, body.End.Column); - } /// - /// Gets the region of the scope statement (typically a ClassDefinition). + /// If the current class is null then create a module so a method outside of a class can be + /// parsed. /// - /// - /// A class region includes the body. - /// - DomRegion GetRegion(ScopeStatement statement) + IClass GetClassBeingWalked() { - return new DomRegion(statement.Start.Line, statement.Start.Column, statement.End.Line, statement.End.Column); - } - - /// - /// Gets the region of a method. This does not include the body. - /// - DomRegion GetMethodRegion(FunctionDefinition node) - { - return new DomRegion(node.Start.Line, node.Start.Column, node.Header.Line, node.Header.Column + 1); - } - - /// - /// Looks for any base types for the class defined in the - /// list of expressions and adds them to the class. - /// - void AddBaseTypes(IClass c, IList baseTypes) - { - foreach (Expression expression in baseTypes) { - NameExpression nameExpression = expression as NameExpression; - MemberExpression memberExpression = expression as MemberExpression; - if (nameExpression != null) { - AddBaseType(c, nameExpression.Name); - } else if (memberExpression != null) { - AddBaseType(c, PythonControlFieldExpression.GetMemberName(memberExpression)); - } + if (currentClass == null) { + // Walking a method outside a class. + CreateModule(); + return module; } + return currentClass; } /// - /// Adds the named base type to the class. + /// Creates the module which will act as a class so it can hold any methods defined in the module. /// - void AddBaseType(IClass c, string name) + void CreateModule() { - c.BaseTypes.Add(CreateSearchClassReturnType(c, name)); - } - - SearchClassReturnType CreateSearchClassReturnType(IClass c, string name) - { - return new SearchClassReturnType(c.ProjectContent, c, 0, 0, name, 0); - } - - /// - /// Converts from Python AST expressions to parameters. - /// - /// If the parameters belong to a class method then the first - /// "self" parameter can be ignored. - IParameter[] ConvertParameters(IList parameters, bool ignoreFirstParameter) - { - List convertedParameters = new List(); - - int startingIndex = 0; - if (ignoreFirstParameter) { - startingIndex = 1; - } - - for (int i = startingIndex; i < parameters.Count; ++i) { - DefaultParameter parameter = new DefaultParameter(parameters[i].Name, null, new DomRegion()); - convertedParameters.Add(parameter); + if (module == null) { + module = new PythonModule(compilationUnit); } - return convertedParameters.ToArray(); } /// - /// Adds the namespace to the class name taken from the class definition. + /// Walks an import statement and adds it to the compilation unit's + /// Usings. /// - string GetFullyQualifiedClassName(ClassDefinition classDef) + public override bool Walk(ImportStatement node) { - return String.Concat(compilationUnit.UsingScope.NamespaceName, ".", classDef.Name); + PythonImport import = new PythonImport(compilationUnit.ProjectContent, node); + compilationUnit.UsingScope.Usings.Add(import); + return false; } - /// - /// Creates the dummy class that is used to hold global methods. - /// - void CreateGlobalClass() + public override bool Walk(FromImportStatement node) { - if (globalClass == null) { - globalClass = new DefaultClass(compilationUnit, compilationUnit.UsingScope.NamespaceName); - compilationUnit.Classes.Add(globalClass); - } + PythonFromImport import = new PythonFromImport(compilationUnit.ProjectContent, node); + compilationUnit.UsingScope.Usings.Add(import); + return false; } public override bool Walk(AssignmentStatement node) @@ -254,9 +127,7 @@ namespace ICSharpCode.PythonBinding void WalkPropertyAssignment(AssignmentStatement node) { PythonPropertyAssignment propertyAssignment = new PythonPropertyAssignment(node); - if (propertyAssignment.IsProperty()) { - propertyAssignment.AddPropertyToClass(currentClass); - } + propertyAssignment.CreateProperty(currentClass); } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonClass.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonClass.cs new file mode 100644 index 0000000000..b3d64e5176 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonClass.cs @@ -0,0 +1,91 @@ +// 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 ICSharpCode.SharpDevelop.Dom; +using IronPython.Compiler.Ast; + +namespace ICSharpCode.PythonBinding +{ + public class PythonClass : DefaultClass + { + public PythonClass(ICompilationUnit compilationUnit, ClassDefinition classDefinition) + : base(compilationUnit, String.Empty) + { + GetFullyQualifiedName(classDefinition); + GetClassRegions(classDefinition); + AddBaseTypes(classDefinition.Bases); + + compilationUnit.Classes.Add(this); + } + + /// + /// Adds the namespace to the class name taken from the class definition. + /// + void GetFullyQualifiedName(ClassDefinition classDefinition) + { + string ns = CompilationUnit.UsingScope.NamespaceName; + FullyQualifiedName = String.Format("{0}.{1}", ns, classDefinition.Name); + } + + void GetClassRegions(ClassDefinition classDefinition) + { + GetRegion(classDefinition); + BodyRegion = PythonMethodOrClassBodyRegion.GetBodyRegion(classDefinition); + } + + /// + /// Gets the region of the scope statement (ClassDefinition). + /// + /// + /// A class region includes the body. + /// + void GetRegion(ScopeStatement statement) + { + Region = new DomRegion(statement.Start.Line, statement.Start.Column, statement.End.Line, statement.End.Column); + } + + /// + /// Looks for any base types for the class defined in the + /// list of expressions and adds them to the class. + /// + void AddBaseTypes(IList baseTypes) + { + foreach (Expression baseTypeExpression in baseTypes) { + AddBaseType(baseTypeExpression); + } + } + + void AddBaseType(Expression baseTypeExpression) + { + NameExpression nameExpression = baseTypeExpression as NameExpression; + MemberExpression memberExpression = baseTypeExpression as MemberExpression; + if (nameExpression != null) { + AddBaseType(nameExpression.Name); + } else if (memberExpression != null) { + AddBaseType(memberExpression); + } + } + + /// + /// Adds the named base type to the class. + /// + void AddBaseType(string name) + { + IReturnType returnType = CreateSearchClassReturnType(name); + BaseTypes.Add(returnType); + } + + void AddBaseType(MemberExpression memberExpression) + { + string name = PythonControlFieldExpression.GetMemberName(memberExpression); + AddBaseType(name); + } + + SearchClassReturnType CreateSearchClassReturnType(string name) + { + return new SearchClassReturnType(ProjectContent, this, 0, 0, name, 0); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonCompilationUnit.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonCompilationUnit.cs new file mode 100644 index 0000000000..1b99582ba3 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonCompilationUnit.cs @@ -0,0 +1,18 @@ +// 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 ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.PythonBinding +{ + public class PythonCompilationUnit : DefaultCompilationUnit + { + public PythonCompilationUnit(IProjectContent projectContent, string fileName) + : base(projectContent) + { + this.FileName = fileName; + this.UsingScope = new PythonUsingScope(fileName); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConstructor.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConstructor.cs new file mode 100644 index 0000000000..3b4c8eef17 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonConstructor.cs @@ -0,0 +1,17 @@ +// 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 ICSharpCode.SharpDevelop.Dom; +using IronPython.Compiler.Ast; + +namespace ICSharpCode.PythonBinding +{ + public class PythonConstructor : PythonMethod + { + public PythonConstructor(IClass declaringType, FunctionDefinition methodDefinition) + : base(declaringType, methodDefinition, "#ctor") + { + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethod.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethod.cs new file mode 100644 index 0000000000..1f9610ae84 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethod.cs @@ -0,0 +1,98 @@ +// 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 ICSharpCode.SharpDevelop.Dom; +using IronPython.Compiler.Ast; +using Microsoft.Scripting; + +namespace ICSharpCode.PythonBinding +{ + public class PythonMethod : DefaultMethod + { + public PythonMethod(IClass declaringType, FunctionDefinition methodDefinition) + : this(declaringType, methodDefinition, methodDefinition.Name) + { + } + + public PythonMethod(IClass declaringType, FunctionDefinition methodDefinition, string name) + : base(declaringType, name) + { + ReturnType = new DefaultReturnType(declaringType); + Modifiers = ModifierEnum.Public; + + GetMethodRegions(methodDefinition); + AddParameters(methodDefinition); + + declaringType.Methods.Add(this); + } + + void GetMethodRegions(FunctionDefinition methodDefinition) + { + GetBodyRegion(methodDefinition); + GetMethodRegion(methodDefinition); + } + + void GetBodyRegion(FunctionDefinition methodDefinition) + { + BodyRegion = PythonMethodOrClassBodyRegion.GetBodyRegion(methodDefinition); + } + + /// + /// Gets the region of a method. This does not include the body. + /// + void GetMethodRegion(FunctionDefinition methodDefinition) + { + SourceLocation start = methodDefinition.Start; + SourceLocation end = methodDefinition.Header; + Region = new DomRegion(start.Line, start.Column, end.Line, end.Column + 1); + } + + void AddParameters(FunctionDefinition methodDefinition) + { + bool ignoreFirstMethodParameter = !DeclaringTypeIsPythonModule; + AddParameters(methodDefinition, ignoreFirstMethodParameter); + } + + bool DeclaringTypeIsPythonModule { + get { return DeclaringType is PythonModule; } + } + + void AddParameters(FunctionDefinition methodDefinition, bool ignoreFirstMethodParameter) + { + foreach (IParameter parameter in ConvertParameters(methodDefinition.Parameters, ignoreFirstMethodParameter)) { + Parameters.Add(parameter); + } + } + + /// + /// Converts from Python AST expressions to parameters. + /// + /// If the parameters belong to a class method then the first + /// "self" parameter can be ignored. + IParameter[] ConvertParameters(IList parameters, bool ignoreFirstParameter) + { + int startingIndex = GetStartingIndex(ignoreFirstParameter); + return ConvertParameters(parameters, startingIndex); + } + + int GetStartingIndex(bool ignoreFirstParameter) + { + if (ignoreFirstParameter) { + return 1; + } + return 0; + } + + IParameter[] ConvertParameters(IList parameters, int startingIndex) + { + List convertedParameters = new List(); + for (int i = startingIndex; i < parameters.Count; ++i) { + DefaultParameter parameter = new DefaultParameter(parameters[i].Name, null, new DomRegion()); + convertedParameters.Add(parameter); + } + return convertedParameters.ToArray(); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethodDefinition.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethodDefinition.cs new file mode 100644 index 0000000000..cbcd188ca7 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethodDefinition.cs @@ -0,0 +1,33 @@ +// 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 ICSharpCode.SharpDevelop.Dom; +using IronPython.Compiler.Ast; +using Microsoft.Scripting; + +namespace ICSharpCode.PythonBinding +{ + public class PythonMethodDefinition + { + FunctionDefinition methodDefinition; + + public PythonMethodDefinition(FunctionDefinition methodDefinition) + { + this.methodDefinition = methodDefinition; + } + + public PythonMethod CreateMethod(IClass c) + { + if (IsConstructor) { + return new PythonConstructor(c, methodDefinition); + } + return new PythonMethod(c, methodDefinition); + } + + bool IsConstructor { + get { return methodDefinition.Name == "__init__"; } + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethodOrClassBodyRegion.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethodOrClassBodyRegion.cs new file mode 100644 index 0000000000..1c5acbc67d --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonMethodOrClassBodyRegion.cs @@ -0,0 +1,39 @@ +// 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 ICSharpCode.SharpDevelop.Dom; +using IronPython.Compiler.Ast; +using Microsoft.Scripting; + +namespace ICSharpCode.PythonBinding +{ + public static class PythonMethodOrClassBodyRegion + { + /// + /// Gets the body region for a class or a method. + /// + /// + /// Note that SharpDevelop line numbers are zero based but the + /// DomRegion values are one based. IronPython columns and lines are one based. + /// + /// The body statement. + /// The location of the header. This gives the end location for the + /// method or class definition up to the colon. + public static DomRegion GetBodyRegion(Statement body, SourceLocation header) + { + int columnAfterColonCharacter = header.Column + 1; + return new DomRegion(header.Line, header.Column + 1, body.End.Line, body.End.Column); + } + + public static DomRegion GetBodyRegion(FunctionDefinition methodDefinition) + { + return GetBodyRegion(methodDefinition.Body, methodDefinition.Header); + } + + public static DomRegion GetBodyRegion(ClassDefinition classDefinition) + { + return GetBodyRegion(classDefinition.Body, classDefinition.Header); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonModule.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonModule.cs new file mode 100644 index 0000000000..03d63f22bf --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonModule.cs @@ -0,0 +1,17 @@ +// 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 ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.PythonBinding +{ + public class PythonModule : DefaultClass + { + public PythonModule(ICompilationUnit compilationUnit) + : base(compilationUnit, compilationUnit.UsingScope.NamespaceName) + { + compilationUnit.Classes.Add(this); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonProperty.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonProperty.cs new file mode 100644 index 0000000000..324043a354 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonProperty.cs @@ -0,0 +1,26 @@ +// 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 ICSharpCode.SharpDevelop.Dom; +using Microsoft.Scripting; + +namespace ICSharpCode.PythonBinding +{ + public class PythonProperty : DefaultProperty + { + public PythonProperty(IClass declaringType, string name, SourceLocation location) + : base(declaringType, name) + { + GetPropertyRegion(location); + declaringType.Properties.Add(this); + } + + void GetPropertyRegion(SourceLocation location) + { + int line = location.Line; + int column = location.Column; + Region = new DomRegion(line, column, line, column); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonPropertyAssignment.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonPropertyAssignment.cs index 2dba9e1534..6a0cf95f1b 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonPropertyAssignment.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonPropertyAssignment.cs @@ -16,39 +16,39 @@ namespace ICSharpCode.PythonBinding this.assignmentStatement = assignmentStatement; } - public bool IsProperty() + public PythonProperty CreateProperty(IClass c) { - CallExpression rhs = assignmentStatement.Right as CallExpression; - if (rhs != null) { - NameExpression nameExpression = rhs.Target as NameExpression; + if (IsProperty()) { + NameExpression nameExpression = assignmentStatement.Left[0] as NameExpression; if (nameExpression != null) { - return nameExpression.Name == "property"; + string propertyName = nameExpression.Name; + return CreateProperty(c, propertyName); } } - return false; + return null; } - public void AddPropertyToClass(IClass c) + bool IsProperty() { - NameExpression nameExpression = assignmentStatement.Left[0] as NameExpression; - if (nameExpression != null) { - string propertyName = nameExpression.Name; - AddPropertyToClass(c, propertyName); + CallExpression callExpression = assignmentStatement.Right as CallExpression; + if (callExpression != null) { + return IsPropertyFunctionBeingCalled(callExpression); } + return false; } - void AddPropertyToClass(IClass c, string propertyName) + bool IsPropertyFunctionBeingCalled(CallExpression callExpression) { - DefaultProperty property = new DefaultProperty(c, propertyName); - property.Region = GetPropertyRegion(); - c.Properties.Add(property); + NameExpression nameExpression = callExpression.Target as NameExpression; + if (nameExpression != null) { + return nameExpression.Name == "property"; + } + return false; } - DomRegion GetPropertyRegion() + PythonProperty CreateProperty(IClass c, string propertyName) { - int line = assignmentStatement.Start.Line; - int column = assignmentStatement.Start.Column; - return new DomRegion(line, column, line, column); + return new PythonProperty(c, propertyName, assignmentStatement.Start); } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonUsingScope.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonUsingScope.cs new file mode 100644 index 0000000000..4a68f3e806 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonUsingScope.cs @@ -0,0 +1,18 @@ +// 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.IO; +using ICSharpCode.SharpDevelop.Dom; + +namespace ICSharpCode.PythonBinding +{ + public class PythonUsingScope : DefaultUsingScope + { + public PythonUsingScope(string fileName) + { + NamespaceName = Path.GetFileNameWithoutExtension(fileName); + Parent = new DefaultUsingScope(); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Parsing/PythonParserParsePropertyTests.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Parsing/PythonParserParsePropertyTests.cs index 7586707476..f5a2a16bbf 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Parsing/PythonParserParsePropertyTests.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Parsing/PythonParserParsePropertyTests.cs @@ -59,5 +59,61 @@ namespace PythonBinding.Tests.Parsing Assert.AreEqual(expectedRegion, region); } + + [Test] + public void Parse_ClassMethodHasNoPropertyButHasAssignmentStatementSetToValueFromFunctionCall_ParseInfoHasNoPropertyAdded() + { + string code = + "class MyClass:\r\n" + + " a = foo()\r\n" + + "\r\n"; + + ParseInformation parseInfo = PythonParserHelper.CreateParseInfo(code); + int count = parseInfo.CompilationUnit.Classes[0].Properties.Count; + + Assert.AreEqual(0, count); + } + + [Test] + public void Parse_ClassMethodHasNoPropertyButHasAssignmentStatementUsingMemberExpression_ParseInfoHasNoPropertyAddedAndNoExceptionThrown() + { + string code = + "class MyClass:\r\n" + + " a.b = foo()\r\n" + + "\r\n"; + + ParseInformation parseInfo = PythonParserHelper.CreateParseInfo(code); + int count = parseInfo.CompilationUnit.Classes[0].Properties.Count; + + Assert.AreEqual(0, count); + } + + [Test] + public void Parse_ClassMethodHasNoPropertyButHasAssignmentStatementSetToIntegerValue_ParseInfoHasNoPropertyAddedAndNoExceptionThrown() + { + string code = + "class MyClass:\r\n" + + " a = 1\r\n" + + "\r\n"; + + ParseInformation parseInfo = PythonParserHelper.CreateParseInfo(code); + int count = parseInfo.CompilationUnit.Classes[0].Properties.Count; + + Assert.AreEqual(0, count); + } + + [Test] + public void Parse_ClassMethodHasNoPropertyButHasAssignmentStatementSetToValueFromMemberExpressionCall_ParseInfoHasNoPropertyAddedAndNoExceptionThrown() + { + string code = + "class MyClass:\r\n" + + " a = foo.bar()\r\n" + + "\r\n"; + + ParseInformation parseInfo = PythonParserHelper.CreateParseInfo(code); + int count = parseInfo.CompilationUnit.Classes[0].Properties.Count; + + Assert.AreEqual(0, count); + } } } \ No newline at end of file