/*******************************************************************************
* Copyright (c) 2015 Bruno Medeiros and other Contributors.
* 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:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.lang.tooling.structure;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.CoreUtil.areEqual;
import static melnorme.utilbox.core.CoreUtil.nullToEmpty;
import melnorme.lang.tooling.common.ParserError;
import melnorme.utilbox.collections.Indexable;
import melnorme.utilbox.misc.HashcodeUtil;
import melnorme.utilbox.misc.Location;
public abstract class SourceFileStructure_Default extends AbstractStructureContainer implements ISourceFileStructure {
protected final Location location;
protected final Indexable<ParserError> parserProblems;
public SourceFileStructure_Default(Location location, Indexable<StructureElement> children,
Indexable<ParserError> parserProblems) {
super(children);
this.location = location;
this.parserProblems = nullToEmpty(parserProblems);
}
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(!(obj instanceof SourceFileStructure)) return false;
SourceFileStructure other = (SourceFileStructure) obj;
return
areEqual(location, other.location) &&
areEqual(children, other.children);
}
@Override
public int hashCode() {
return HashcodeUtil.combinedHashCode(location, children);
}
@Override
public String toString() {
return getClass().getSimpleName() + (location == null ? "" : " " + location);
}
/* ----------------- ----------------- */
@Override
public Location getLocation() {
return location;
}
@Override
public String getModuleName() {
return location == null ? null : location.getPath().getFileName().toString();
}
public Indexable<ParserError> getParserProblems() {
return parserProblems;
}
public StructureElement getStructureElementAt(int offset) {
return new StructureElementFinderByOffset(offset).findInnerMost(this);
}
/* ----------------- Utils ----------------- */
public static class StructureElementFinderByOffset {
protected final int offset;
protected StructureElement pickedElement;
public StructureElementFinderByOffset(int offset) {
this.offset = offset;
}
// Note: This could be optimized if element tree is sorted
public StructureElement findInnerMost(IStructureElementContainer container) {
visitContainer(container);
return pickedElement;
}
protected void visitContainer(IStructureElementContainer container) {
assertNotNull(container);
for(StructureElement childElement : container.getChildren()) {
if(childElement.getSourceRange().inclusiveContains(offset)) {
if(pickedElement == null) {
pickedElement = childElement;
} else if(pickedElement.getSourceRange().inclusiveContains(childElement.getSourceRange())) {
// childElement has a more specific source-range, so it's a better match
pickedElement = childElement;
}
}
visitContainer(childElement); // Check children
}
}
}
}