package alien4cloud.tosca.parser;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ArrayUtils;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.ScalarNode;
import org.yaml.snakeyaml.nodes.SequenceNode;
import alien4cloud.exception.InvalidArgumentException;
import alien4cloud.tosca.parser.impl.ErrorCode;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* Utility class to help with parsing.
*/
public final class ParserUtils {
/**
* Utility to get a scalar.
*
* @param node The node from which to get a scalar value.
* @param context The parsing execution context in which to add errors in which to add errors in case the node is not a scalar node.
* @return The Scalar value or null if the node is not a scalar node.
*/
public static String getScalar(Node node, ParsingContextExecution context) {
if (node instanceof ScalarNode) {
return ((ScalarNode) node).getValue().trim();
}
addTypeError(node, context.getParsingErrors(), "scalar");
return null;
}
/**
* Build a map while parsing a {@link MappingNode} assuming that all tuples are scalars (both key and value). Other entries are ignored but warned.
*
* @param ignoredKeys ignore these keys (no warning for them !)
*/
public static Map<String, String> parseStringMap(MappingNode mappingNode, ParsingContextExecution context, String... ignoredKeys) {
Map<String, String> result = Maps.newHashMap();
List<NodeTuple> mappingNodeValues = mappingNode.getValue();
for (NodeTuple entry : mappingNodeValues) {
if (!(entry.getKeyNode() instanceof ScalarNode)) {
ParsingError err = new ParsingError(ParsingErrorLevel.WARNING, ErrorCode.UNRECOGNIZED_PROPERTY, "Parsing a MappingNode as a Map", entry
.getKeyNode().getStartMark(), "The key of this tuple should be a scalar", entry.getKeyNode().getEndMark(), "");
context.getParsingErrors().add(err);
continue;
}
if (!(entry.getValueNode() instanceof ScalarNode)) {
if (!ArrayUtils.contains(ignoredKeys, getScalar(entry.getKeyNode(), context))) {
ParsingError err = new ParsingError(ParsingErrorLevel.WARNING, ErrorCode.UNRECOGNIZED_PROPERTY, "Parsing a MappingNode as a Map", entry
.getKeyNode().getStartMark(), "The value of this tuple should be a scalar", entry.getValueNode().getEndMark(),
((ScalarNode) entry.getKeyNode()).getValue());
context.getParsingErrors().add(err);
}
continue;
}
// ok both key and value are scalar
String k = ((ScalarNode) entry.getKeyNode()).getValue();
String v = ((ScalarNode) entry.getValueNode()).getValue();
result.put(k, v);
}
return result;
}
public static Object parse(Node node) {
if (node == null) {
return null;
} else if (node instanceof ScalarNode) {
return ((ScalarNode) node).getValue();
} else if (node instanceof SequenceNode) {
return parseSequence((SequenceNode) node);
} else if (node instanceof MappingNode) {
return parseMap((MappingNode) node);
} else {
throw new InvalidArgumentException("Unknown type of node " + node.getClass().getName());
}
}
public static List<Object> parseSequence(SequenceNode sequenceNode) {
List<Object> result = Lists.newArrayList();
for (Node node : sequenceNode.getValue()) {
result.add(parse(node));
}
return result;
}
public static Map<String, Object> parseMap(MappingNode mappingNode) {
Map<String, Object> result = Maps.newHashMap();
for (NodeTuple entry : mappingNode.getValue()) {
String key = ((ScalarNode) entry.getKeyNode()).getValue();
result.put(key, parse(entry.getValueNode()));
}
return result;
}
/**
* Add an invalid type {@link ParsingError} to the given parsing errors list.
*
* @param node The node that is causing the type error.
* @param parsingErrors The parsing errors in which to add the error.
* @param expectedType The type that was actually expected.
*/
public static void addTypeError(Node node, List<ParsingError> parsingErrors, String expectedType) {
parsingErrors.add(new ParsingError(ErrorCode.SYNTAX_ERROR, "Invalid type syntax", node.getStartMark(), "Expected the type to match tosca type", node
.getEndMark(), expectedType));
}
}