Skip to content
This repository has been archived by the owner on Oct 16, 2020. It is now read-only.

Commit

Permalink
Refactor PythonAstWalker.
Browse files Browse the repository at this point in the history
  • Loading branch information
mrward committed Sep 29, 2010
1 parent c0c8677 commit 4efdaf8
Show file tree
Hide file tree
Showing 13 changed files with 479 additions and 186 deletions.
Expand Up @@ -93,22 +93,30 @@
<Compile Include="Src\IPythonResolver.cs" />
<Compile Include="Src\MemberName.cs" />
<Compile Include="Src\PythonBuiltInModuleMemberName.cs" />
<Compile Include="Src\PythonClass.cs" />
<Compile Include="Src\PythonClassResolver.cs" />
<Compile Include="Src\PythonCodeCompletionItemProvider.cs" />
<Compile Include="Src\PythonCompilationUnit.cs" />
<Compile Include="Src\PythonCompletionItemList.cs" />
<Compile Include="Src\PythonConsoleApplication.cs" />
<Compile Include="Src\PythonConstructor.cs" />
<Compile Include="Src\PythonDotNetMethodResolver.cs" />
<Compile Include="Src\PythonFromImport.cs" />
<Compile Include="Src\PythonImport.cs" />
<Compile Include="Src\PythonLanguageBinding.cs" />
<Compile Include="Src\PythonLocalVariableResolver.cs" />
<Compile Include="Src\PythonMemberResolver.cs" />
<Compile Include="Src\PythonMethod.cs" />
<Compile Include="Src\PythonMethodDefinition.cs" />
<Compile Include="Src\PythonMethodGroupResolveResult.cs" />
<Compile Include="Src\PythonMethodOrClassBodyRegion.cs" />
<Compile Include="Src\PythonMethodResolver.cs" />
<Compile Include="Src\PythonModule.cs" />
<Compile Include="Src\PythonModuleCompletionItems.cs" />
<Compile Include="Src\PythonModuleCompletionItemsFactory.cs" />
<Compile Include="Src\PythonImportResolver.cs" />
<Compile Include="Src\PythonNamespaceResolver.cs" />
<Compile Include="Src\PythonProperty.cs" />
<Compile Include="Src\PythonPropertyAssignment.cs" />
<Compile Include="Src\PythonResolverContext.cs" />
<Compile Include="Src\PythonSelfResolver.cs" />
Expand All @@ -125,6 +133,7 @@
<Compile Include="Src\PythonTestRunnerApplication.cs" />
<Compile Include="Src\PythonTestRunnerContext.cs" />
<Compile Include="Src\PythonTestRunnerResponseFile.cs" />
<Compile Include="Src\PythonUsingScope.cs" />
<Compile Include="Src\PythonWorkbench.cs" />
<Compile Include="Src\SendLineToPythonConsoleCommand.cs" />
<Compile Include="Src\SendSelectedTextToPythonConsoleCommand.cs" />
Expand Down
Expand Up @@ -18,32 +18,16 @@ namespace ICSharpCode.PythonBinding
/// </summary>
public class PythonAstWalker : PythonWalker
{
DefaultCompilationUnit compilationUnit;
PythonCompilationUnit compilationUnit;
IClass currentClass;
IClass globalClass;
PythonModule module;

/// <summary>
/// All classes in a file take the namespace of the filename.
/// </summary>
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);
}

/// <summary>
Expand All @@ -62,184 +46,73 @@ public void Walk(Statement statement)
statement.Walk(this);
}

/// <summary>
/// Walks a class definition.
/// </summary>
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;
}

/// <summary>
/// Walks a function definition.
/// </summary>
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;
}

/// <summary>
/// Walks an import statement and adds it to the compilation unit's
/// Usings.
/// </summary>
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;
}

/// <summary>
/// Gets the body region for a class or a method.
/// </summary>
/// <remarks>
/// Note that SharpDevelop line numbers are zero based but the
/// DomRegion values are one based. IronPython columns and lines are one based.
/// </remarks>
/// <param name="body">The body statement.</param>
/// <param name="header">The location of the header. This gives the end location for the
/// method or class definition up to the colon.</param>
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);
}

/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// A class region includes the body.
/// </remarks>
DomRegion GetRegion(ScopeStatement statement)
IClass GetClassBeingWalked()
{
return new DomRegion(statement.Start.Line, statement.Start.Column, statement.End.Line, statement.End.Column);
}

/// <summary>
/// Gets the region of a method. This does not include the body.
/// </summary>
DomRegion GetMethodRegion(FunctionDefinition node)
{
return new DomRegion(node.Start.Line, node.Start.Column, node.Header.Line, node.Header.Column + 1);
}

/// <summary>
/// Looks for any base types for the class defined in the
/// list of expressions and adds them to the class.
/// </summary>
void AddBaseTypes(IClass c, IList<Expression> 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;
}

/// <summary>
/// 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.
/// </summary>
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);
}

/// <summary>
/// Converts from Python AST expressions to parameters.
/// </summary>
/// <remarks>If the parameters belong to a class method then the first
/// "self" parameter can be ignored.</remarks>
IParameter[] ConvertParameters(IList<Parameter> parameters, bool ignoreFirstParameter)
{
List<IParameter> convertedParameters = new List<IParameter>();

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();
}

/// <summary>
/// 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.
/// </summary>
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;
}

/// <summary>
/// Creates the dummy class that is used to hold global methods.
/// </summary>
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)
Expand All @@ -254,9 +127,7 @@ public override bool Walk(AssignmentStatement node)
void WalkPropertyAssignment(AssignmentStatement node)
{
PythonPropertyAssignment propertyAssignment = new PythonPropertyAssignment(node);
if (propertyAssignment.IsProperty()) {
propertyAssignment.AddPropertyToClass(currentClass);
}
propertyAssignment.CreateProperty(currentClass);
}
}
}
@@ -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);
}

/// <summary>
/// Adds the namespace to the class name taken from the class definition.
/// </summary>
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);
}

/// <summary>
/// Gets the region of the scope statement (ClassDefinition).
/// </summary>
/// <remarks>
/// A class region includes the body.
/// </remarks>
void GetRegion(ScopeStatement statement)
{
Region = new DomRegion(statement.Start.Line, statement.Start.Column, statement.End.Line, statement.End.Column);
}

/// <summary>
/// Looks for any base types for the class defined in the
/// list of expressions and adds them to the class.
/// </summary>
void AddBaseTypes(IList<Expression> 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);
}
}

/// <summary>
/// Adds the named base type to the class.
/// </summary>
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);
}
}
}

0 comments on commit 4efdaf8

Please sign in to comment.