diff --git a/Helpers.jrag b/Helpers.jrag index 8c1ff5650a1619fb604a7f96de82ca32e858ffa4..41287726d4e900a0ef096abee83f679daf74808c 100644 --- a/Helpers.jrag +++ b/Helpers.jrag @@ -1,20 +1,76 @@ aspect Helpers { + // --- of --- public static ValueElement ValueElement.of(int value) { - return new ValueElement(String.valueOf(value)); + return new ValueElement(false, String.valueOf(value)); } public static ValueElement ValueElement.of(boolean value) { - return new ValueElement(String.valueOf(value)); + return new ValueElement(false, String.valueOf(value)); } public static ValueElement ValueElement.of(String value) { - return new ValueElement(value); + return new ValueElement(false, value); } public static StringElement StringElement.of(String value) { - return new StringElement(value); + return new StringElement(false, value); } + + // --- addKeyValuePair --- public void MappingElement.addKeyValuePair(String key, Element value) { addKeyValuePair(new KeyValuePair(key, value)); } + // --- put --- + public MappingElement MappingElement.put(String key, int value) { + addKeyValuePair(key, ValueElement.of(value)); + return this; + } + public MappingElement MappingElement.put(String key, boolean value) { + addKeyValuePair(key, ValueElement.of(value)); + return this; + } + public MappingElement MappingElement.put(String key, String value) { + addKeyValuePair(key, makeStringElement(value)); + return this; + } + public MappingElement MappingElement.put(String key, Element inner) { + addKeyValuePair(key, inner); + return this; + } + + // --- add --- + public ListElement ListElement.add(int value) { + addElement(ValueElement.of(value)); + return this; + } + public ListElement ListElement.add(boolean value) { + addElement(ValueElement.of(value)); + return this; + } + public ListElement ListElement.add(String value) { + addElement(makeStringElement(value)); + return this; + } + public ListElement ListElement.add(Element inner) { + addElement(inner); + return this; + } + + // --- helper methods for put/add --- + protected SimpleElement ComplexElement.makeStringElement(String value) { + // simple test, check for special characters + return containsAny(value, "[{\"\n") ? + StringElement.of(value.replace("\n", "\\n").replace("\"", "\\\"")) : + ValueElement.of(value); + } + + protected boolean ComplexElement.containsAny(String s, String searchChars) { + // from https://stackoverflow.com/a/54399334/2493208 + java.util.Set<Character> charsToTestFor = searchChars.chars() + .mapToObj(ch -> Character.valueOf((char) ch)) + .collect(java.util.stream.Collectors.toSet()); + return s.chars().anyMatch(ch -> charsToTestFor.contains(Character.valueOf((char) ch))); + } + + // --- getValue --- public java.util.Optional<Element> MappingElement.getValue(String key) { for (KeyValuePair pair : getKeyValuePairList()) { if (pair.getKey().equals(key)) { diff --git a/Mustache.relast b/Mustache.relast index 4ffd34a97eba31b5978c93d0faaccf3327f4bde7..581dcdf509d2bb0757a8545e72a297d8a05fab69 100644 --- a/Mustache.relast +++ b/Mustache.relast @@ -1,5 +1,5 @@ Document ::= <FileName> [RootElement:ComplexElement] ; -abstract Element ; +abstract Element ::= <Collapse:boolean> ; abstract ComplexElement : Element ; MappingElement : ComplexElement ::= KeyValuePair* ; KeyValuePair ::= <Key> Value:Element ; diff --git a/Printing.jrag b/Printing.jrag index 2b93aa2b87162bef2766b5d5e263d774a86cf06c..39deaadb67827a56e3f25af6f09017aa79cb621f 100644 --- a/Printing.jrag +++ b/Printing.jrag @@ -1,14 +1,25 @@ aspect Printing { String ASTNode.PRINT_INDENT = " "; + // --- isLast --- inh boolean KeyValuePair.isLast(); inh boolean Element.isLast(); eq MappingElement.getKeyValuePair(int i).isLast() = i == getNumKeyValuePair() - 1; eq ListElement.getElement(int i).isLast() = i == getNumElement() - 1; eq Document.getRootElement().isLast() = true; + + // --- needTrailingNewLine --- syn boolean KeyValuePair.needTrailingNewLine() = !this.isLast(); syn boolean Element.needTrailingNewLine() = !this.isLast() || containingListElement() == null; + // --- isCollapsed --- + inh boolean Element.isCollapsed(); + inh boolean KeyValuePair.isCollapsed(); + eq Document.getRootElement().isCollapsed() = getRootElement().getCollapse(); + eq MappingElement.getKeyValuePair(int i).isCollapsed() = isCollapsed(); + eq ListElement.getElement(int i).isCollapsed() = getElement(i).getCollapse() || isCollapsed(); + eq KeyValuePair.getValue().isCollapsed() = getValue().getCollapse() || isCollapsed(); + public String Document.prettyPrint() { return prettyPrint(true); } @@ -46,11 +57,22 @@ aspect Printing { if (isEmpty()) { sb.append("[]"); } else { - for (Element element : getElementList()) { - sb.append(indent).append("- "); - element.prettyPrint(sb, false, indent + PRINT_INDENT); - if (element.needTrailingNewLine()) { - sb.append("\n"); + if (isCollapsed()) { + sb.append("["); + for (Element element : getElementList()) { + element.prettyPrint(sb, false, indent); + if (!element.isLast()) { + sb.append(", "); + } + } + sb.append("]"); + } else { + for (Element element : getElementList()) { + sb.append(indent).append("- "); + element.prettyPrint(sb, false, indent + PRINT_INDENT); + if (element.needTrailingNewLine()) { + sb.append("\n"); + } } } } @@ -59,8 +81,15 @@ aspect Printing { protected StringBuilder KeyValuePair.prettyPrint(StringBuilder sb, boolean printIndent, String indent) { if (printIndent) sb.append(indent); - sb.append(getKey()).append(":"); - if (getValue().isComplexElement() && !getValue().isEmpty()) { + if (isCollapsed()) { + sb.append("\""); + } + sb.append(getKey()); + if (isCollapsed()) { + sb.append("\""); + } + sb.append(":"); + if (getValue().isComplexElement() && !getValue().isEmpty() && !getValue().isCollapsed()) { sb.append("\n"); getValue().prettyPrint(sb, true, indent + PRINT_INDENT); } else { @@ -75,13 +104,24 @@ aspect Printing { if (isEmpty()) { sb.append("{}"); } else { - boolean first = true; - for (KeyValuePair pair : getKeyValuePairList()) { - if (!first || printIndent) sb.append(indent); - first = false; - pair.prettyPrint(sb, false, indent); - if (pair.needTrailingNewLine()) { - sb.append("\n"); + if (isCollapsed()) { + sb.append("{"); + for (KeyValuePair pair : getKeyValuePairList()) { + pair.prettyPrint(sb, false, indent); + if (!pair.isLast()) { + sb.append(", "); + } + } + sb.append("}"); + } else { + boolean first = true; + for (KeyValuePair pair : getKeyValuePairList()) { + if (!first || printIndent) sb.append(indent); + first = false; + pair.prettyPrint(sb, false, indent); + if (pair.needTrailingNewLine()) { + sb.append("\n"); + } } } }