Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Difference between revisions of "DLTK Core Architecture"
(New page: == Build paths == Similar to java class paths, DLTK has a concept of build paths. Build paths is a set of source folders, library containers and references to another projects. This pat...) |
(→Model) |
||
(8 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
+ | [[Category:DLTK]] | ||
== Build paths == | == Build paths == | ||
− | Similar to | + | Similar to Java's class paths, DLTK has the concept of build paths. |
− | + | A build path is the set of source folders, library containers and references to other projects. The build path is used for model building and launching. | |
− | + | The build path is stored in the file .buildpath relative to the project's root folder. DLTK automatically reads it when required. You can get the current project's build path as an array of <code lang="java">IBuildpathEntry</code>s via the <code lang="java">IScriptProject.getRawBuildpath()</code> method. To change the build path for a project use the <code lang="java">setRawBuildpath()</code> method. New elements of <code lang="java">IBuildpathEntry</code> may be created with the <code lang="java">DLTKCore.new*Entry(...)</code> methods. | |
== Model == | == Model == | ||
− | + | The DLTK model is central to understanding DLTK. The DLTK model is based on the [[JDT]] [http://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.jdt.doc.isv%2Fguide%2Fjdt_int_model.htm Java Model], so if you are familiar with that then you will understand everything here quickly. | |
− | + | ||
− | + | ||
− | + | Like JDT, DLTK uses an in-memory, hierarchical object model to represent the workspace structure from the project level down to source file internals. This structure is derived from the project's build path. | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | The following table summarizes the different kinds of model elements. All element's classes support the <code lang="java">IModelElement</code> interface. | |
− | == | + | {| {{Greytable}} |
+ | |- | ||
+ | !Element | ||
+ | !JDT-analog | ||
+ | !Description | ||
+ | |- valign="top" | ||
+ | |<code lang="java">IScriptModel</code> | ||
+ | |<code lang="java">IJavaModel</code> | ||
+ | |Represents the root model element, corresponding to the workspace. The parent of all projects with the script natures. It also gives you access to the projects without the script nature. | ||
+ | |- valign="top" | ||
+ | |<code lang="java">IScriptProject</code> | ||
+ | |<code lang="java">IJavaProject</code> | ||
+ | |Represents a script project in the workspace. (Child of <code lang="java">IScriptModel</code>) | ||
+ | |- valign="top" | ||
+ | |<code lang="java">IProjectFragment</code> | ||
+ | |<code lang="java">IPackageFragmentRoot</code> | ||
+ | |Represents a project fragment, and maps the contents to an underlying resource which is either a folder, JAR, or ZIP file. (Child of <code lang="java">IScriptProject</code>) | ||
+ | |- valign="top" | ||
+ | |<code lang="java">IScriptFolder</code> | ||
+ | |<code lang="java">IPackageFragment</code> | ||
+ | |Represents a folder containing script files inside. (Child of <code lang="java">IProjectFragment</code>) | ||
+ | |- valign="top" | ||
+ | |<code lang="java">ISourceModule</code> | ||
+ | |<code lang="java">ICompilationUnit</code> | ||
+ | |Represents a source file. (Child of <code lang="java">IScriptFolder</code>) | ||
+ | |- valign="top" | ||
+ | |<code lang="java">IPackageDeclaration</code> | ||
+ | |<code lang="java">IPackageDeclaration</code> | ||
+ | |Represents a package declaration in a source module. (Child of <code lang="java">ISourceModule</code>) | ||
+ | |- valign="top" | ||
+ | |<code lang="java">IType</code> | ||
+ | |<code lang="java">IType</code> | ||
+ | |Represents either a class/module/namespace inside a source file. | ||
+ | |- valign="top" | ||
+ | |<code lang="java">IField</code> | ||
+ | |<code lang="java">IField</code> | ||
+ | |Represents a field inside a type. (Child of <code lang="java">IType</code>) | ||
+ | |- valign="top" | ||
+ | |<code lang="java">IMethod</code> | ||
+ | |<code lang="java">IMethod</code> | ||
+ | |Represents a method or constructor inside a type. (Child of <code lang="java">IType</code>) | ||
+ | |} | ||
− | + | You should use the <code lang="java">DLTKCore.create(...)</code> methods to build out a model. These methods make it easy for the DLTK user to create the appropriate model element from a file, resource or project. | |
− | + | ||
− | + | ||
− | + | ||
− | + | == Model building == | |
− | + | DLTK automatically provides model elements from the workspace level down to the source modules level. To extend the model, the DLTK user should: | |
+ | * contribute a <code lang="java">IDLTKLanguageToolkit</code> interface implementation via the <code>org.eclipse.dltk.core.language</code> extension point, | ||
+ | * contribute the language-specific nature as an extension point attribute, and return that from the <code lang="java">getNatureId()</code> method, | ||
+ | * implement methods <code lang="java">validateSourceModule()</code> and <code lang="java">validateSourcePackage()</code> to return OK only for source modules or packages that are real source modules. | ||
− | + | User projects that have the right nature will then be considered as a script project and the DLTK model for them will be built accordingly to internal structure, results from <code lang="java">validate...()</code> methods and from build paths. | |
+ | |||
+ | For building a source module's internal model elements, there is another mechanism called source element parsers. These are contributed via the <code>org.eclipse.dltk.core.sourceElementParsers</code> extension point and should implement <code lang="java">ISourceElementParser</code>. | ||
+ | |||
+ | The main task of the source element parser is to parse source files and report internal model element information to the given <code lang="java">ISourceElementRequestor</code>. | ||
== Search engine == | == Search engine == | ||
Line 94: | Line 78: | ||
===Indexes=== | ===Indexes=== | ||
− | + | The platform's search engine uses indexes. An index is a set of documents and the keys associated with them. There are possible several different indexes (for type names, methods, ...). | |
− | DLTK automatically index all source files in a separate thread. | + | DLTK automatically builds an index for all script source files in a separate thread. The DLTK provides a standard source element parser with a requester set to it's own <code lang="java">SourceIndexerRequestor</code> object. The source element parser doesn't know anything about search and just reports model elements info. The task of the <code lang="java">SourceIndexerRequestor</code> is to find and report appropriate index keys to the platform's <code lang="java">SourceIndexer</code>. The DLTK user may extend the DLTK's <code lang="java">SourceIndexerRequestor</code> as required. |
===Search=== | ===Search=== | ||
− | Before using the search engine user should prepare | + | Before using the search engine, the user should prepare DLTK <code lang="java">SearchPattern</code> objects. These may be a <code lang="java">TypeDeclarationPattern</code> or a <code lang="java">MethodPattern</code>. These can be created using the static method <code lang="java">SearchPattern.createPattern()</code>. |
− | + | ||
− | + | ||
− | + | ||
− | <code> | + | |
− | + | ||
− | + | After that, the user should specify a search scope(project, workspace,...). The scope may be created with the <code lang="java">SearchEngine.createSearchScope()</code> method. | |
− | + | ||
− | + | ||
− | + | ||
− | + | The final item required is a <code lang="java">SearchRequestor</code> object that will receive all successful search matches. | |
− | + | When that is ready, DLTK's <code lang="java">SearchEngine.search()</code> may be called. Here is an example: | |
− | + | <source lang="java"> | |
− | + | SearchRequestor requestor = new SearchRequestor() { | |
− | + | public void acceptSearchMatch(SearchMatch match) | |
− | + | throws CoreException { | |
− | + | // process match | |
− | + | } | |
− | + | }; | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | SearchPattern pattern = SearchPattern.createPattern(namePattern, | |
+ | IDLTKSearchConstants.METHOD, IDLTKSearchConstants.DECLARATIONS, | ||
+ | SearchPattern.R_PATTERN_MATCH | SearchPattern.R_EXACT_MATCH); | ||
+ | IDLTKSearchScope scope = SearchEngine.createWorkspaceScope(RubyLanguageToolkit | ||
+ | .getDefault()); | ||
− | = | + | try { |
+ | SearchEngine engine = new SearchEngine(); | ||
+ | engine.search(pattern, new SearchParticipant[] { SearchEngine | ||
+ | .getDefaultSearchParticipant() }, scope, requestor, null); | ||
+ | } catch (CoreException e) { | ||
+ | if (DLTKCore.DEBUG) | ||
+ | e.printStackTrace(); | ||
+ | } | ||
+ | </source> | ||
− | Extending | + | ===How search works=== |
+ | |||
+ | Extending the search engine requires understanding of how the search engine works. When <code lang="java">SearchEngine.search()</code> is called, a special <code lang="java">PatternSearchJob</code> is created containing all the indexes being enumerated. As result the list of documents containing matching keys will be found. Next, each document is reparsed with a <code lang="java">MatchLocator</code> and appropriate <code lang="java">SearchMatch</code> objects are reported. | ||
+ | |||
+ | The DLTK user should provide an implementation of <code lang="java">MatchLocatorParser</code> to use for reparsing. This object will receive a <code lang="java">MatchLocator</code> and a <code lang="java">PossibleMatch</code> (indicating a candidate source file) and while parsing should invoke the <code lang="java">match(...)</code> method on the <code lang="java">MatchLocator</code> with the matches it determines. | ||
==Runtime model ("mixin" model)== | ==Runtime model ("mixin" model)== | ||
− | DLTK has a very simple, but really powerful structure for managing runtime source files model. If model elements may be constructed from several source files | + | DLTK has a very simple, but really powerful structure for managing runtime source files model. If model elements may be constructed from several source files or can modified during execution, this approach can help. |
− | + | The mixin model is built on top of the standard indexes facility. A mixin parser (implementing <code lang="java">IMixinParser</code> with extension point <code>org.eclipse.dltk.core.mixin</code>) will reports <code lang="java">String</code>-typed mixin keys while parsing. A key may be reported many times from many places. To each key an <code lang="java">Object</code> may be attached and DLTK takes care of everything else. | |
− | + | Let's consider the following example for Ruby. | |
− | + | ||
− | + | ||
− | class Foo # key "Foo" reported, IType object attached | + | file1.rb |
+ | <source lang="ruby"> | ||
+ | class Foo # key "Foo" reported, IType object attached | ||
end | end | ||
− | class Foo # key "Foo" reported, IType object attached | + | class Foo # key "Foo" reported, IType object attached |
− | + | def doo # key "Foo{doo" reported, IMethod object attached | |
− | + | end | |
end | end | ||
+ | </source> | ||
file2.rb | file2.rb | ||
− | + | <source lang="ruby"> | |
− | class Foo # key "Foo" reported, IType object attached | + | class Foo # key "Foo" reported, IType object attached |
− | + | def doo2 # key "Foo{doo2" reported, IMethod object attached | |
− | + | end | |
end | end | ||
− | </ | + | </source> |
− | Now | + | |
+ | Now if we ask the model for the "Foo" key by calling the <code lang="java">MixinModel.get()</code> method, we'll receive an <code lang="java">IMixinElement</code> with the information that this key has been reported from files file1.rb and file2.rb. We'll also be able to get every IType object attached. | ||
+ | |||
+ | Using "{" as a standard delimiter allows us to call <code lang="java">IMixinElement#getChildren()</code> and fetch information about the "Foo{doo" and "Foo{doo2" keys. | ||
==Type inference== | ==Type inference== | ||
− | DLTK has a language independent engine for building type inference systems. It uses demand-driven analysis with subgoal pruning algorithm. | + | DLTK has a language independent engine for building type inference systems. It uses demand-driven analysis with a subgoal pruning algorithm. |
− | * Goal | + | |
− | * Goal evaluator | + | The key abstractions used here are: |
− | * Goal evaluator factory | + | * '''Goal''' This is an ASTNode in a source file, or an incoming/outcoming data flow, or whatever. Goals are unique. So two objects implementing <code lang="java">IGoal</code> that have a common ASTNode object should be equal. |
− | * Pruner | + | * '''Goal evaluator''' A strategy that knows how to evaluate a goal. While evaluating a goal it may produce helper goals (sub-goals). It may wait for their results and only after that produce its own result. |
+ | * '''Goal evaluator factory''' This factory constructs <code lang="java">GoalEvaluator</code> objects for the given <code lang="java">IGoal</code>s. | ||
+ | * '''Pruner''' The pruner is a strategy that is able to cancel some evaluators recognized as unimportant. The pruner is able to implement time limits for evaluations. | ||
// TODO | // TODO | ||
Line 188: | Line 181: | ||
===Launching a script=== | ===Launching a script=== | ||
− | DLTK launching engine is | + | The DLTK launching engine is integrated into the standard Eclipse framework. |
− | + | Each InterpreterInstall has an IInterpreterRunner object and the launch process is as follows: | |
− | * get selected interpreter install info from launch configuration (it should be put there before) | + | * get the selected interpreter install info from launch configuration (it should be put there before) |
− | * get runner | + | * get the runner |
* launch it | * launch it | ||
Line 203: | Line 196: | ||
==DLTK AST== | ==DLTK AST== | ||
− | + | {| {{Greytable}} | |
− | + | |- | |
− | + | !Class | |
− | + | !Description | |
− | + | |- | |
− | + | |<code lang="java">org.eclipse.dltk.ast.ASTNode</code> | |
− | + | |Superclass of all the AST nodes | |
− | + | |- | |
− | + | |<code lang="java">org.eclipse.dltk.ast.ASTListNode</code> | |
− | + | |Represents list of nodes. | |
− | + | |- | |
− | + | |<code lang="java">org.eclipse.dltk.ast.declarations.ModuleDeclaration</code> | |
− | + | |Top-level node for a source file. | |
− | + | |- | |
− | + | |<code lang="java">org.eclipse.dltk.ast.declarations.TypeDeclaration</code> | |
− | + | |Declaration of class/module/namespace. | |
− | + | |- | |
− | + | |<code lang="java">org.eclipse.dltk.ast.declarations.MethodDeclaration</code> | |
− | + | |Declaration of procedure or method. | |
− | + | |} | |
− | + | ||
− | + | ||
− | + | ||
− | Other classes you can find in org.eclipse.dltk.ast.* packages. | + | Other classes you can find in org.eclipse.dltk.ast.* packages. Use of the DLTK AST is not mandatory, but some DLTK features like folding may rely on it and it can greatly simplify implementation. |
Latest revision as of 08:07, 16 January 2016
Contents
Build paths
Similar to Java's class paths, DLTK has the concept of build paths.
A build path is the set of source folders, library containers and references to other projects. The build path is used for model building and launching.
The build path is stored in the file .buildpath relative to the project's root folder. DLTK automatically reads it when required. You can get the current project's build path as an array of IBuildpathEntry
s via the IScriptProject.getRawBuildpath()
method. To change the build path for a project use the setRawBuildpath()
method. New elements of IBuildpathEntry
may be created with the DLTKCore.new*Entry(...)
methods.
Model
The DLTK model is central to understanding DLTK. The DLTK model is based on the JDT Java Model, so if you are familiar with that then you will understand everything here quickly.
Like JDT, DLTK uses an in-memory, hierarchical object model to represent the workspace structure from the project level down to source file internals. This structure is derived from the project's build path.
The following table summarizes the different kinds of model elements. All element's classes support the IModelElement
interface.
Element | JDT-analog | Description |
---|---|---|
IScriptModel
|
IJavaModel
|
Represents the root model element, corresponding to the workspace. The parent of all projects with the script natures. It also gives you access to the projects without the script nature. |
IScriptProject
|
IJavaProject
|
Represents a script project in the workspace. (Child of IScriptModel )
|
IProjectFragment
|
IPackageFragmentRoot
|
Represents a project fragment, and maps the contents to an underlying resource which is either a folder, JAR, or ZIP file. (Child of IScriptProject )
|
IScriptFolder
|
IPackageFragment
|
Represents a folder containing script files inside. (Child of IProjectFragment )
|
ISourceModule
|
ICompilationUnit
|
Represents a source file. (Child of IScriptFolder )
|
IPackageDeclaration
|
IPackageDeclaration
|
Represents a package declaration in a source module. (Child of ISourceModule )
|
IType
|
IType
|
Represents either a class/module/namespace inside a source file. |
IField
|
IField
|
Represents a field inside a type. (Child of IType )
|
IMethod
|
IMethod
|
Represents a method or constructor inside a type. (Child of IType )
|
You should use the DLTKCore.create(...)
methods to build out a model. These methods make it easy for the DLTK user to create the appropriate model element from a file, resource or project.
Model building
DLTK automatically provides model elements from the workspace level down to the source modules level. To extend the model, the DLTK user should:
- contribute a
IDLTKLanguageToolkit
interface implementation via theorg.eclipse.dltk.core.language
extension point, - contribute the language-specific nature as an extension point attribute, and return that from the
getNatureId()
method, - implement methods
validateSourceModule()
andvalidateSourcePackage()
to return OK only for source modules or packages that are real source modules.
User projects that have the right nature will then be considered as a script project and the DLTK model for them will be built accordingly to internal structure, results from validate...()
methods and from build paths.
For building a source module's internal model elements, there is another mechanism called source element parsers. These are contributed via the org.eclipse.dltk.core.sourceElementParsers
extension point and should implement ISourceElementParser
.
The main task of the source element parser is to parse source files and report internal model element information to the given ISourceElementRequestor
.
Search engine
Indexes
The platform's search engine uses indexes. An index is a set of documents and the keys associated with them. There are possible several different indexes (for type names, methods, ...).
DLTK automatically builds an index for all script source files in a separate thread. The DLTK provides a standard source element parser with a requester set to it's own SourceIndexerRequestor
object. The source element parser doesn't know anything about search and just reports model elements info. The task of the SourceIndexerRequestor
is to find and report appropriate index keys to the platform's SourceIndexer
. The DLTK user may extend the DLTK's SourceIndexerRequestor
as required.
Search
Before using the search engine, the user should prepare DLTK SearchPattern
objects. These may be a TypeDeclarationPattern
or a MethodPattern
. These can be created using the static method SearchPattern.createPattern()
.
After that, the user should specify a search scope(project, workspace,...). The scope may be created with the SearchEngine.createSearchScope()
method.
The final item required is a SearchRequestor
object that will receive all successful search matches.
When that is ready, DLTK's SearchEngine.search()
may be called. Here is an example:
SearchRequestor requestor = new SearchRequestor() { public void acceptSearchMatch(SearchMatch match) throws CoreException { // process match } }; SearchPattern pattern = SearchPattern.createPattern(namePattern, IDLTKSearchConstants.METHOD, IDLTKSearchConstants.DECLARATIONS, SearchPattern.R_PATTERN_MATCH | SearchPattern.R_EXACT_MATCH); IDLTKSearchScope scope = SearchEngine.createWorkspaceScope(RubyLanguageToolkit .getDefault()); try { SearchEngine engine = new SearchEngine(); engine.search(pattern, new SearchParticipant[] { SearchEngine .getDefaultSearchParticipant() }, scope, requestor, null); } catch (CoreException e) { if (DLTKCore.DEBUG) e.printStackTrace(); }
How search works
Extending the search engine requires understanding of how the search engine works. When SearchEngine.search()
is called, a special PatternSearchJob
is created containing all the indexes being enumerated. As result the list of documents containing matching keys will be found. Next, each document is reparsed with a MatchLocator
and appropriate SearchMatch
objects are reported.
The DLTK user should provide an implementation of MatchLocatorParser
to use for reparsing. This object will receive a MatchLocator
and a PossibleMatch
(indicating a candidate source file) and while parsing should invoke the match(...)
method on the MatchLocator
with the matches it determines.
Runtime model ("mixin" model)
DLTK has a very simple, but really powerful structure for managing runtime source files model. If model elements may be constructed from several source files or can modified during execution, this approach can help.
The mixin model is built on top of the standard indexes facility. A mixin parser (implementing IMixinParser
with extension point org.eclipse.dltk.core.mixin
) will reports String
-typed mixin keys while parsing. A key may be reported many times from many places. To each key an Object
may be attached and DLTK takes care of everything else.
Let's consider the following example for Ruby.
file1.rb
class Foo # key "Foo" reported, IType object attached end class Foo # key "Foo" reported, IType object attached def doo # key "Foo{doo" reported, IMethod object attached end end
file2.rb
class Foo # key "Foo" reported, IType object attached def doo2 # key "Foo{doo2" reported, IMethod object attached end end
Now if we ask the model for the "Foo" key by calling the MixinModel.get()
method, we'll receive an IMixinElement
with the information that this key has been reported from files file1.rb and file2.rb. We'll also be able to get every IType object attached.
Using "{" as a standard delimiter allows us to call IMixinElement#getChildren()
and fetch information about the "Foo{doo" and "Foo{doo2" keys.
Type inference
DLTK has a language independent engine for building type inference systems. It uses demand-driven analysis with a subgoal pruning algorithm.
The key abstractions used here are:
- Goal This is an ASTNode in a source file, or an incoming/outcoming data flow, or whatever. Goals are unique. So two objects implementing
IGoal
that have a common ASTNode object should be equal. - Goal evaluator A strategy that knows how to evaluate a goal. While evaluating a goal it may produce helper goals (sub-goals). It may wait for their results and only after that produce its own result.
- Goal evaluator factory This factory constructs
GoalEvaluator
objects for the givenIGoal
s. - Pruner The pruner is a strategy that is able to cancel some evaluators recognized as unimportant. The pruner is able to implement time limits for evaluations.
// TODO
Launching
Interpreter management
Each interpreter installation in system is stored inside a IInterpreterInstall object. Such object knows interpreter name, executable path, arguments, library paths and also installation type and IInterpreterRunner object. Installation type is represented via IInterpreterInstallType object. Installation type knows about all installations with such type, knows how to fetch default library locations and able to validate installations.
For each language, DLTK stores a separate set of IInterpreterInstalls. One of them should be marked as "default".
The key class for accessing installation is a ScriptRuntime.
However, ScriptRuntime allows only to fetch installs, not to modify them. In fact, there is no beautiful way for that. So here we'll describe relatively low-level way to do that.
All information about interpreter installs are stored in plugin preferences in XML format. XML data can be read/created using an InterpreterDefinitionsContainer. This class represent a set of interpreter installs and allows to read them from XML or store to XML.
For setting set of interpreters in preferences, there are exists an IntepreterUpdater class. It takes an InterpreterDefinitionsContainer object and stores in plugin preferences. After that ScriptRuntime will be able to read new values.
Launching a script
The DLTK launching engine is integrated into the standard Eclipse framework.
Each InterpreterInstall has an IInterpreterRunner object and the launch process is as follows:
- get the selected interpreter install info from launch configuration (it should be put there before)
- get the runner
- launch it
In fact, all this stuff is already implemented. First, there is a AbstractScriptLaunchConfigurationDelegate class. It requires only two methods from user: getLanguageId() and createInterpreterConfig(). InterpreterConfig is a simple structure containing information for launch in a low-level form.
Also, for IInterpreterRunner exists a AbstractInterpreterRunner class, that requires from user only a launching plugin id and created process type.
For launching scripts programmatically there is a ScriptLaunchUtil class. It contains lots of methods for launching scripts.
DLTK AST
Class | Description |
---|---|
org.eclipse.dltk.ast.ASTNode
|
Superclass of all the AST nodes |
org.eclipse.dltk.ast.ASTListNode
|
Represents list of nodes. |
org.eclipse.dltk.ast.declarations.ModuleDeclaration
|
Top-level node for a source file. |
org.eclipse.dltk.ast.declarations.TypeDeclaration
|
Declaration of class/module/namespace. |
org.eclipse.dltk.ast.declarations.MethodDeclaration
|
Declaration of procedure or method. |
Other classes you can find in org.eclipse.dltk.ast.* packages. Use of the DLTK AST is not mandatory, but some DLTK features like folding may rely on it and it can greatly simplify implementation.