org.modelcc.io.java.JavaLanguageReader 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!
/*
* ModelCC, distributed under ModelCC Shared Software License, www.modelcc.org
*/
package org.modelcc.io.java;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import org.modelcc.*;
import org.modelcc.io.java.checker.*;
import org.modelcc.io.java.processor.*;
import org.modelcc.io.java.visitor.*;
import org.modelcc.language.metamodel.*;
import org.modelcc.lexer.recognizer.PatternRecognizer;
import org.modelcc.metamodel.*;
/**
* Java model reader
*
* @author Luis Quesada ([email protected]) & Fernando Berzal ([email protected])
*/
public class JavaLanguageReader extends JavaModelReader
{
/**
* Constructor
* @param root the root class
*/
public JavaLanguageReader(Class root)
{
super(root);
}
/**
* Create specific instance of JavaModelReaderMetadata
* @return Reader metadata
*/
@Override
public JavaLanguageMetadata createMetadata ()
{
return new JavaLanguageMetadata();
}
/**
* Process JavaModelReader metadata
* @param metadata Metadata obtained through reflection
* @return The resulting ModelCC model
* @throws Exception
*/
@Override
public LanguageModel createModel(JavaLanguageMetadata metadata) throws Exception
{
preProcessModel(metadata);
for (JavaLanguageClass java: metadata.getJavaElements()) {
LanguageElement element = createElement(metadata, java);
metadata.elements.add(element);
metadata.javaElementToElement.put( java, element);
metadata.classToElement.put(element.getElementClass(), element);
}
postProcessModel(metadata);
return new LanguageModel(metadata.elements,metadata.start,metadata.delimiters,metadata.precedences,metadata.subclasses,metadata.superclasses,metadata.classToElement,metadata.defaultElement);
}
// Model preprocessing
private void preProcessModel(JavaLanguageMetadata metadata)
{
// Priorities
(new PriorityProcessor(this)).process(metadata);
// Inherit members.
(new MemberInheritanceProcessor(this)).process(metadata);
// Recursively manage attribute inheritance
(new AttributeInheritanceProcessor(this)).process(metadata);
// Convert priority values to precedences.
(new PriorityToPrecedenceConverter(this)).process(metadata);
// Check precedences for any cycles
(new PrecedenceChecker(this)).check(metadata);
// Check optional members
(new OptionalChecker(this)).check(metadata);
// Check references
(new ReferenceChecker(this)).check(metadata);
}
// Model postprocessing
private void postProcessModel(JavaLanguageMetadata metadata)
{
// Process metadata
(new PrecedenceProcessor(this)).process(metadata);
(new SubclassProcessor(this)).process(metadata);
(new SuperclassProcessor(this)).process(metadata);
(new PositionProcessor(this)).process(metadata);
(new DefaultElementProcessor(this)).process(metadata);
// Check for cycles
(new CycleChecker(this)).check(metadata);
metadata.start = metadata.classToElement.get(root);
}
@Override
protected void preProcessClass (Class type, JavaLanguageMetadata metadata, JavaLanguageClass element)
throws Exception
{
JavaModelVisitor visitor;
// @Value
visitor = new ValueVisitor(this);
visitor.visitFields(type,element);
// @Probability
// visitor = new ProbabilityVisitor(this);
// visitor.visit(type,element);
// @Pattern
visitor = new PatternVisitor(this,metadata);
visitor.visit(type,element);
// @Setup
visitor = new SetupVisitor(this);
visitor.visitMethods(type,element);
// @Constraint
visitor = new ConstraintVisitor(this);
visitor.visitMethods(type,element);
}
@Override
protected void postProcessClass(Class type, JavaLanguageMetadata metadata, JavaLanguageClass element)
throws Exception
{
JavaModelVisitor visitor;
// @FreeOrder
visitor = new FreeOrderVisitor(this);
visitor.visit(type,element);
// @Associativity
visitor = new AssociativityVisitor(this);
visitor.visit(type,element);
// @Composition
visitor = new CompositionVisitor(this);
visitor.visit(type,element);
// @Prefix
visitor = new PrefixVisitor(this,metadata);
visitor.visit(type,element);
// @Prefix
visitor = new SuffixVisitor(this,metadata);
visitor.visit(type,element);
// @Separator
visitor = new SeparatorVisitor(this,metadata);
visitor.visit(type,element);
}
@Override
protected LanguageMember createFieldElement (Field field,Class elementClass,JavaLanguageMetadata metadata)
{
MemberCollectionType collection = null;
Class contentClass;
// Collection
if (List.class.isAssignableFrom(field.getType())) {
collection = MemberCollectionType.LIST;
} else if (Set.class.isAssignableFrom(field.getType())) {
collection = MemberCollectionType.SET;
} else if (Map.class.isAssignableFrom(field.getType())) {
return null;
} else if (field.getType().isArray()) {
collection = MemberCollectionType.ARRAY;
}
contentClass = Reflection.getType(collection,field);
if (!metadata.getRelevantClasses().contains(contentClass)) {
if (field.isAnnotationPresent(ID.class) || field.isAnnotationPresent(Multiplicity.class) || field.isAnnotationPresent(Optional.class) || field.isAnnotationPresent(Prefix.class) || field.isAnnotationPresent(Suffix.class) || field.isAnnotationPresent(Separator.class) || field.isAnnotationPresent(Reference.class)) {
log(Level.SEVERE, "In field \"{0}\" of class \"{1}\": Field class does not implement IModel but has ModelCC annotations.", new Object[]{field.getName(), elementClass.getCanonicalName()});
}
return null;
}
LanguageMember member;
if (collection == null)
member = new LanguageMember(field.getName(),contentClass);
else
member = new MemberCollection(field.getName(),contentClass,collection);
// Annotation visitors
JavaModelVisitor visitor;
visitor = new OptionalVisitor(this);
visitor.visit(field,member);
visitor = new IDVisitor(this);
visitor.visit(field,member);
visitor = new ReferenceVisitor(this);
visitor.visit(field,member);
visitor = new PrefixVisitor(this,metadata);
visitor.visit(field,member);
visitor = new SuffixVisitor(this,metadata);
visitor.visit(field,member);
visitor = new SeparatorVisitor(this,metadata);
visitor.visit(field,member);
visitor = new MultiplicityVisitor(this);
visitor.visit(field,member);
// visitor = new ProbabilityVisitor(this);
// visitor.visit(field,member);
return member;
}
/**
* Process new element member
*/
@Override
protected void processField (JavaLanguageClass element, LanguageMember lm)
{
if (lm.isKey())
element.addKeyMember(lm);
}
/**
* Create Java element
*/
@Override
protected JavaLanguageClass createClassElement (Class type)
{
return new JavaLanguageClass(type);
}
/**
* Create ModelCC model element from Java element
*/
protected LanguageElement createElement (JavaLanguageMetadata metadata, JavaLanguageClass pe)
{
LanguageElement e;
Class elementClass;
List contents;
List ids;
boolean freeOrder;
AssociativityType associativity;
CompositionType composition;
List prefix;
List suffix;
List separator;
PatternRecognizer pattern;
Field valueField;
Method setupMethod;
elementClass = pe.getElementClass();
contents = pe.getMembers();
ids = pe.getKeyMembers();
Evaluator evaluator;
if (pe.isFreeOrder() != null)
freeOrder = pe.isFreeOrder();
else
freeOrder = false;
if (pe.getAssociativity() == null)
associativity = AssociativityType.UNDEFINED;
else
associativity = pe.getAssociativity();
if (pe.getComposition() == null)
composition = CompositionType.UNDEFINED;
else
composition = pe.getComposition();
if (pe.getPrefix()==null)
prefix = null;
else
prefix = pe.getPrefix();
if (pe.getSuffix()==null)
suffix = null;
else
suffix = pe.getSuffix();
if (pe.getSeparator()==null)
separator = null;
else
separator = pe.getSeparator();
pattern = pe.getPattern();
valueField = pe.getValueField();
setupMethod = pe.getSetupMethod();
evaluator = pe.getEvaluator();
String valueFieldName = null;
if (valueField != null)
valueFieldName = valueField.getName();
String setupMethodName = null;
if (setupMethod != null)
setupMethodName = setupMethod.getName();
List constraintMethodNames = new ArrayList();
for (int i = 0;i < pe.getConstraintMethods().size();i++) {
constraintMethodNames.add(pe.getConstraintMethods().get(i).getName());
}
e = null;
if (Modifier.isAbstract(elementClass.getModifiers()) && metadata.getJavaSubclasses(pe) == null) {
e = new LanguageElement(elementClass,associativity,prefix,suffix,separator,setupMethodName,constraintMethodNames,evaluator);
log(Level.SEVERE, "In class \"{0}\": Abstract class without subclasses.", new Object[]{elementClass.getCanonicalName()});
} else if (pe.getMembers().isEmpty() && metadata.getJavaSubclasses(pe) != null) {
e = new LanguageElement(elementClass,associativity,prefix,suffix,separator,setupMethodName,constraintMethodNames,evaluator);
} else if (pe.getPattern() != null) {
if (!Reflection.hasConstructor(elementClass))
log(Level.SEVERE, "In class \"{0}\": Elements containing @Pattern or @Value need to implement a public parameterless constructor.", new Object[]{elementClass.getCanonicalName()});
e = new SimpleLanguageElement(elementClass,associativity,prefix,suffix,separator,setupMethodName,constraintMethodNames,pattern,valueFieldName,evaluator);
} else {
e = new CompositeLanguageElement(elementClass,associativity,prefix,suffix,separator,setupMethodName,constraintMethodNames,contents,ids,freeOrder,composition,evaluator);
if (Reflection.hasAnnotation(elementClass,Pattern.class)) {
contents = new ArrayList();
}
if (!Reflection.hasConstructor(elementClass))
log(Level.SEVERE, "In class \"{0}\": Composite elements need to implement a public parameterless constructor.", new Object[]{elementClass.getCanonicalName()});
if (contents.isEmpty() && !Reflection.hasAnnotation(elementClass,Pattern.class) && metadata.getJavaSubclasses(pe) == null)
log(Level.SEVERE, "In class \"{0}\": Empty composite element.", new Object[]{elementClass.getCanonicalName()});
}
return e;
}
}