/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.devtools.j2objc.ast; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.devtools.j2objc.util.TranslationEnvironment; import java.util.List; /** * Tree node for a Java compilation unit. */ public class CompilationUnit extends TreeNode { private final TranslationEnvironment env; private final String sourceFilePath; private final String mainTypeName; private final String source; private final int[] newlines; private boolean hasIncompleteProtocol = false; private boolean hasIncompleteImplementation = false; private boolean hasNullabilityAnnotations = false; private final ChildLink<PackageDeclaration> packageDeclaration = ChildLink.create(PackageDeclaration.class, this); private final ChildList<Comment> comments = ChildList.create(Comment.class, this); private final ChildList<NativeDeclaration> nativeBlocks = ChildList.create(NativeDeclaration.class, this); private final ChildList<AbstractTypeDeclaration> types = ChildList.create(AbstractTypeDeclaration.class, this); public CompilationUnit( TranslationEnvironment env, String sourceFilePath, String mainTypeName, String source) { super(); this.env = env; this.sourceFilePath = Preconditions.checkNotNull(sourceFilePath); this.mainTypeName = Preconditions.checkNotNull(mainTypeName); this.source = Preconditions.checkNotNull(source); newlines = findNewlines(source); } public CompilationUnit(CompilationUnit other) { super(other); this.env = other.env; sourceFilePath = other.getSourceFilePath(); mainTypeName = other.getMainTypeName(); source = other.getSource(); newlines = new int[other.newlines.length]; System.arraycopy(other.newlines, 0, newlines, 0, newlines.length); packageDeclaration.copyFrom(other.getPackage()); comments.copyFrom(other.getCommentList()); nativeBlocks.copyFrom(other.getNativeBlocks()); types.copyFrom(other.getTypes()); } @Override public Kind getKind() { return Kind.COMPILATION_UNIT; } public TranslationEnvironment getEnv() { return env; } public String getSourceFilePath() { return sourceFilePath; } public String getMainTypeName() { return mainTypeName; } public String getSource() { return source; } public boolean hasIncompleteProtocol() { return hasIncompleteProtocol; } public void setHasIncompleteProtocol() { hasIncompleteProtocol = true; } public boolean hasIncompleteImplementation() { return hasIncompleteImplementation; } public void setHasIncompleteImplementation() { hasIncompleteImplementation = true; } public boolean hasNullabilityAnnotations() { return hasNullabilityAnnotations; } public void setHasNullabilityAnnotations() { hasNullabilityAnnotations = true; } public PackageDeclaration getPackage() { return packageDeclaration.get(); } public void setPackage(PackageDeclaration newPackageDeclaration) { packageDeclaration.set(newPackageDeclaration); } public List<Comment> getCommentList() { return comments; } public List<NativeDeclaration> getNativeBlocks() { return nativeBlocks; } public List<AbstractTypeDeclaration> getTypes() { return types; } public int getLineNumber(int position) { if (position < 0 || position >= source.length()) { return -1; } return getLineNumber(position, 0, newlines.length - 1); } private int getLineNumber(int position, int start, int end) { if (start == end) { return start + 1; } int middle = (start + end + 1) / 2; if (newlines[middle] > position) { return getLineNumber(position, start, middle - 1); } else { return getLineNumber(position, middle, end); } } private static int[] findNewlines(String source) { List<Integer> newlinesList = Lists.newArrayList(); newlinesList.add(0); int len = source.length(); for (int i = 0; i < len; i++) { if (source.charAt(i) == '\n') { newlinesList.add(i + 1); } } int size = newlinesList.size(); int[] newlines = new int[size]; for (int i = 0; i < size; i++) { newlines[i] = newlinesList.get(i); } return newlines; } @Override protected void acceptInner(TreeVisitor visitor) { if (visitor.visit(this)) { packageDeclaration.accept(visitor); comments.accept(visitor); nativeBlocks.accept(visitor); types.accept(visitor); } visitor.endVisit(this); } @Override public CompilationUnit copy() { return new CompilationUnit(this); } @Override public void validateInner() { super.validateInner(); Preconditions.checkNotNull(sourceFilePath); Preconditions.checkNotNull(mainTypeName); Preconditions.checkNotNull(source); Preconditions.checkNotNull(packageDeclaration); } public CompilationUnit addComment(Comment comment) { comments.add(comment); return this; } public CompilationUnit addNativeBlock(NativeDeclaration decl) { nativeBlocks.add(decl); return this; } public CompilationUnit addType(AbstractTypeDeclaration type) { types.add(type); return this; } public CompilationUnit addType(int index, AbstractTypeDeclaration type) { types.add(index, type); return this; } }