/*******************************************************************************
* Copyright (c) 2013 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.ast;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertFail;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import melnorme.lang.tooling.ast.util.ASTDirectChildrenVisitor;
import melnorme.lang.tooling.ast_actual.ASTNode;
import melnorme.lang.tooling.common.ParserError;
public abstract class NodeData {
public abstract boolean isParsedStatus();
public abstract Collection<ParserError> getNodeErrors();
public boolean hasErrors() {
return getNodeErrors().size() > 0;
}
public abstract boolean isSemanticReadyStatus();
public abstract void setSemanticReady(CommonLanguageElement node);
public static CreatedStatusNodeData CREATED_STATUS = new CreatedStatusNodeData() {
@Override
public String toString() {
return "(CREATED)";
}
};
public static class CreatedStatusNodeData extends NodeData {
@Override
public boolean isParsedStatus() {
return false;
}
@Override
public boolean isSemanticReadyStatus() {
return false;
};
@Override
public Collection<ParserError> getNodeErrors() {
throw assertFail();
}
public void setParsed(ASTNode node) {
setParsedWithErrors(node, (ParserError[]) null);
}
public void setParsedWithErrors(final ASTNode node, ParserError... errors) {
// Ensure children are also in parsed status
node.visitDirectChildren(new ASTDirectChildrenVisitor() {
@Override
protected void geneticChildrenVisit(ASTNode child) {
assertTrue(child.getLexicalParent() == node);
assertTrue(child.isParsedStatus());
}
});
if(errors == null) {
node.setData(NodeData.DEFAULT_PARSED_STATUS);
} else {
node.setData(new ParsedNodeDataWithErrors(errors));
}
assertTrue(node.hasSourceRangeInfo());
}
@Override
public void setSemanticReady(CommonLanguageElement node) {
node.setData(DEFAULT_LOCALLY_ANALYZED_STATUS);
}
}
public static NodeData DEFAULT_PARSED_STATUS = new ParsedNodeData();
public static class ParsedNodeData extends NodeData {
protected static final Collection<ParserError> NO_ERRORS = Collections.emptyList();
@Override
public boolean isParsedStatus() {
return true;
}
@Override
public boolean isSemanticReadyStatus() {
return false;
}
@Override
public Collection<ParserError> getNodeErrors() {
return NO_ERRORS;
};
@Override
public String toString() {
return "(PARSED)";
}
@Override
public void setSemanticReady(CommonLanguageElement node) {
if(this == DEFAULT_PARSED_STATUS) {
// Reuse instance to avoid unnecessary allocations
node.setData(DEFAULT_LOCALLY_ANALYZED_STATUS);
} else {
node.setData(new AnalysedNodeData(this));
}
}
}
public static class ParsedNodeDataWithErrors extends ParsedNodeData {
protected Collection<ParserError> errors;
public ParsedNodeDataWithErrors(ParserError... errors) {
for (ParserError parserError : errors) {
assertNotNull(parserError);
}
this.errors = Arrays.asList(errors);
}
@Override
public Collection<ParserError> getNodeErrors() {
return errors;
};
}
public static NodeData DEFAULT_LOCALLY_ANALYZED_STATUS = new AnalysedNodeData(DEFAULT_PARSED_STATUS);
public static class AnalysedNodeData extends NodeData {
protected NodeData parsedStatus;
public AnalysedNodeData(NodeData parsedStatus) {
this.parsedStatus = assertNotNull(parsedStatus);
}
@Override
public boolean isParsedStatus() {
return false;
}
@Override
public boolean isSemanticReadyStatus() {
return true;
}
@Override
public Collection<ParserError> getNodeErrors() {
return parsedStatus.getNodeErrors();
}
@Override
public String toString() {
return "(ANALYSED)";
}
@Override
public void setSemanticReady(CommonLanguageElement node) {
// Do nothing
assertTrue(node.getData() == this);
}
}
/* ----------------- util ----------------- */
public static final class CompleteNodeVisitor extends ASTVisitor {
public static final CompleteNodeVisitor instance = new CompleteNodeVisitor();
@Override
public boolean preVisit(ASTNode node) {
return true;
}
@Override
public void postVisit(ASTNode node) {
node.setSemanticReady_afterChildren();
}
}
}