/**
* Copyright (C) 2010 Lowereast Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mattinsler.guiceymongo.data.generator.parser;
import com.mattinsler.guiceymongo.data.generator.TypeRegistry;
import com.mattinsler.guiceymongo.data.generator.option.Option;
import com.mattinsler.guiceymongo.data.generator.property.*;
import com.mattinsler.guiceymongo.data.generator.type.*;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;
import java.util.LinkedList;
import java.util.List;
public class TypeParser {
private static final String OPTION_IDENTITY = "identity";
private final boolean _useCamelCaseKeys;
private final TypeRegistry _typeRegistry;
private final boolean _isQuiet;
public TypeParser(TypeRegistry typeRegistry, boolean useCamelCaseKeys, boolean isQuiet) {
_useCamelCaseKeys = useCamelCaseKeys;
_typeRegistry = typeRegistry;
_isQuiet = isQuiet;
}
private Object parseLiteral(Tree tree) {
try {
String text = tree.getText();
if (text.startsWith("'") && text.endsWith("'"))
return text.substring(1, text.length() - 1);
if (text.contains("."))
return Float.parseFloat(text);
return Integer.parseInt(text);
} catch (Exception e) {
throw new RuntimeException("Could not parse literal", e);
}
}
private Option parseOptionTree(CommonTree tree) {
assert GuiceyDataParser.OPTION == tree.getToken().getType();
List<CommonTree> children = tree.getChildren();
Option option = new Option(children.get(0).getText());
if (children.size() == 2 && GuiceyDataParser.PAIR != children.get(1).getToken().getType())
option.addParameter("value", parseLiteral(children.get(1)));
else {
for (int x = 1; x < children.size(); ++x) {
if (GuiceyDataParser.PAIR == children.get(x).getToken().getType() && children.get(x).getChildCount() == 2)
option.addParameter(children.get(x).getChild(0).getText(), parseLiteral(children.get(x).getChild(1)));
}
}
return option;
}
private String parseCommentTree(CommonTree tree) {
assert GuiceyDataParser.COMMENT == tree.getToken().getType();
List<CommonTree> children = tree.getChildren();
StringBuilder commentBuilder = new StringBuilder();
for (CommonTree child : children) {
commentBuilder.append(child.getText()).append(' ');
}
return commentBuilder.toString();
}
private Type parseType(UserDataType scopingType, List<CommonTree> typeArguments) {
switch (typeArguments.remove(0).getToken().getType()) {
case GuiceyDataParser.TYPE_PRIMITIVE:
String typeName = typeArguments.remove(0).getText();
Type type = _typeRegistry.getScopedGuiceyType(scopingType, typeName);
if (type == null)
throw new RuntimeException("Could not find type " + typeName);
return type;
case GuiceyDataParser.TYPE_LIST:
return new ListType(parseType(scopingType, typeArguments));
case GuiceyDataParser.TYPE_SET:
return new SetType(parseType(scopingType, typeArguments));
case GuiceyDataParser.TYPE_MAP:
Type keyType = parseType(scopingType, typeArguments);
Type valueType = parseType(scopingType, typeArguments);
return new MapType(keyType, valueType);
}
throw new RuntimeException("The parser might have messed up or there's a type here I didn't account for (which is my mess up)");
}
private void parsePropertyTree(CommonTree tree, UserDataType type) {
assert GuiceyDataParser.PROPERTY == tree.getToken().getType();
List<CommonTree> children = tree.getChildren();
String propertyName = children.get(0).getText();
children = children.subList(1, children.size());
Type propertyType = parseType(type, children);
List<Option> options = new LinkedList<Option>();
String comment = null;
for (CommonTree child : children) {
switch (child.getToken().getType()) {
case GuiceyDataParser.COMMENT:
comment = parseCommentTree(child);
break;
case GuiceyDataParser.OPTION:
options.add(parseOptionTree(child));
break;
}
}
Property<?> property;
if (propertyType instanceof PrimitiveType) {
property = new PrimitiveProperty(type, propertyName, (PrimitiveType)propertyType, comment, _useCamelCaseKeys);
} else if (propertyType instanceof BlobType) {
property = new BlobProperty(type, propertyName, (BlobType)propertyType, comment, _useCamelCaseKeys);
} else if (propertyType instanceof UserEnumType) {
property = new UserEnumProperty(type, propertyName, (UserEnumType)propertyType, comment, _useCamelCaseKeys);
} else if (propertyType instanceof UserDataType) {
property = new UserDataProperty(type, propertyName, (UserDataType)propertyType, comment, _useCamelCaseKeys);
} else if (propertyType instanceof ListType) {
property = new ListProperty(type, propertyName, (ListType)propertyType, comment, _useCamelCaseKeys);
} else if (propertyType instanceof SetType) {
property = new SetProperty(type, propertyName, (SetType)propertyType, comment, _useCamelCaseKeys);
} else if (propertyType instanceof MapType) {
property = new MapProperty(type, propertyName, (MapType)propertyType, comment, _useCamelCaseKeys);
} else {
throw new RuntimeException("Shouldn't happen");
}
type.addProperty(property);
for (Option option : options) {
if (option.getName().equals(TypeParser.OPTION_IDENTITY)) {
// TODO validation...?
type.setIdentityProperty(property);
}
property.addOption(option);
}
}
private void parseDataTree(CommonTree tree, UserDataType parentType) {
assert GuiceyDataParser.DATA == tree.getToken().getType();
List<CommonTree> children = tree.getChildren();
UserDataType type = _typeRegistry.getGuiceyType((parentType == null ? "" : parentType.getGuiceyType() + ".") + children.remove(0).getText());
for (CommonTree child : children) {
switch (child.getToken().getType()) {
case GuiceyDataParser.DATA:
parseDataTree(child, type);
break;
case GuiceyDataParser.ENUM:
parseEnumTree(child, type);
break;
case GuiceyDataParser.PROPERTY:
parsePropertyTree(child, type);
break;
case GuiceyDataParser.COMMENT:
type.setComment(parseCommentTree(child));
break;
}
}
}
private void parseEnumTree(CommonTree tree, UserDataType parentType) {
assert GuiceyDataParser.ENUM == tree.getToken().getType();
List<CommonTree> children = tree.getChildren();
UserEnumType type = _typeRegistry.getGuiceyType((parentType == null ? "" : parentType.getGuiceyType() + ".") + children.remove(0).getText());
for (CommonTree child : children) {
switch (child.getToken().getType()) {
case GuiceyDataParser.COMMENT:
type.setComment(parseCommentTree(child));
break;
default:
type.addValue(child.getText());
break;
}
}
}
private void registerAllUserTypes(CommonTree tree, UserDataType parentType) {
try {
Type type = null;
if (tree.getToken() != null) {
if (GuiceyDataParser.DATA == tree.getToken().getType() && tree.getChildCount() > 0) {
type = new UserDataType(tree.getChild(0).getText());
if (parentType != null)
parentType.addChildType((UserDataType)type);
} else if (GuiceyDataParser.ENUM == tree.getToken().getType() && tree.getChildCount() > 0) {
type = new UserEnumType(tree.getChild(0).getText());
if (parentType != null)
parentType.addChildType((UserEnumType)type);
}
if (type != null)
_typeRegistry.addType(type);
}
if (tree.getChildCount() > 0) {
for (CommonTree child : (List<CommonTree>)tree.getChildren()) {
if (type instanceof UserDataType)
registerAllUserTypes(child, (UserDataType)type);
else
registerAllUserTypes(child, null);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void parse(CommonTree tree) {
if (tree == null)
return;
registerAllUserTypes(tree, null);
if (!_isQuiet) {
for (UserDataType type : _typeRegistry.getTypes(UserDataType.class))
System.out.println(type.getJavaType());
}
for (CommonTree typeTree : (List<CommonTree>)tree.getChildren()) {
if (GuiceyDataParser.EOF != typeTree.getToken().getType()) {
switch (typeTree.getToken().getType()) {
case GuiceyDataParser.DATA:
parseDataTree(typeTree, null);
break;
case GuiceyDataParser.ENUM:
parseEnumTree(typeTree, null);
break;
}
}
}
}
}