org.modelcc.io.java.checker.CycleChecker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ModelCC Show documentation
Show all versions of ModelCC Show documentation
ModelCC is a model-based parser generator (a.k.a. compiler compiler) that decouples language specification from language processing, avoiding some of the problems caused by grammar-driven parser generators. ModelCC receives a conceptual model as input, along with constraints that annotate it. It is then able to create a parser for the desired textual language and the generated parser fully automates the instantiation of the language conceptual model. ModelCC also includes a built-in reference resolution mechanism that results in abstract syntax graphs, rather than mere abstract syntax trees.
The newest version!
package org.modelcc.io.java.checker;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import org.modelcc.io.java.JavaModelReader;
import org.modelcc.io.java.JavaModelChecker;
import org.modelcc.io.java.JavaLanguageMetadata;
import org.modelcc.language.metamodel.SimpleLanguageElement;
import org.modelcc.language.metamodel.MemberCollection;
import org.modelcc.language.metamodel.CompositeLanguageElement;
import org.modelcc.language.metamodel.LanguageElement;
import org.modelcc.language.metamodel.LanguageMember;
import org.modelcc.lexer.recognizer.PatternRecognizer;
/**
* Cycle checker
*/
public class CycleChecker extends JavaModelChecker
{
public CycleChecker (JavaModelReader reader)
{
super(reader);
}
@Override
public void check(JavaLanguageMetadata metadata)
{
for (LanguageElement e: metadata.elements) {
checkCycle(e,e,metadata.classToElement,metadata.subclasses);
}
}
private boolean acceptsEmptyString (List list)
{
if (list!=null) {
for (PatternRecognizer p: list) {
if (p.read("") == null) {
return false;
}
}
}
return true;
}
private void checkCycle(LanguageElement es, LanguageElement orig,
Map classToElement,
Map> subclasses)
{
if (!acceptsEmptyString(es.getPrefix()))
return;
if (!acceptsEmptyString(es.getSuffix()))
return;
if (SimpleLanguageElement.class.isAssignableFrom(es.getClass())) {
return;
} else if (CompositeLanguageElement.class.isAssignableFrom(es.getClass())) {
checkComplexModelElement( (CompositeLanguageElement)es, orig, classToElement, subclasses);
} else {
checkAbstractModelElement( es, orig, classToElement, subclasses);
}
}
private void checkComplexModelElement(
CompositeLanguageElement ces, LanguageElement orig,
Map classToElement,
Map> subclasses)
{
for (int i = 0; i < ces.getMembers().size();i++) {
LanguageMember em = ces.getMembers().get(i);
if (!em.isOptional()) {
LanguageElement emca = classToElement.get(em.getElementClass());
if (!acceptsEmptyString(emca.getPrefix()))
return;
if (!acceptsEmptyString(emca.getSuffix()))
return;
if (!acceptsEmptyString(em.getPrefix()))
return;
if (!acceptsEmptyString(em.getSuffix()))
return;
if (MemberCollection.class.isAssignableFrom(em.getClass())) {
MemberCollection mem = (MemberCollection)em;
if (mem.getMinimumMultiplicity()>0) {
if (!acceptsEmptyString(em.getSeparator()))
return;
}
}
}
}
boolean hasOtherThanOrig = false;
boolean hasOrig = false;
for (int i = 0;i < ces.getMembers().size();i++) {
LanguageMember em = ces.getMembers().get(i);
LanguageElement emm = classToElement.get(em.getElementClass());
if (!em.isOptional()) {
if (emm.equals(orig)) {
if (singleton(em))
hasOrig = true;
if (!acceptsEmptyString(emm.getPrefix()))
hasOtherThanOrig = true;
if (!acceptsEmptyString(emm.getSuffix()))
hasOtherThanOrig = true;
} else {
hasOtherThanOrig = true;
}
}
}
if (hasOrig && !hasOtherThanOrig)
log(Level.SEVERE, "Class \"{0}\" cycles with recursive inheritance or composition.", new Object[]{orig.getElementClass().getCanonicalName()});
if (hasOrig && !hasOtherThanOrig) {
for (int i = 0;i < ces.getMembers().size();i++) {
LanguageMember em = ces.getMembers().get(i);
LanguageElement emm = classToElement.get(em.getElementClass());
if (!em.isOptional() && !emm.equals(orig)) {
checkCycle(emm,orig,classToElement,subclasses);
}
}
}
}
private boolean singleton(LanguageMember em)
{
boolean onlyOne = true;
if ((MemberCollection.class.isAssignableFrom(em.getClass()))) {
MemberCollection mem = (MemberCollection)em;
if (mem.getMinimumMultiplicity()>1)
onlyOne = false;
}
return onlyOne;
}
private void checkAbstractModelElement(
LanguageElement ces, LanguageElement orig,
Map classToElement,
Map> subclasses)
{
if (subclasses.containsKey(ces)) {
boolean hasOtherThanOrig = false;
boolean hasOrig = false;
for (LanguageElement me: subclasses.get(ces)) {
if (me.equals(orig)) {
hasOrig = true;
if (!acceptsEmptyString(me.getPrefix()))
hasOtherThanOrig = true;
if (!acceptsEmptyString(me.getSuffix()))
hasOtherThanOrig = true;
} else {
hasOtherThanOrig = true;
}
checkCycle(me,orig,classToElement,subclasses);
}
if (hasOrig && !hasOtherThanOrig) {
log(Level.SEVERE, "Class \"{0}\" cycles with recursive inheritance or composition.", new Object[]{orig.getElementClass().getCanonicalName()});
}
}
}
}