/******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.core.dom; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.parser.Scanner; import org.eclipse.jface.text.IDocument; import org.eclipse.text.edits.TextEdit; /** * Java compilation unit AST node type. This is the type of the root of an AST. *
* The source range for this type of node is ordinarily the entire source file, * including leading and trailing whitespace and comments. *
* For JLS2: ** CompilationUnit: * [ PackageDeclaration ] * { ImportDeclaration } * { TypeDeclaration | ; } ** For JLS3, the kinds of type declarations * grew to include enum and annotation type declarations: *
* CompilationUnit: * [ PackageDeclaration ] * { ImportDeclaration } * { TypeDeclaration | EnumDeclaration | AnnotationTypeDeclaration | ; } ** * @since 2.0 */ public class CompilationUnit extends ASTNode { /** * The "package" structural property of this node type. * * @since 3.0 */ public static final ChildPropertyDescriptor PACKAGE_PROPERTY = new ChildPropertyDescriptor(CompilationUnit.class, "package", PackageDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ /** * The "imports" structural property of this node type. * * @since 3.0 */ public static final ChildListPropertyDescriptor IMPORTS_PROPERTY = new ChildListPropertyDescriptor(CompilationUnit.class, "imports", ImportDeclaration.class, NO_CYCLE_RISK); //$NON-NLS-1$ /** * The "types" structural property of this node type. * * @since 3.0 */ public static final ChildListPropertyDescriptor TYPES_PROPERTY = new ChildListPropertyDescriptor(CompilationUnit.class, "types", AbstractTypeDeclaration.class, CYCLE_RISK); //$NON-NLS-1$ /** * A list of property descriptors (element type: * {@link StructuralPropertyDescriptor}), * or null if uninitialized. * @since 3.0 */ private static final List PROPERTY_DESCRIPTORS; static { List properyList = new ArrayList(4); createPropertyList(CompilationUnit.class, properyList); addProperty(PACKAGE_PROPERTY, properyList); addProperty(IMPORTS_PROPERTY, properyList); addProperty(TYPES_PROPERTY, properyList); PROPERTY_DESCRIPTORS = reapPropertyList(properyList); } /** * Returns a list of structural property descriptors for this node type. * Clients must not modify the result. * * @param apiLevel the API level; one of the *
AST.JLS*
constants
* @return a list of property descriptors (element type:
* {@link StructuralPropertyDescriptor})
* @since 3.0
*/
public static List propertyDescriptors(int apiLevel) {
return PROPERTY_DESCRIPTORS;
}
/**
* The comment table, or null
if none; initially
* null
. This array is the storage underlying
* the optionalCommentList
ArrayList.
* @since 3.0
*/
Comment[] optionalCommentTable = null;
/**
* The comment list (element type: Comment
,
* or null
if none; initially null
.
* @since 3.0
*/
private List optionalCommentList = null;
/**
* The package declaration, or null
if none; initially
* null
.
*/
private PackageDeclaration optionalPackageDeclaration = null;
/**
* The list of import declarations in textual order order;
* initially none (elementType: ImportDeclaration
).
*/
private ASTNode.NodeList imports =
new ASTNode.NodeList(IMPORTS_PROPERTY);
/**
* The list of type declarations in textual order order;
* initially none (elementType: AbstractTypeDeclaration
)
*/
private ASTNode.NodeList types =
new ASTNode.NodeList(TYPES_PROPERTY);
/**
* Line end table. If lineEndTable[i] == p
then the
* line number i+1
ends at character position
* p
. Except for the last line, the positions are that
* of the last character of the line delimiter.
* For example, the source string A\nB\nC
has
* line end table {1, 3} (if \n is one character).
*/
private int[] lineEndTable = new int[0];
/**
* Canonical empty list of messages.
*/
private static final Message[] EMPTY_MESSAGES = new Message[0];
/**
* Canonical empty list of problems.
*/
private static final IProblem[] EMPTY_PROBLEMS = new IProblem[0];
/**
* Messages reported by the compiler during parsing or name resolution.
*/
private Message[] messages;
/**
* Problems reported by the compiler during parsing or name resolution.
*/
private IProblem[] problems = EMPTY_PROBLEMS;
/**
* The comment mapper, or null
if none;
* initially null
.
* @since 3.0
*/
private DefaultCommentMapper commentMapper = null;
/**
* The Java element (an org.eclipse.jdt.core.ICompilationUnit
or an org.eclipse.jdt.core.IClassFile
)
* this compilation unit was created from, or null
if it was not created from a Java element.
* @since 3.1
*/
private IJavaElement element = null;
/**
* Sets the line end table for this compilation unit.
* If lineEndTable[i] == p
then line number i+1
* ends at character position p
. Except for the last line, the
* positions are that of (the last character of) the line delimiter.
* For example, the source string A\nB\nC
has
* line end table {1, 3, 4}.
*
* @param lineEndTable the line end table
*/
void setLineEndTable(int[] lineEndTable) {
if (lineEndTable == null) {
throw new NullPointerException();
}
// alternate root is *not* considered a structural property
// but we protect them nevertheless
checkModifiable();
this.lineEndTable = lineEndTable;
}
/**
* Creates a new AST node for a compilation owned by the given AST.
* The compilation unit initially has no package declaration, no
* import declarations, and no type declarations.
* * N.B. This constructor is package-private; all subclasses must be * declared in the same package; clients are unable to declare * additional subclasses. *
* * @param ast the AST that is to own this node */ CompilationUnit(AST ast) { super(ast); } /* (omit javadoc for this method) * Method declared on ASTNode. * @since 3.0 */ final List internalStructuralPropertiesForType(int apiLevel) { return propertyDescriptors(apiLevel); } /* (omit javadoc for this method) * Method declared on ASTNode. */ final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { if (property == PACKAGE_PROPERTY) { if (get) { return getPackage(); } else { setPackage((PackageDeclaration) child); return null; } } // allow default implementation to flag the error return super.internalGetSetChildProperty(property, get, child); } /* (omit javadoc for this method) * Method declared on ASTNode. */ final List internalGetChildListProperty(ChildListPropertyDescriptor property) { if (property == IMPORTS_PROPERTY) { return imports(); } if (property == TYPES_PROPERTY) { return types(); } // allow default implementation to flag the error return super.internalGetChildListProperty(property); } /* (omit javadoc for this method) * Method declared on ASTNode. */ final int getNodeType0() { return COMPILATION_UNIT; } /* (omit javadoc for this method) * Method declared on ASTNode. */ ASTNode clone0(AST target) { CompilationUnit result = new CompilationUnit(target); // n.b do not copy line number table or messages result.setSourceRange(this.getStartPosition(), this.getLength()); result.setPackage( (PackageDeclaration) ASTNode.copySubtree(target, getPackage())); result.imports().addAll(ASTNode.copySubtrees(target, imports())); result.types().addAll(ASTNode.copySubtrees(target, types())); return result; } /* (omit javadoc for this method) * Method declared on ASTNode. */ final boolean subtreeMatch0(ASTMatcher matcher, Object other) { // dispatch to correct overloaded match method return matcher.match(this, other); } /* (omit javadoc for this method) * Method declared on ASTNode. */ void accept0(ASTVisitor visitor) { boolean visitChildren = visitor.visit(this); if (visitChildren) { // visit children in normal left to right reading order acceptChild(visitor, getPackage()); acceptChildren(visitor, this.imports); acceptChildren(visitor, this.types); } visitor.endVisit(this); } /** * Returns the node for the package declaration of this compilation * unit, ornull
if this compilation unit is in the
* default package.
*
* @return the package declaration node, or null
if none
*/
public PackageDeclaration getPackage() {
return this.optionalPackageDeclaration;
}
/**
* Sets or clears the package declaration of this compilation unit
* node to the given package declaration node.
*
* @param pkgDecl the new package declaration node, or
* null
if this compilation unit does not have a package
* declaration (that is in the default package)
* @exception IllegalArgumentException if:
* ImportDeclaration
)
*/
public List imports() {
return this.imports;
}
/**
* Returns the live list of nodes for the top-level type declarations of this
* compilation unit, in order of appearance.
*
* Note that in JLS3, the types may include both enum declarations
* and annotation type declarations introduced in J2SE 5.
* For JLS2, the elements are always TypeDeclaration
.
*
AbstractTypeDeclaration
)
*/
public List types() {
return this.types;
}
/**
* Finds the corresponding AST node in the given compilation unit from
* which the given binding originated. Returns null
if the
* binding does not correspond to any node in this compilation unit.
* This method always returns null
if bindings were not requested
* when this AST was built.
* * The following table indicates the expected node type for the various * different kinds of bindings: *
PackageDeclaration
TypeDeclaration
or a
* AnonymousClassDeclaration
(for anonymous classes)VariableDeclarationFragment
in a
* FieldDeclaration
SingleVariableDeclaration
, or
* a VariableDeclarationFragment
in a
* VariableDeclarationStatement
or
* VariableDeclarationExpression
MethodDeclaration
MethodDeclaration
AnnotationTypeDeclaration
AnnotationTypeMemberDeclaration
EnumDeclaration
EnumConstantDeclaration
TypeParameter
* Each call to {@link ASTParser#createAST(org.eclipse.core.runtime.IProgressMonitor)} with a request for bindings
* gives rise to separate universe of binding objects. This method always returns
* null
when the binding object comes from a different AST.
* Use findDeclaringNode(binding.getKey())
when the binding comes
* from a different AST.
*
null
if the binding does not correspond to a node in this
* compilation unit or if bindings were not requested when this AST was built
* @see #findDeclaringNode(String)
*/
public ASTNode findDeclaringNode(IBinding binding) {
return this.ast.getBindingResolver().findDeclaringNode(binding);
}
/**
* Finds the corresponding AST node in the given compilation unit from
* which the given resolved annotation originated. Returns null
* if the resolved annotation does not correspond to any node in this compilation unit.
*
* This method always returns null
when the resolved annotation
* comes from a different AST.
*
* @param resolvedAnnotation the resolved annotation
* @return the corresponding node where the given resolved annotation is declared,
* or null
if the resolved annotation does not correspond to a node in this
* compilation unit or if bindings were not requested when this AST was built
* @since 3.2
*/
public ASTNode findDeclaringNode(IResolvedAnnotation resolvedAnnotation) {
return this.ast.getBindingResolver().findDeclaringNode(resolvedAnnotation);
}
/**
* Finds the corresponding AST node in the given compilation unit from
* which the binding with the given key originated. Returns
* null
if the corresponding node cannot be determined.
* This method always returns null
if bindings were not requested
* when this AST was built.
* * The following table indicates the expected node type for the various * different kinds of binding keys: *
PackageDeclaration
TypeDeclaration
or a
* AnonymousClassDeclaration
(for anonymous classes)VariableDeclarationFragment
in a
* FieldDeclaration
SingleVariableDeclaration
, or
* a VariableDeclarationFragment
in a
* VariableDeclarationStatement
or
* VariableDeclarationExpression
MethodDeclaration
MethodDeclaration
AnnotationTypeDeclaration
AnnotationTypeMemberDeclaration
EnumDeclaration
EnumConstantDeclaration
TypeParameter
* Note that as explained in {@link IBinding#getKey() IBinding.getkey} * there may be no keys for finding the declaring node for local variables, * local or anonymous classes, etc. *
* * @param key the binding key, ornull
* @return the corresponding node where a binding with the given
* key is declared, or null
if the key is null
* or if the key does not correspond to a node in this compilation unit
* or if bindings were not requested when this AST was built
* @see IBinding#getKey()
* @since 2.1
*/
public ASTNode findDeclaringNode(String key) {
return this.ast.getBindingResolver().findDeclaringNode(key);
}
/**
* Returns the internal comment mapper.
*
* @return the comment mapper, or null
if none.
* @since 3.0
*/
DefaultCommentMapper getCommentMapper() {
return this.commentMapper;
}
/**
* Initializes the internal comment mapper with the given
* scanner.
*
* @param scanner the scanner
* @since 3.0
*/
void initCommentMapper(Scanner scanner) {
this.commentMapper = new DefaultCommentMapper(this.optionalCommentTable);
this.commentMapper.initialize(this, scanner);
}
/**
* Returns the extended start position of the given node. Unlike
* {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()},
* the extended source range may include comments and whitespace
* immediately before or after the normal source range for the node.
*
* @param node the node
* @return the 0-based character index, or -1
* if no source position information is recorded for this node
* @see #getExtendedLength(ASTNode)
* @since 3.0
*/
public int getExtendedStartPosition(ASTNode node) {
if (node == null) {
throw new IllegalArgumentException();
}
if (this.commentMapper == null || node.getAST() != getAST()) {
// fall back: use best info available
return node.getStartPosition();
} else {
return this.commentMapper.getExtendedStartPosition(node);
}
}
/**
* Returns the extended source length of the given node. Unlike
* {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()},
* the extended source range may include comments and whitespace
* immediately before or after the normal source range for the node.
*
* @param node the node
* @return a (possibly 0) length, or 0
* if no source position information is recorded for this node
* @see #getExtendedStartPosition(ASTNode)
* @since 3.0
*/
public int getExtendedLength(ASTNode node) {
if (node == null) {
throw new IllegalArgumentException();
}
if (this.commentMapper == null || node.getAST() != getAST()) {
// fall back: use best info available
return node.getLength();
} else {
return this.commentMapper.getExtendedLength(node);
}
}
/**
* Returns the line number corresponding to the given source character
* position in the original source string. The initial line of the
* compilation unit is numbered 1, and each line extends through the
* last character of the end-of-line delimiter. The very last line extends
* through the end of the source string and has no line delimiter.
* For example, the source string class A\n{\n}
has 3 lines
* corresponding to inclusive character ranges [0,7], [8,9], and [10,10].
* Returns 1 for a character position that does not correspond to any
* source line, or if no line number information is available for this
* compilation unit.
*
* @param position a 0-based character position, possibly
* negative or out of range
* @return the 1-based line number, or 1
if the character
* position does not correspond to a source line in the original
* source file or if line number information is not known for this
* compilation unit
* @see ASTParser
*/
public int lineNumber(int position) {
int length = lineEndTable.length;
if (length == 0) {
// no line number info
return 1;
}
int low = 0;
if (position <= lineEndTable[low]) {
// position illegal or before the first line delimiter
return 1;
}
// assert position > lineEndTable[low+1] && low == 0
int hi = length - 1;
if (position > lineEndTable[hi]) {
// position beyond the last line separator
if (position >= getStartPosition() + getLength()) {
// this is beyond the end of the source length
return 1;
} else {
return length + 1;
}
}
// assert lineEndTable[low] < position <= lineEndTable[hi]
// && low == 0 && hi == length - 1 && low < hi
// binary search line end table
while (true) {
// invariant lineEndTable[low] < position <= lineEndTable[hi]
// && 0 <= low < hi <= length - 1
// reducing measure hi - low
if (low + 1 == hi) {
// assert lineEndTable[low] < position <= lineEndTable[low+1]
// position is on line low+1 (line number is low+2)
return low + 2;
}
// assert hi - low >= 2, so average is truly in between
int mid = (low + hi) / 2;
// assert 0 <= low < mid < hi <= length - 1
if (position <= lineEndTable[mid]) {
// assert lineEndTable[low] < position <= lineEndTable[mid]
// && 0 <= low < mid < hi <= length - 1
hi = mid;
} else {
// position > lineEndTable[mid]
// assert lineEndTable[mid] < position <= lineEndTable[hi]
// && 0 <= low < mid < hi <= length - 1
low = mid;
}
// in both cases, invariant reachieved with reduced measure
}
}
/**
* Returns the column number corresponding to the given source character
* position in the original source string. Column number are zero-based.
* Return zero if it is beyond the valid range.
*
* @param position a 0-based character position, possibly
* negative or out of range
* @return the 0-based coloumn number, or 0
if the character
* position does not correspond to a source line in the original
* source file or if column number information is not known for this
* compilation unit
* @see ASTParser
*/
public int columnNumber(final int position)
{
final int lineNumber = lineNumber(position);
final int startOfLine = getPosition(lineNumber, 0);
return position - startOfLine;
}
/**
* Given a line number and column number return the corresponding
* position in the original source string.
* Returns 0 if no line number information is available for this
* compilation unit or the requested line number is less than one.
* Return the total size of the source string if line
* is greater than the actual number lines in the unit.
* Assume 0 for the column number if column
is less than 0
* or return the position of the last character of the line if column
* is beyond the legal range.
*
* @param line the one-based line number
* @param column the zero-based column number.
* @return the 0-based character position in the source string.
* Return 0
if line/column number information is not known
* for this compilation unit or the input are not valid.
*
*/
public int getPosition(int line, int column)
{
int length = lineEndTable.length;
if( length == 0 || line < 1 ) return 0;
if( line == 1 ){
final int endOfLine = lineEndTable[0];
return column > endOfLine ? endOfLine : column;
}
else if( line > length + 1 )
// greater than the number of lines in the source string.
if( line > length + 1 )
return getStartPosition() + getLength();
if( column < 0 ) column = 0;
// -1 to for one-based to zero-based conversion.
// -1, again, to get previous line.
final int previousLine = line - 2;
final int previousLineOffset = lineEndTable[previousLine];
final int offsetForLine = previousLineOffset + 1 ; // + 1 for the newline character
final int currentLineEnd = lineEndTable[line-1];
if( (offsetForLine + column) > currentLineEnd )
return currentLineEnd;
else
return offsetForLine + column;
}
/**
* The Java element (an org.eclipse.jdt.core.ICompilationUnit
or an org.eclipse.jdt.core.IClassFile
)
* this compilation unit was created from, or null
if it was not created from a Java element.
*
* @return the Java element this compilation unit was created from, or null
if none
* @since 3.1
*/
public IJavaElement getJavaElement() {
return this.element;
}
/**
* Returns the list of messages reported by the compiler during the parsing
* or the type checking of this compilation unit. This list might be a subset of
* errors detected and reported by a Java compiler.
*
* This list of messages is suitable for simple clients that do little
* more than log the messages or display them to the user. Clients that
* need further details should call getProblems
to get
* compiler problem objects.
*
* Simple clients that do little more than log the messages or display
* them to the user should probably call getMessages
instead.
*
* Since the Java language allows comments to appear most anywhere * in the source text, it is problematic to locate comments in relation * to the structure of an AST. The one exception is doc comments * which, by convention, immediately precede type, field, and * method declarations; these comments are located in the AST * by {@link BodyDeclaration#getJavadoc BodyDeclaration.getJavadoc}. * Other comments do not show up in the AST. The table of comments * is provided for clients that need to find the source ranges of * all comments in the original source string. It includes entries * for comments of all kinds (line, block, and doc), arranged in order * of increasing source position. *
* Note on comment parenting: The {@link ASTNode#getParent() getParent()} * of a doc comment associated with a body declaration is the body * declaration node; for these comment nodes * {@link ASTNode#getRoot() getRoot()} will return the compilation unit * (assuming an unmodified AST) reflecting the fact that these nodes * are property located in the AST for the compilation unit. * However, for other comment nodes, {@link ASTNode#getParent() getParent()} * will returnnull
, and {@link ASTNode#getRoot() getRoot()}
* will return the comment node itself, indicating that these comment nodes
* are not directly connected to the AST for the compilation unit. The
* {@link Comment#getAlternateRoot Comment.getAlternateRoot}
* method provides a way to navigate from a comment to its compilation
* unit.
*
* * A note on visitors: The only comment nodes that will be visited when * visiting a compilation unit are the doc comments parented by body * declarations. To visit all comments in normal reading order, iterate * over the comment table and call {@link ASTNode#accept(ASTVisitor) accept} * on each element. *
** Clients cannot modify the resulting list. *
* * @return an unmodifiable list of comments in increasing order of source * start position, ornull
if comment information
* for this compilation unit is not available
* @see ASTParser
* @since 3.0
*/
public List getCommentList() {
return this.optionalCommentList;
}
/**
* Sets the list of the comments encountered while parsing
* this compilation unit.
*
* @param commentTable a list of comments in increasing order
* of source start position, or null
if comment
* information for this compilation unit is not available
* @exception IllegalArgumentException if the comment table is
* not in increasing order of source position
* @see #getCommentList()
* @see ASTParser
* @since 3.0
*/
void setCommentTable(Comment[] commentTable) {
// double check table to ensure that all comments have
// source positions and are in strictly increasing order
if (commentTable == null) {
this.optionalCommentList = null;
this.optionalCommentTable = null;
} else {
int nextAvailablePosition = 0;
for (int i = 0; i < commentTable.length; i++) {
Comment comment = commentTable[i];
if (comment == null) {
throw new IllegalArgumentException();
}
int start = comment.getStartPosition();
int length = comment.getLength();
if (start < 0 || length < 0 || start < nextAvailablePosition) {
throw new IllegalArgumentException();
}
nextAvailablePosition = comment.getStartPosition() + comment.getLength();
}
this.optionalCommentTable = commentTable;
List commentList = Arrays.asList(commentTable);
// protect the list from further modification
this.optionalCommentList = Collections.unmodifiableList(commentList);
}
}
/**
* Sets the Java element (an org.eclipse.jdt.core.ICompilationUnit
or an org.eclipse.jdt.core.IClassFile
)
* this compilation unit was created from, or null
if it was not created from a Java element.
*
* @param element the Java element this compilation unit was created from
* @since 3.1
*/
void setJavaElement(IJavaElement element) {
this.element = element;
}
/* (omit javadoc for this method)
* Method declared on ASTNode.
*/
int memSize() {
int size = BASE_NODE_SIZE + 8 * 4;
if (this.lineEndTable != null) {
size += HEADERS + 4 * this.lineEndTable.length;
}
if (this.optionalCommentTable != null) {
size += HEADERS + 4 * this.optionalCommentTable.length;
}
// ignore the space taken up by optionalCommentList
return size;
}
/* (omit javadoc for this method)
* Method declared on ASTNode.
*/
int treeSize() {
int size = memSize();
if (this.optionalPackageDeclaration != null) {
size += getPackage().treeSize();
}
size += this.imports.listSize();
size += this.types.listSize();
// include disconnected comments
if (this.optionalCommentList != null) {
for (int i = 0; i < this.optionalCommentList.size(); i++) {
Comment comment = (Comment) this.optionalCommentList.get(i);
if (comment != null && comment.getParent() == null) {
size += comment.treeSize();
}
}
}
return size;
}
/**
* Enables the recording of changes to this compilation
* unit and its descendents. The compilation unit must have
* been created by ASTParser
and still be in
* its original state. Once recording is on,
* arbitrary changes to the subtree rooted at this compilation
* unit are recorded internally. Once the modification has
* been completed, call rewrite
to get an object
* representing the corresponding edits to the original
* source code string.
*
* @exception IllegalArgumentException if this compilation unit is
* marked as unmodifiable, or if this compilation unit has already
* been tampered with, or recording has already been enabled
* @since 3.0
*/
public void recordModifications() {
getAST().recordModifications(this);
}
/**
* Converts all modifications recorded for this compilation
* unit into an object representing the corresponding text
* edits to the given document containing the original source
* code for this compilation unit.
*
* The compilation unit must have been created by
* ASTParser
from the source code string in the
* given document, and recording must have been turned
* on with a prior call to recordModifications
* while the AST was still in its original state.
*
* Calling this methods does not discard the modifications * on record. Subsequence modifications made to the AST * are added to the ones already on record. If this method * is called again later, the resulting text edit object will * accurately reflect the net cumulative affect of all those * changes. *
* * @param document original document containing source code * for this compilation unit * @param options the table of formatter options * (key type:String
; value type: String
);
* or null
to use the standard global options
* {@link org.eclipse.jdt.core.JavaCore#getOptions() JavaCore.getOptions()}.
* @return text edit object describing the changes to the
* document corresponding to the recorded AST modifications
* @exception IllegalArgumentException if the document passed is
* null
or does not correspond to this AST
* @exception IllegalStateException if recordModifications
* was not called to enable recording
* @see #recordModifications()
* @since 3.0
*/
public TextEdit rewrite(IDocument document, Map options) {
return getAST().rewrite(document, options);
}
}