net.jangaroo.exml.as.ConfigClassBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of exml-compiler Show documentation
Show all versions of exml-compiler Show documentation
parses an EXML and generates an AS config class
package net.jangaroo.exml.as;
import net.jangaroo.exml.model.ConfigAttribute;
import net.jangaroo.exml.model.ConfigClass;
import net.jangaroo.exml.model.ConfigClassType;
import net.jangaroo.utils.AS3Type;
import net.jangaroo.jooc.CompilerError;
import net.jangaroo.jooc.JooSymbol;
import net.jangaroo.jooc.ast.Annotation;
import net.jangaroo.jooc.ast.AnnotationParameter;
import net.jangaroo.jooc.ast.AstNode;
import net.jangaroo.jooc.ast.AstVisitorBase;
import net.jangaroo.jooc.ast.ClassBody;
import net.jangaroo.jooc.ast.ClassDeclaration;
import net.jangaroo.jooc.ast.CommaSeparatedList;
import net.jangaroo.jooc.ast.CompilationUnit;
import net.jangaroo.jooc.ast.FunctionDeclaration;
import net.jangaroo.jooc.ast.Ide;
import net.jangaroo.jooc.ast.PackageDeclaration;
import net.jangaroo.jooc.ast.TypeRelation;
import net.jangaroo.jooc.sym;
import java.io.IOException;
public class ConfigClassBuilder extends AstVisitorBase {
private static final String EXT_CONFIG_META_NAME = "ExtConfig";
private static final String TARGET_ANNOTATION_PARAMETER_NAME = "target";
private static final String COMMENT_START = "/*";
private static final String COMMENT_END = "*/";
private static final String LINE_COMMENT_START = "//";
private static final String ASDOC_COMMENT_START = "/**";
private ConfigClass configClass;
private CompilationUnit compilationUnit;
public ConfigClassBuilder(CompilationUnit compilationUnit) {
this.compilationUnit = compilationUnit;
}
public ConfigClass buildConfigClass() {
try {
compilationUnit.visit(this);
} catch (IOException e) {
throw new IllegalStateException("should not happen, because the ConfigClassBuilder does not do I/O", e);
}
return configClass.getComponentClassName() == null ? null : configClass;
}
@Override
public void visitCompilationUnit(CompilationUnit compilationUnit) throws IOException {
configClass = new ConfigClass();
compilationUnit.getPackageDeclaration().visit(this);
compilationUnit.getPrimaryDeclaration().visit(this);
}
@Override
public void visitPackageDeclaration(PackageDeclaration packageDeclaration) throws IOException {
String packageName = packageDeclaration.getQualifiedNameStr();
configClass.setPackageName(packageName);
}
@Override
public void visitClassDeclaration(ClassDeclaration classDeclaration) throws IOException {
for (Annotation annotation : classDeclaration.getAnnotations()) {
annotation.visit(this);
}
String name = classDeclaration.getName();
configClass.setName(name);
ClassDeclaration superTypeDeclaration = classDeclaration.getSuperTypeDeclaration();
//Ignore superclass if its object or null
String superClassName = superTypeDeclaration == null ? null : "Object".equals(superTypeDeclaration.getQualifiedNameStr()) ? null : superTypeDeclaration.getQualifiedNameStr();
configClass.setSuperClassName(superClassName);
String description = parseDescription(classDeclaration.getSymClass(), classDeclaration.getSymModifiers());
if (description != null && description.trim().length() > 0) {
configClass.setDescription(description);
}
classDeclaration.getBody().visit(this);
}
@Override
public void visitClassBody(ClassBody classBody) throws IOException {
for (AstNode node : classBody.getDirectives()) {
node.visit(new ClassBodyVisitor());
}
}
@Override
public void visitAnnotation(Annotation annotation) {
detectAsDoc(annotation);
detectExtConfigAnnotation(annotation);
}
private void detectAsDoc(Annotation annotation) {
if (configClass.getDescription() == null) {
String description = parseDescription(annotation.getLeftBracket(), new JooSymbol[0]);
configClass.setDescription(description);
}
}
private void detectExtConfigAnnotation(Annotation annotation) {
if (EXT_CONFIG_META_NAME.equals(annotation.getMetaName())) {
if (configClass.getComponentClassName() != null) {
throw new CompilerError(annotation.getSymbol(), "Only one [" + EXT_CONFIG_META_NAME + "] annotation may be given.");
}
CommaSeparatedList annotationParameters = annotation.getOptAnnotationParameters();
while (annotationParameters != null) {
AnnotationParameter annotationParameter = annotationParameters.getHead();
Ide optNameIde = annotationParameter.getOptName();
if (optNameIde != null) {
String parameterName = optNameIde.getName();
AstNode annotationParameterValue = annotationParameter.getValue();
String parameterValue = null;
if (annotationParameterValue != null) {
JooSymbol symbol = annotationParameterValue.getSymbol();
if (symbol.sym != sym.STRING_LITERAL) {
throw new CompilerError(symbol, "The " + parameterName + " parameter of an [" + EXT_CONFIG_META_NAME + "] annotation must be a string literal.");
}
parameterValue = (String) symbol.getJooValue();
}
if (TARGET_ANNOTATION_PARAMETER_NAME.equals(parameterName)) {
if (parameterValue == null) {
throw new CompilerError(optNameIde.getSymbol(), "The " + parameterName + " parameter of an [" + EXT_CONFIG_META_NAME + "] annotation must have a value.");
}
configClass.setComponentClassName(parameterValue);
} else {
try {
configClass.setType(ConfigClassType.fromExtConfigAttribute(parameterName));
} catch (IllegalArgumentException e) {
throw new CompilerError(optNameIde.getSymbol(), "'" + parameterName + "' is not a valid parameter of an [" + EXT_CONFIG_META_NAME + "] annotation (only 'xtype', 'ptype', 'type', 'gctype' are allowed).", e);
}
configClass.setTypeValue(parameterValue);
}
}
annotationParameters = annotationParameters.getTail();
}
if (configClass.getComponentClassName() == null) {
throw new CompilerError(annotation.getSymbol(), "A " + TARGET_ANNOTATION_PARAMETER_NAME + " parameter must be provided for an [" + EXT_CONFIG_META_NAME + "] annotation.");
}
if (configClass.getType() == null) {
configClass.setType(ConfigClassType.CLASS);
}
}
}
private class ClassBodyVisitor extends AstVisitorBase {
@Override
public void visitFunctionDeclaration(FunctionDeclaration functionDeclaration) throws IOException {
if (functionDeclaration.isGetter() && !functionDeclaration.isStatic()) {
String name = functionDeclaration.getName();
String type = parseTypeDeclaration(functionDeclaration);
String description = parseDescription(functionDeclaration.getSymbol(), functionDeclaration.getSymModifiers());
configClass.addCfg(new ConfigAttribute(name, type, description));
}
}
private String parseTypeDeclaration(FunctionDeclaration functionDeclaration) {
TypeRelation optTypeRelation = functionDeclaration.getFun().getOptTypeRelation();
String type;
if (optTypeRelation != null) {
type = optTypeRelation.getType().getIde().getQualifiedNameStr();
} else {
type = AS3Type.ANY.toString();
}
return type;
}
}
public static String parseDescription(JooSymbol symbol, JooSymbol[] symModifiers) {
JooSymbol firstSymbol = symbol;
if (symModifiers.length > 0) {
firstSymbol = symModifiers[0];
}
String whitespace = firstSymbol.getWhitespace();
int pos = 0;
String lastAsDocComment = null;
while (true) {
int commentStart = whitespace.indexOf(COMMENT_START, pos);
int lineCommentStart = whitespace.indexOf(LINE_COMMENT_START, pos);
if (commentStart < 0) {
break;
}
if (lineCommentStart >= 0 && lineCommentStart < commentStart) {
pos = findLineCommentEnd(whitespace, lineCommentStart) + 1;
} else {
int endPos = findCommentEndPos(whitespace, commentStart);
if (whitespace.substring(commentStart).startsWith(ASDOC_COMMENT_START)) {
String comment = whitespace.substring(commentStart + ASDOC_COMMENT_START.length(), endPos);
lastAsDocComment = parseAsDocComment(comment);
}
pos = endPos + COMMENT_END.length();
}
}
return lastAsDocComment;
}
public static int findCommentEndPos(String whitespace, int commentStart) {
int endPos = whitespace.indexOf(COMMENT_END, commentStart + COMMENT_START.length());
if (endPos < 0) {
throw new IllegalStateException("unterminated comment found; this should be detected by the lexer");
}
return endPos;
}
public static int findLineCommentEnd(String whitespace, int lineCommentStart) {
int returnPos = whitespace.indexOf('\r', lineCommentStart);
int lineFeedPos = whitespace.indexOf('\n', lineCommentStart);
int endPos = returnPos < 0 ? lineFeedPos : lineFeedPos < 0 ? returnPos : Math.min(returnPos, lineFeedPos);
if (endPos < 0) {
throw new IllegalStateException("unterminated line comment found; this should be detected by the lexer");
}
return endPos;
}
public static String parseAsDocComment(String comment) {
String lastAsDocComment = comment.replaceAll("\\s*[\\r\\n]\\s*\\*[ \\t\u000B\\f]*", " ");
lastAsDocComment = lastAsDocComment.replaceAll("\\s+", " ");
lastAsDocComment = lastAsDocComment.trim();
return lastAsDocComment;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy