/*******************************************************************************
* 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 dtool.parser.structure;
import java.util.EnumSet;
import dtool.ast.declarations.DeclarationSpecialFunction;
import dtool.ast.definitions.DefUnit;
import dtool.ast.definitions.DefinitionAggregate;
import dtool.ast.definitions.DefinitionEnum;
import dtool.ast.definitions.DefinitionEnum.EnumBody;
import dtool.ast.definitions.DefinitionVariable;
import dtool.ast.definitions.EArcheType;
import dtool.ast.definitions.ITemplateParameter;
import dtool.engine.operations.DeeNamedElementLabelProvider.DeeNamedElementSimpleLabelProvider;
import dtool.parser.DeeParserResult.ParsedModule;
import melnorme.lang.tooling.EAttributeFlag;
import melnorme.lang.tooling.ElementAttributes;
import melnorme.lang.tooling.ElementLabelInfo;
import melnorme.lang.tooling.ast.ASTVisitor;
import melnorme.lang.tooling.ast.util.NodeList;
import melnorme.lang.tooling.ast_actual.ASTNode;
import melnorme.lang.tooling.engine.scoping.INonScopedContainer;
import melnorme.lang.tooling.structure.SourceFileStructure;
import melnorme.lang.tooling.structure.StructureElement;
import melnorme.lang.tooling.structure.StructureElementKind;
import melnorme.utilbox.collections.ArrayList2;
import melnorme.utilbox.collections.Indexable;
import melnorme.utilbox.misc.Location;
public class DeeStructureCreator extends ASTVisitor {
protected ArrayList2<StructureElement> elements;
public DeeStructureCreator() {
}
/**
* Create a {@link SourceFileStructure} from given parsedModule
* @param location optional parameter, can be null.
*/
public SourceFileStructure createStructure(ParsedModule parsedModule, Location location) {
Indexable<StructureElement> moduleChildren = collectChildElements(parsedModule.module);
return new SourceFileStructure(location, moduleChildren, parsedModule);
}
public Indexable<StructureElement> collectChildElements(ASTNode node) {
elements = new ArrayList2<>();
node.visitChildren(this);
Indexable<StructureElement> nodeChildren = elements;
elements = null;
return nodeChildren;
}
@Override
public boolean preVisit(ASTNode node) {
if(node instanceof DefUnit) {
DefUnit defUnit = (DefUnit) node;
return visit(defUnit);
}
if(node instanceof NodeList<?>) {
return true;
}
if(node instanceof INonScopedContainer) {
return true;
}
if(node instanceof EnumBody) {
return true;
}
if(node instanceof DeclarationSpecialFunction) {
return visit_DeclarationSpecialFunction((DeclarationSpecialFunction) node);
}
return false;
}
@Override
public void postVisit(ASTNode node) {
}
public void pushNewElement(StructureElement newStructureElement) {
elements.add(newStructureElement);
}
public boolean visit(DefUnit node) {
if(node.getArcheType() == EArcheType.Module) {
return true; // Ignore node, just go to children
}
if(node instanceof ITemplateParameter) {
return false; // Ignore all subtree
}
ElementLabelInfo labelInfo = new DeeLabelInfoProvider().getLabelInfo(node);
boolean hasStructuralChildren =
node instanceof DefinitionAggregate ||
node instanceof DefinitionEnum ||
node instanceof DefinitionVariable; // Review this, might change in the future
String nameLabel = new DeeNamedElementSimpleLabelProvider().getLabel(node);
pushNewElement(new StructureElement(
nameLabel,
node.getNameSourceRangeOrNull(),
node.getSourceRange(),
labelInfo.kind,
labelInfo.elementAttribs,
labelInfo.type,
hasStructuralChildren ? collectChildren(node) : null)
);
return false;
}
public static Indexable<StructureElement> collectChildren(ASTNode node) {
return new DeeStructureCreator().collectChildElements(node);
}
public boolean visit_DeclarationSpecialFunction(DeclarationSpecialFunction node) {
EnumSet<EAttributeFlag> flagsSet = ElementAttributes.newFlagsSet();
ElementAttributes elementAttribs = new ElementAttributes(null, flagsSet);
boolean hasStructuralChildren = true;
pushNewElement(new StructureElement(
node.kind.toStringAsCode(),
null,
node.getSourceRange(),
StructureElementKind.CONSTRUCTOR,
elementAttribs,
null,
hasStructuralChildren ? collectChildren(node) : null)
);
return false;
}
}