summaryrefslogtreecommitdiffstats
path: root/dcaedt_validator/kwalify/src/main/java/kwalify/PlainYamlParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'dcaedt_validator/kwalify/src/main/java/kwalify/PlainYamlParser.java')
-rw-r--r--dcaedt_validator/kwalify/src/main/java/kwalify/PlainYamlParser.java742
1 files changed, 742 insertions, 0 deletions
diff --git a/dcaedt_validator/kwalify/src/main/java/kwalify/PlainYamlParser.java b/dcaedt_validator/kwalify/src/main/java/kwalify/PlainYamlParser.java
new file mode 100644
index 0000000..5f23a19
--- /dev/null
+++ b/dcaedt_validator/kwalify/src/main/java/kwalify/PlainYamlParser.java
@@ -0,0 +1,742 @@
+/*
+ * copyright(c) 2005 kuwata-lab all rights reserved.
+ */
+
+package kwalify;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.regex.Matcher;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * plain yaml parser class which is a parent of YamlParser class.
+ */
+public class PlainYamlParser implements Parser {
+
+ private static final String ANCHOR = "anchor '";
+ private static final String ENDFLAG_EOF = "<EOF>";
+ private static final String ENDFLAG_DOC_BEGIN = "---";
+ private static final String ENDFLAG_DOC_END = "...";
+ private static final String REGEXP1 = "^( *)(.*)";
+ private static final String REGEXP2 = "^((?::?[-.\\w]+|'.*?'|\".*?\"|=|<<) *):(( +)(.*))?$";
+
+ public static class Alias {
+ private String label;
+ private int lineNum;
+
+ Alias(String label, int lineNum) {
+ this.label = label;
+ this.lineNum = lineNum;
+ }
+
+ String getLabel() { return label; }
+
+ int getLineNumber() { return lineNum; }
+ }
+
+
+ private String[] lines;
+ private String line = null;
+ private int linenum = 0;
+ private Map<String,Object> anchors = new HashMap<>();
+ private Map<String,Integer> aliases = new HashMap<>();
+ private String endFlag = null;
+ private String sbuf = null;
+ private int index = 0;
+
+ PlainYamlParser(String yamlStr) {
+ List list = Util.toListOfLines(yamlStr);
+ int len = list.size();
+ lines = new String[len + 1];
+ for (int i = 0; i < len; i++) {
+ lines[i + 1] = (String)list.get(i);
+ }
+ }
+
+ public Object parse() throws SyntaxException {
+ Object data = parseChild(0);
+ if (data == null && endFlag.equals(ENDFLAG_DOC_BEGIN)) {
+ data = parseChild(0);
+ }
+ if (aliases.size() > 0) {
+ resolveAliases(data);
+ }
+ return data;
+ }
+
+ public boolean hasNext() {
+ return !endFlag.equals(ENDFLAG_EOF);
+ }
+
+ private List createSequence() {
+ return new ArrayList();
+ }
+
+ private void addSequenceValue(List seq, Object value) {
+ seq.add(value);
+ }
+
+ private void setSequenceValueAt(List seq, int index, Object value) {
+ seq.set(index, value);
+ }
+
+ Map createMapping() {
+ return new DefaultableHashMap();
+ }
+
+ private void setMappingValueWith(Map map, Object key, Object value) {
+ map.put(key, value);
+ }
+
+ void setMappingDefault(Map map, Object value) {
+ if (map instanceof Defaultable) {
+ ((Defaultable)map).setDefault(value);
+ }
+ }
+
+ private void mergeMapping(Map map, Map map2) {
+ for (Object key : map2.keySet()) {
+ if (!map.containsKey(key)) {
+ Object value = map2.get(key);
+ map.put(key, value);
+ }
+ }
+ }
+
+ private void mergeList(Map map, List maplist) throws SyntaxException {
+ for (Object elem : maplist) {
+ mergeCollection(map, elem);
+ }
+ }
+
+ private void mergeCollection(Map map, Object collection) throws SyntaxException {
+ if (collection instanceof Map) {
+ mergeMapping(map, (Map)collection);
+ } else if (collection instanceof List) {
+ mergeList(map, (List)collection);
+ } else {
+ throw syntaxError("'<<' requires collection (mapping, or sequence of mapping).");
+ }
+ }
+
+ private Object createScalar(Object value) {
+ return value;
+ }
+
+ private String currentLine() {
+ return line;
+ }
+
+ int currentLineNumber() {
+ return linenum;
+ }
+
+ protected String getLine() {
+ String currentLine;
+ do {
+ currentLine = getCurrentLine();
+ } while (currentLine != null && Util.matches(currentLine, "^\\s*($|#)"));
+ return currentLine;
+ }
+
+ private String getCurrentLine() {
+ if (++linenum < lines.length) {
+ line = lines[linenum];
+ if (Util.matches(line, "^\\.\\.\\.$")) {
+ line = null;
+ endFlag = ENDFLAG_DOC_END;
+ } else if (Util.matches(line, "^---( [!%].*)?$")) {
+ line = null;
+ endFlag = ENDFLAG_DOC_BEGIN;
+ }
+ } else {
+ line = null;
+ endFlag = ENDFLAG_EOF;
+ }
+ return line;
+ }
+
+ private void resetBuffer(String str) {
+ sbuf = str.charAt(str.length() - 1) == '\n' ? str : str + "\n";
+ index = -1;
+ }
+
+ private int getCurrentCharacter() {
+ if (index + 1 < sbuf.length()) {
+ index++;
+ } else {
+ String currentLine = getLine();
+ if (currentLine == null) {
+ return -1;
+ }
+ resetBuffer(currentLine);
+ index++;
+ }
+ return sbuf.charAt(index);
+ }
+
+ private int getChar() {
+ int ch;
+ do {
+ ch = getCurrentCharacter();
+ } while (ch >= 0 && isWhite(ch));
+ return ch;
+ }
+
+ private int getCharOrNewline() {
+ int ch;
+ do {
+ ch = getCurrentCharacter();
+ } while (ch >= 0 && isWhite(ch) && ch != '\n');
+ return ch;
+ }
+
+ private int currentChar() {
+ return sbuf.charAt(index);
+ }
+
+ private SyntaxException syntaxError(String message, int linenum) {
+ return new YamlSyntaxException(message, linenum);
+ }
+
+ private SyntaxException syntaxError(String message) {
+ return new SyntaxException(message, linenum);
+ }
+
+ private Object parseChild(int column) throws SyntaxException {
+ String currentLine = getLine();
+ if (currentLine == null) {
+ return createScalar(null);
+ }
+ Matcher m = Util.matcher(currentLine, REGEXP1);
+ if (! m.find()) {
+ assert false;
+ return null;
+ }
+ int indent = m.group(1).length();
+ if (indent < column) {
+ return createScalar(null);
+ }
+ String value = m.group(2);
+ return parseValue(column, value, indent);
+ }
+
+ private Object parseValue(int column, String value, int valueStartColumn) throws SyntaxException {
+ Object data;
+ if (Util.matches(value, "^-( |$)")) {
+ data = parseSequence(valueStartColumn, value);
+ } else if (Util.matches(value, REGEXP2)) {
+ data = parseMapping(valueStartColumn, value);
+ } else if (Util.matches(value, "^[\\[\\{]")) {
+ data = parseFlowStyle(value);
+ } else if (Util.matches(value, "^\\&[-\\w]+( |$)")) {
+ data = parseAnchor(column, value);
+ } else if (Util.matches(value, "^\\*[-\\w]+( |$)")) {
+ data = parseAlias(value);
+ } else if (Util.matches(value, "^[|>]")) {
+ data = parseBlockText(column, value);
+ } else if (Util.matches(value, "^!")) {
+ data = parseTag(column, value);
+ } else if (Util.matches(value, "^\\#")) {
+ data = parseChild(column);
+ } else {
+ data = parseScalar(value);
+ }
+ return data;
+ }
+
+ private static boolean isWhite(int ch) {
+ return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r';
+ }
+
+
+ private Object parseFlowStyle(String value) throws SyntaxException {
+ resetBuffer(value);
+ getChar();
+ Object data = parseFlow(0);
+ int ch = currentChar();
+ assert ch == ']' || ch == '}';
+ ch = getCharOrNewline();
+ if (ch != '\n' && ch != '#' && ch >= 0) {
+ throw syntaxError("flow style sequence is closed buf got '" + ((char)ch) + "'.");
+ }
+ if (ch >= 0) {
+ getLine();
+ }
+ return data;
+ }
+
+ private Object parseFlow(int depth) throws SyntaxException {
+ int ch = currentChar();
+ if (ch < 0) {
+ throw syntaxError("found EOF when parsing flow style.");
+ }
+ Object data;
+ if (ch == '[') {
+ data = parseFlowSequence(depth);
+ } else if (ch == '{') {
+ data = parseFlowMapping(depth);
+ } else {
+ data = parseFlowScalar();
+ }
+ return data;
+ }
+
+ private List parseFlowSequence(int depth) throws SyntaxException {
+ assert currentChar() == '[';
+ List seq = createSequence();
+ int ch = getChar();
+ if (ch != '}') {
+ addSequenceValue(seq, parseFlowSequenceItem(depth + 1));
+ while ((ch = currentChar()) == ',') {
+ ch = getChar();
+ if (ch == '}') {
+ throw syntaxError("sequence item required (or last comma is extra).");
+ }
+ addSequenceValue(seq, parseFlowSequenceItem(depth + 1));
+ }
+ }
+ if (currentChar() != ']') {
+ throw syntaxError("flow style sequence requires ']'.");
+ }
+ if (depth > 0) {
+ getChar();
+ }
+ return seq;
+ }
+
+ private Object parseFlowSequenceItem(int depth) throws SyntaxException {
+ return parseFlow(depth);
+ }
+
+ private Map parseFlowMapping(int depth) throws SyntaxException {
+ assert currentChar() == '{';
+ Map map = createMapping();
+ int ch = getChar();
+ if (ch != '}') {
+ Object[] pair = parseFlowMappingItem(depth + 1);
+ Object key = pair[0];
+ Object value = pair[1];
+ setMappingValueWith(map, key, value);
+ while ((ch = currentChar()) == ',') {
+ ch = getChar();
+ if (ch == '}') {
+ throw syntaxError("mapping item required (or last comman is extra.");
+ }
+ pair = parseFlowMappingItem(depth + 1);
+ key = pair[0];
+ value = pair[1];
+ setMappingValueWith(map, key, value);
+ }
+ }
+ if (currentChar() != '}') {
+ throw syntaxError("flow style mapping requires '}'.");
+ }
+ if (depth > 0) {
+ getChar();
+ }
+ return map;
+ }
+
+ private Object[] parseFlowMappingItem(int depth) throws SyntaxException {
+ Object key = parseFlow(depth);
+ int ch = currentChar();
+ if (ch != ':') {
+ String s = ch >= 0 ? "'" + ((char)ch) + "'" : "EOF";
+ throw syntaxError("':' expected but got " + s);
+ }
+ getChar();
+ Object value = parseFlow(depth);
+ return new Object[] { key, value };
+ }
+
+ private Object parseFlowScalar() {
+ int ch = currentChar();
+ Object scalar;
+ StringBuilder sb = new StringBuilder();
+ if (ch == '"' || ch == '\'') {
+ int endch = ch;
+ while ((ch = getCurrentCharacter()) >= 0 && ch != endch) {
+ sb.append((char)ch);
+ }
+ getChar();
+ scalar = sb.toString();
+ } else {
+ sb.append((char)ch);
+ while ((ch = getCurrentCharacter()) >= 0 && ch != ':' && ch != ',' && ch != ']' && ch != '}') {
+ sb.append((char)ch);
+ }
+ scalar = toScalar(sb.toString().trim());
+ }
+ return createScalar(scalar);
+ }
+
+ private Object parseTag(int column, String value) throws SyntaxException {
+ assert Util.matches(value, "^!\\S+");
+ Matcher m = Util.matcher(value, "^!(\\S+)((\\s+)(.*))?$");
+ if (! m.find()) {
+ assert false;
+ return null;
+ }
+ String tag = m.group(1);
+ String space = m.group(3);
+ String value2 = m.group(4);
+ Object data;
+ if (value2 != null && value2.length() > 0) {
+ int valueStartColumn = column + 1 + tag.length() + space.length();
+ data = parseValue(column, value2, valueStartColumn);
+ } else {
+ data = parseChild(column);
+ }
+ return data;
+ }
+
+ private Object parseAnchor(int column, String value) throws SyntaxException {
+ assert Util.matches(value, "^\\&([-\\w]+)(( *)(.*))?$");
+ Matcher m = Util.matcher(value, "^\\&([-\\w]+)(( *)(.*))?$");
+ if (! m.find()) {
+ assert false;
+ return null;
+ }
+ String label = m.group(1);
+ String space = m.group(3);
+ String value2 = m.group(4);
+ Object data;
+ if (value2 != null && value2.length() > 0) {
+ int valueStartColumn = column + 1 + label.length() + space.length();
+ data = parseValue(column, value2, valueStartColumn);
+ } else {
+ data = parseChild(column);
+ }
+ registerAnchor(label, data);
+ return data;
+ }
+
+ private void registerAnchor(String label, Object data) throws SyntaxException {
+ if (anchors.containsKey(label)) {
+ throw syntaxError(ANCHOR + label + "' is already used.");
+ }
+ anchors.put(label, data);
+ }
+
+ private Object parseAlias(String value) throws SyntaxException {
+ assert value.matches("^\\*([-\\w]+)(( *)(.*))?$");
+ Matcher m = Util.matcher(value, "^\\*([-\\w]+)(( *)(.*))?$");
+ if (! m.find()) {
+ assert false;
+ return null;
+ }
+ String label = m.group(1);
+ String value2 = m.group(4);
+ if (value2 != null && value2.length() > 0 && value2.charAt(0) != '#') {
+ throw syntaxError("alias cannot take any data.");
+ }
+ Object data = anchors.get(label);
+ if (data == null) {
+ data = registerAlias(label);
+ }
+ getLine();
+ return data;
+ }
+
+ private Alias registerAlias(String label) {
+ aliases.merge(label, 1, (a, b) -> a + b);
+ return new Alias(label, linenum);
+ }
+
+
+ private void resolveAliases(Object data) throws SyntaxException {
+ Map resolved = new IdentityHashMap();
+ resolveAliases(data, resolved);
+ }
+
+
+ private void resolveAliases(Object data, Map resolved) throws SyntaxException {
+ if (resolved.containsKey(data)) {
+ return;
+ }
+ resolved.put(data, data);
+ if (data instanceof List) {
+ resolveAliases((List)data, resolved);
+ } else if (data instanceof Map) {
+ resolveAliases((Map)data, resolved);
+ } else {
+ assert !(data instanceof Alias);
+ }
+ if (data instanceof Defaultable) {
+ Object defaultValue = ((Defaultable)data).getDefault();
+ if (defaultValue != null) {
+ resolveAliases(defaultValue, resolved);
+ }
+ }
+ }
+
+ private void resolveAliases(List seq, Map resolved) throws SyntaxException {
+ int len = seq.size();
+ for (int i = 0; i < len; i++) {
+ Object val = seq.get(i);
+ if (val instanceof Alias) {
+ Alias alias = (Alias)val;
+ String label = alias.getLabel();
+ if (anchors.containsKey(label)) {
+ setSequenceValueAt(seq, i, anchors.get(label));
+ } else {
+ throw syntaxError(ANCHOR + alias.getLabel() + "' not found.");
+ }
+ } else if (val instanceof List || val instanceof Map) {
+ resolveAliases(val, resolved);
+ }
+ }
+ }
+
+ private void resolveAliases(Map map, Map resolved) throws SyntaxException {
+ for (Object key : map.keySet()) {
+ Object val = map.get(key);
+ if (val instanceof Alias) {
+ Alias alias = (Alias) val;
+ String label = alias.getLabel();
+ if (anchors.containsKey(label)) {
+ setMappingValueWith(map, key, anchors.get(label));
+ } else {
+ throw syntaxError(ANCHOR + alias.getLabel() + "' not found.", alias.getLineNumber());
+ }
+ } else if (val instanceof List || val instanceof Map) {
+ resolveAliases(val, resolved);
+ }
+ }
+ }
+
+ private Object parseBlockText(int column, String value) throws SyntaxException {
+ assert Util.matches(value, "^[>|]");
+ Matcher m = Util.matcher(value, "^([>|])([-+]?)(\\d*)\\s*(.*)$");
+ if (! m.find()) {
+ assert false;
+ return null;
+ }
+ char blockChar = m.group(1).length() > 0 ? m.group(1).charAt(0) : '\0';
+ char indicator = m.group(2).length() > 0 ? m.group(2).charAt(0) : '\0';
+ int indent = m.group(3).length() > 0 ? Integer.parseInt(m.group(3)) : -1;
+ String text = m.group(4);
+ char sep = blockChar == '|' ? '\n' : ' ';
+ String currentLine;
+ StringBuilder sb = new StringBuilder();
+ int n = 0;
+ while ((currentLine = getCurrentLine()) != null) {
+ m = Util.matcher(currentLine, "^( *)(.*)$");
+ m.find();
+ String space = m.group(1);
+ String str = m.group(2);
+ if (indent < 0) {
+ indent = space.length();
+ }
+ if (str.length() == 0) {
+ n++;
+ } else {
+ int slen = space.length();
+ if (slen < column) {
+ break;
+ } else if (slen < indent) {
+ throw syntaxError("invalid indent in block text.");
+ } else {
+ if (n > 0) {
+ if (blockChar == '>' && sb.length() > 0) {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+ for (int i = 0; i < n; i++) {
+ sb.append('\n');
+ }
+ n = 0;
+ }
+ str = currentLine.substring(indent);
+ }
+ }
+ sb.append(str);
+ if ((blockChar == '>') && (sb.charAt(sb.length() - 1) == '\n')) {
+ sb.setCharAt(sb.length() - 1, ' ');
+ }
+ }
+ if (currentLine != null && Util.matches(currentLine, "^ *#")) {
+ getLine();
+ }
+ switch (indicator) {
+ case '+':
+ handlePlus(blockChar, sb, n);
+ break;
+ case '-':
+ handleMinus(sep, sb);
+ break;
+ default:
+ if (blockChar == '>') {
+ sb.setCharAt(sb.length() - 1, '\n');
+ }
+ }
+ return createScalar(text + sb.toString());
+ }
+
+ private void handleMinus(char sep, StringBuilder sb) {
+ if (sb.charAt(sb.length() - 1) == sep) {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+ }
+
+ private void handlePlus(char blockChar, StringBuilder sb, int n) {
+ if (n > 0) {
+ if (blockChar == '>') {
+ sb.setCharAt(sb.length() - 1, '\n');
+ }
+ for (int i = 0; i < n; i++) {
+ sb.append('\n');
+ }
+ }
+ }
+
+
+ private List parseSequence(int column, String value) throws SyntaxException {
+ assert Util.matches(value, "^-(( +)(.*))?$");
+ List seq = createSequence();
+ while (true) {
+ Matcher m = Util.matcher(value, "^-(( +)(.*))?$");
+ if (! m.find()) {
+ throw syntaxError("sequence item is expected.");
+ }
+ String space = m.group(2);
+ String value2 = m.group(3);
+ int column2 = column + 1;
+
+ Object elem;
+ if (value2 == null || value2.length() == 0) {
+ elem = parseChild(column2);
+ } else {
+ int valueStartColumn = column2 + space.length();
+ elem = parseValue(column2, value2, valueStartColumn);
+ }
+ addSequenceValue(seq, elem);
+
+ String currentLine = currentLine();
+ if (currentLine == null) {
+ break;
+ }
+ Matcher m2 = Util.matcher(currentLine, REGEXP1);
+ m2.find();
+ int indent = m2.group(1).length();
+ if (indent < column) {
+ break;
+ } else if (indent > column) {
+ throw syntaxError("invalid indent of sequence.");
+ }
+ value = m2.group(2);
+ }
+ return seq;
+ }
+
+
+ private Map parseMapping(int column, String value) throws SyntaxException {
+ assert Util.matches(value, REGEXP2);
+ Map map = createMapping();
+ while (true) {
+ Matcher m = Util.matcher(value, REGEXP2);
+ if (! m.find()) {
+ throw syntaxError("mapping item is expected.");
+ }
+ String v = m.group(1).trim();
+ Object key = toScalar(v);
+ String value2 = m.group(4);
+ int column2 = column + 1;
+
+ Object elem;
+ if (value2 == null || value2.length() == 0) {
+ elem = parseChild(column2);
+ } else {
+ int valueStartColumn = column2 + m.group(1).length() + m.group(3).length();
+ elem = parseValue(column2, value2, valueStartColumn);
+ }
+ if ("=".equals(v)) {
+ setMappingDefault(map, elem);
+ } else if ("<<".equals(v)) {
+ mergeCollection(map, elem);
+ } else {
+ setMappingValueWith(map, key, elem);
+ }
+
+ String currentLine = currentLine();
+ if (currentLine == null) {
+ break;
+ }
+ Matcher m2 = Util.matcher(currentLine, REGEXP1);
+ m2.find();
+ int indent = m2.group(1).length();
+ if (indent < column) {
+ break;
+ } else if (indent > column) {
+ throw syntaxError("invalid indent of mapping.");
+ }
+ value = m2.group(2);
+ }
+ return map;
+ }
+
+
+ private Object parseScalar(String value) {
+ Object data = createScalar(toScalar(value));
+ getLine();
+ return data;
+ }
+
+
+ private Object toScalar(String value) {
+ Matcher m;
+ if ((m = Util.matcher(value, "^\"(.*)\"([ \t]*#.*$)?")).find()) {
+ return m.group(1);
+ } else if ((m = Util.matcher(value, "^'(.*)'([ \t]*#.*$)?")).find()) {
+ return m.group(1);
+ } else if ((m = Util.matcher(value, "^(.*\\S)[ \t]*#")).find()) {
+ value = m.group(1);
+ }
+
+ if (Util.matches(value, "^-?0x\\d+$")) {
+ return Integer.parseInt(value, 16);
+ } else if (Util.matches(value, "^-?0\\d+$")) {
+ return Integer.parseInt(value, 8);
+ } else if (Util.matches(value, "^-?\\d+$")) {
+ return Integer.parseInt(value, 10);
+ } else if (Util.matches(value, "^-?\\d+\\.\\d+$")) {
+ return Double.parseDouble(value);
+ } else if (Util.matches(value, "^(true|yes|on)$")) {
+ return Boolean.TRUE;
+ } else if (Util.matches(value, "^(false|no|off)$")) {
+ return Boolean.FALSE;
+ } else if (Util.matches(value, "^(null|~)$")){
+ return null;
+ } else if (Util.matches(value, "^:(\\w+)$")) {
+ return value;
+ } else if ((m = Util.matcher(value, "^(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)$")).find()) {
+ int year = Integer.parseInt(m.group(1));
+ int month = Integer.parseInt(m.group(2));
+ int day = Integer.parseInt(m.group(3));
+ Calendar cal = Calendar.getInstance();
+ cal.set(year, month, day, 0, 0, 0);
+ return cal.getTime();
+ } else if ((m = Util.matcher(value, "^(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)(?:[Tt]|[ \t]+)(\\d\\d?):(\\d\\d):(\\d\\d)(\\.\\d*)?(?:Z|[ \t]*([-+]\\d\\d?)(?::(\\d\\d))?)?$")).find()) {
+ int year = Integer.parseInt(m.group(1));
+ int month = Integer.parseInt(m.group(2));
+ int day = Integer.parseInt(m.group(3));
+ int hour = Integer.parseInt(m.group(4));
+ int min = Integer.parseInt(m.group(5));
+ int sec = Integer.parseInt(m.group(6));
+
+ String timezone = "GMT" + m.group(8) + ":" + m.group(9);
+ Calendar cal = Calendar.getInstance();
+ cal.set(year, month, day, hour, min, sec);
+ cal.setTimeZone(TimeZone.getTimeZone(timezone));
+ return cal.getTime();
+ } else {
+ return value;
+ }
+ }
+
+}