Explorar o código

grammar: refactoring, generated grammar moved into commons
new: ArraySet
WIP: ColorUtils2

Ranides Atterwim %!s(int64=2) %!d(string=hai) anos
pai
achega
22a06b6e1c
Modificáronse 46 ficheiros con 1130 adicións e 582 borrados
  1. 21 0
      assira.commons/pom.xml
  2. 49 0
      assira.commons/src/main/antlr4/imports/Primitives.g4
  3. 65 0
      assira.commons/src/main/antlr4/net/ranides/grammars/generated/CssColors.g4
  4. 5 91
      assira.commons/src/main/java/net/ranides/assira/awt/ColorUtils.java
  5. 76 0
      assira.commons/src/main/java/net/ranides/assira/awt/ColorUtils2.java
  6. 1 1
      assira.commons/src/main/java/net/ranides/assira/grammar/G4Node.java
  7. 6 3
      assira.grammar/src/main/java/net/ranides/assira/grammar/G4Parser.java
  8. 8 2
      assira.grammar/src/main/java/net/ranides/assira/grammar/G4Selector.java
  9. 15 1
      assira.grammar/src/main/java/net/ranides/assira/grammar/G4SelectorBuilder.java
  10. 0 0
      assira.commons/src/main/java/net/ranides/assira/grammar/G4Support.java
  11. 6 6
      assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/NodeAbstract.java
  12. 2 2
      assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/NodeForRule.java
  13. 1 1
      assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/NodeForTerm.java
  14. 1 1
      assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/NodeForToken.java
  15. 1 1
      assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/NodeSupport.java
  16. 207 0
      assira.commons/src/main/java/net/ranides/assira/grammar/impl/ParserGenerated.java
  17. 2 2
      assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/RootAbstract.java
  18. 1 1
      assira.commons/src/main/java/net/ranides/assira/grammar/properties/G4NodeProperties.java
  19. 0 0
      assira.commons/src/main/java/net/ranides/assira/grammar/properties/G4NodeProperty.java
  20. 99 0
      assira.commons/src/test/java/net/ranides/assira/awt/ColorUtils2Test.java
  21. 9 5
      assira.commons/src/test/java/net/ranides/assira/awt/ColorUtilsTest.java
  22. 20 0
      assira.commons/src/test/resources/grammars/CssColors.paths.txt
  23. 20 0
      assira.commons/src/test/resources/grammars/CssColors.tree.txt
  24. 224 0
      assira.core/src/main/java/net/ranides/assira/collection/sets/ArraySet.java
  25. 31 0
      assira.core/src/test/java/net/ranides/assira/collection/sets/ArraySetTest.java
  26. 8 6
      assira.core8/src/main/java/net/ranides/assira/trace/FStackWalker8.java
  27. 1 23
      assira.grammar/pom.xml
  28. 32 8
      assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/ParserInterpreted.java
  29. 72 0
      assira.grammar-tool/src/test/java/net/ranides/assira/grammar/InspectionTest.java
  30. 67 0
      assira.grammar-tool/src/test/java/net/ranides/assira/grammar/LabelTest.java
  31. 2 2
      assira.grammar/src/test/java/net/ranides/assira/grammar/G4NodeTest.java
  32. 56 5
      assira.grammar/src/test/java/net/ranides/assira/grammar/G4SelectorTest.java
  33. 2 2
      assira.grammar/src/test/resources/Calculator.g4
  34. 0 0
      assira.grammar-tool/src/test/resources/Calculator.paths.txt
  35. 1 1
      assira.grammar/src/test/resources/Calculator.tree.txt
  36. 0 0
      assira.grammar-tool/src/test/resources/LabelTest.g4
  37. 0 0
      assira.grammar-tool/src/test/resources/SkipTest.g4
  38. 0 65
      assira.grammar/src/main/antlr4/net/ranides/grammars/CssColors.g4
  39. 0 101
      assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/ParserGenerated.java
  40. 0 123
      assira.grammar/src/test/java/net/ranides/assira/grammar/G4ParserTest.java
  41. 0 94
      assira.grammar/src/test/java/net/ranides/assira/grammars/CssColorsTest.java
  42. 0 15
      assira.grammar/src/test/resources/CssColors.paths.txt
  43. 0 15
      assira.grammar/src/test/resources/CssColors.tree.txt
  44. 4 3
      assira.xls/src/main/java/net/ranides/assira/xls/XLSReader.java
  45. 2 1
      assira.xls/src/main/java/net/ranides/assira/xls/XLSUtils.java
  46. 13 1
      pom.xml

+ 21 - 0
assira.commons/pom.xml

@@ -21,6 +21,23 @@
         <maven.compiler.target>1.8</maven.compiler.target>
         <maven.compiler.target>1.8</maven.compiler.target>
     </properties>
     </properties>
 
 
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.antlr</groupId>
+                <artifactId>antlr4-maven-plugin</artifactId>
+                <version>${antlr.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>antlr4</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
     <dependencies>
     <dependencies>
         <dependency>
         <dependency>
             <groupId>net.ranides</groupId>
             <groupId>net.ranides</groupId>
@@ -60,6 +77,10 @@
             <type>jar</type>
             <type>jar</type>
             <optional>true</optional>
             <optional>true</optional>
         </dependency>
         </dependency>
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>antlr4-runtime</artifactId>
+        </dependency>
 
 
         <dependency>
         <dependency>
             <groupId>junit</groupId>
             <groupId>junit</groupId>

+ 49 - 0
assira.commons/src/main/antlr4/imports/Primitives.g4

@@ -0,0 +1,49 @@
+grammar Primitives;
+
+number
+    : numberInt
+    | numberPct
+    | numberReal
+    | numberHex
+    ;
+
+numberInt  : NUMBER_INT;
+numberPct  : NUMBER_PCT;
+numberReal : NUMBER_REAL;
+numberHex  : NUMBER_HEX;
+
+codeHex
+    : CODE_HEX3     #codeHex3
+    | CODE_HEX4     #codeHex4
+    | CODE_HEX6     #codeHex6
+    | CODE_HEX8     #codeHex8
+    ;
+
+LP   : '(' CHAR_WS*;
+LB   : '[' CHAR_WS*;
+LT   : '<' CHAR_WS*;
+RP   : CHAR_WS* ')';
+RB   : CHAR_WS* ']';
+GT   : CHAR_WS* '>';
+
+CS    : CHAR_WS* ',' CHAR_WS*;
+DOT   : CHAR_WS* '.' CHAR_WS*;
+WS    : CHAR_WS+;
+
+NUMBER_INT   : DIGIT+;
+NUMBER_PCT   : DIGIT+ ('.' DIGIT+)? '%';
+NUMBER_REAL  : DIGIT+ '.' DIGIT+ ('e' '-'? DIGIT+)?;
+NUMBER_HEX   : '0x' DIGIT_HEX+ ;
+CODE_HEX8 : CHAR_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX;
+CODE_HEX6 : CHAR_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX;
+CODE_HEX4 : CHAR_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX;
+CODE_HEX3 : CHAR_HEX DIGIT_HEX DIGIT_HEX DIGIT_HEX;
+
+
+fragment CHAR_HEX : '#';
+fragment DIGIT : [0-9] ;
+fragment DIGIT_NZ : [1-9] ;
+fragment DIGIT_Z : '0' ;
+fragment DIGIT_HEX: [0-9a-fA-F] ;
+
+fragment CHAR_WS: [ \t\r\n,?!.;]+;

+ 65 - 0
assira.commons/src/main/antlr4/net/ranides/grammars/generated/CssColors.g4

@@ -0,0 +1,65 @@
+grammar CssColors;
+
+import Primitives;
+
+colors
+    : color (WS color)+ EOF    #color_list
+    ;
+
+color1
+    : color EOF
+    ;
+
+color
+    : colorHSL      #color_hsl
+    | colorHSLA     #color_hsla
+    | colorRGB      #color_rgb
+    | colorRGBA     #color_rgba
+    | colorHEX      #color_hex
+    ;
+
+colorHSL
+    : PREFIX_HSL LP h=componentHue CS s=componentSaturation CS l=componentLightness RP
+    ;
+
+colorHSLA
+    : (PREFIX_HSL|PREFIX_HSLA) LP h=componentHue CS s=componentSaturation CS l=componentLightness CS alpha=componentAlpha RP
+    ;
+
+colorRGB
+    : (PREFIX_RGB|PREFIX_RGBA) LP r=componentRGB CS g=componentRGB CS b=componentRGB RP
+    ;
+
+colorRGBA
+    : PREFIX_RGBA LP r=componentRGB CS g=componentRGB CS b=componentRGB CS alpha=componentAlpha RP
+    ;
+
+colorHEX
+    : codeHex
+    ;
+
+componentHue
+    : numberInt
+    ;
+
+componentSaturation
+    : numberPct
+    ;
+
+componentLightness
+    : numberPct
+    ;
+
+componentRGB
+    : numberInt
+    ;
+
+componentAlpha
+    : numberReal
+    | numberInt
+    ;
+
+PREFIX_RGB   : 'rgb'  CHAR_WS*;
+PREFIX_RGBA  : 'rgba' CHAR_WS*;
+PREFIX_HSL   : 'hsl'  CHAR_WS*;
+PREFIX_HSLA  : 'hsla' CHAR_WS*;

+ 5 - 91
assira.commons/src/main/java/net/ranides/assira/awt/ColorUtils.java

@@ -13,6 +13,7 @@ import net.ranides.assira.math.MathUtils;
 import java.awt.*;
 import java.awt.*;
 import java.awt.color.ColorSpace;
 import java.awt.color.ColorSpace;
 import java.util.Locale;
 import java.util.Locale;
+import java.util.NoSuchElementException;
 import java.util.regex.Matcher;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.Pattern;
 
 
@@ -98,25 +99,6 @@ public final class ColorUtils {
         }
         }
     }
     }
 
 
-    /**
-     * Converts string into Color. Supported formats:
-     * hex integer: rrggbb / rgb
-     * CSS2: #rrggbb / #rgb
-     * CSS3: rgb(), hsl()
-     *
-     * @param value input
-     * @return color
-     */
-    public static Color parse(String value) {
-        if(6 == value.length() && value.matches("[0-9a-fA-F]{6}")) {
-            return fromHex6(value);
-        }
-        if(3 == value.length() && value.matches("[0-9a-fA-F]{3}")) {
-            return fromHex3(value);
-        }
-        return fromCSS(value);
-    }
-
     /**
     /**
      * Converts string into Color. Supported formats:
      * Converts string into Color. Supported formats:
      * CSS2: #rrggbb / #rgb
      * CSS2: #rrggbb / #rgb
@@ -126,79 +108,11 @@ public final class ColorUtils {
      * @return color
      * @return color
      */
      */
     public static Color fromCSS(String value) {
     public static Color fromCSS(String value) {
-        if(7 == value.length() && value.startsWith("#")) {
-            // NOPMD
-            return fromHex6(value.substring(1));
-        }
-        if(4 == value.length() && value.startsWith("#")) {
-            // NOPMD
-            return fromHex3(value.substring(1));
-        }
-        if(value.startsWith("rgb")) {
-            Matcher hit = RE_RGBA.matcher(value);
-            if(hit.matches()) {
-                return fromRGBA(hit);
-            }                    
-        }
-        if(value.startsWith("hsl")) {
-            Matcher hit = RE_HSLA.matcher(value);
-            if(hit.matches()) {
-                return fromHSLA(hit);
-            }
-        }
-        throw new IllegalArgumentException("Invalid color: " + value);
-    }
-
-
-    private static Color fromHex6(String value) { // NOPMD
-        return new Color(Integer.parseInt(value,16));
-    }
-
-    private static Color fromHex3(String value) { // NOPMD
-        int r = 17*ord(value.charAt(0));
-        int g = 17*ord(value.charAt(1));
-        int b = 17*ord(value.charAt(2));
-        return new Color(r,g,b);
-
-    }
-    
-    private static Color fromRGBA(Matcher hit) { // NOPMD
-        int r = Integer.parseInt(hit.group(1));
-        int g = Integer.parseInt(hit.group(2));
-        int b = Integer.parseInt(hit.group(3));
-        
-        if(null !=hit.group(4)) {
-            int a = MathUtils.round(255 * Double.parseDouble(hit.group(4)), 0, 255);
-            return new Color(r,g,b,a);
-        } else {
-            return new Color(r,g,b);
-        }
-    }
-    
-    private static Color fromHSLA(Matcher hit) { // NOPMD
-        float h = Float.parseFloat(hit.group(1)) / 360.0f;
-        float s = Float.parseFloat(hit.group(2)) / 100.0f;
-        float v = Float.parseFloat(hit.group(3)) / 100.0f;
-        
-        if(null !=hit.group(4)) {
-            int a = MathUtils.round(255 * Double.parseDouble(hit.group(4)), 0, 255);
-            return alpha(Color.getHSBColor(h,s,v), a);
-        } else {
-            return Color.getHSBColor(h,s,v);
-        }
-    }
-
-    private static int ord(char c) {
-        if( c>='0' && c<='9') {
-            return (c-'0');
-        }
-        if( c>='a' && c<='z') {
-            return 10+(c-'a');
-        }
-        if( c>='A' && c<='Z') {
-            return 10+(c-'A');
+        try {
+            return ColorUtils2.parse(value);
+        } catch (NoSuchElementException e) {
+            throw new IllegalArgumentException("Invalid color: " + value);
         }
         }
-        throw new IllegalArgumentException("Invalid digit: " + c);
     }
     }
 
 
     /**
     /**

+ 76 - 0
assira.commons/src/main/java/net/ranides/assira/awt/ColorUtils2.java

@@ -0,0 +1,76 @@
+package net.ranides.assira.awt;
+
+import net.ranides.assira.collection.query.CQuery;
+import net.ranides.assira.grammar.G4Parser;
+import net.ranides.assira.grammar.G4Selector;
+import net.ranides.assira.grammar.G4SelectorBuilder;
+import net.ranides.assira.math.MathUtils;
+import net.ranides.assira.text.StringUtils;
+import net.ranides.grammars.generated.CssColorsLexer;
+import net.ranides.grammars.generated.CssColorsParser;
+
+import java.awt.*;
+
+// @todo finish ColorUtils2
+public class ColorUtils2 {
+
+    private static final G4Parser PARSER = G4Parser.newInstance(CssColorsLexer.class, CssColorsParser.class);
+
+    private static final G4Selector<Color> SELECTOR = new G4SelectorBuilder<Color>()
+        .withName("CSS2:color")
+        .withParser(PARSER)
+        .mapRule(CssColorsParser.ColorRGBContext.class, node -> {
+            int r = Integer.parseInt(node.r.getText());
+            int g = Integer.parseInt(node.g.getText());
+            int b = Integer.parseInt(node.b.getText());
+
+            return new Color(r, g, b);
+        })
+        .mapRule("colorRGBA", node -> {
+            int r = Integer.parseInt(node.child("@r").text());
+            int g = Integer.parseInt(node.child("@g").text());
+            int b = Integer.parseInt(node.child("@b").text());
+            int alpha = Math.round(255 * Float.parseFloat(node.child("@alpha").text()));
+
+            return new Color(r, g, b, alpha);
+        })
+        .mapRule("colorHSL", node -> {
+            float h = Integer.parseInt(node.child("@h").text()) / 360.0f;
+            float s = Float.parseFloat(StringUtils.substr(node.child("@s").text(), 0, -1)) / 100.0f;
+            float v = Float.parseFloat(StringUtils.substr(node.child("@l").text(), 0, -1)) / 100.0f;
+
+            return Color.getHSBColor(h,s,v);
+        })
+        .mapRule("colorHSLA", node -> {
+            float h = Integer.parseInt(node.child("@h").text()) / 360.0f;
+            float s = Float.parseFloat(StringUtils.substr(node.child("@s").text(), 0, -1)) / 100.0f;
+            float v = Float.parseFloat(StringUtils.substr(node.child("@l").text(), 0, -1)) / 100.0f;
+            int a = Math.round(255 * Float.parseFloat(node.child("@alpha").text()));;
+
+            return ColorUtils.alpha(Color.getHSBColor(h,s,v), a);
+        })
+        .mapRule("#codeHex3", v -> {
+            int r = 17 * Integer.parseInt(v.text().substring(1,2), 16);
+            int g = 17 * Integer.parseInt(v.text().substring(2,3), 16);
+            int b = 17 * Integer.parseInt(v.text().substring(3,4), 16);
+
+            return new Color(r, g, b);
+        })
+        .mapRule("#codeHex6", v -> {
+            int r = Integer.parseInt(v.text().substring(1,3), 16);
+            int g = Integer.parseInt(v.text().substring(3,5), 16);
+            int b = Integer.parseInt(v.text().substring(5,7), 16);
+
+            return new Color(r, g, b);
+        })
+        .prepare();
+
+    public static CQuery<Color> parseAll(String colors) {
+        return SELECTOR.stream(PARSER.parse("colors", colors));
+    }
+
+    public static Color parse(String color) {
+        return SELECTOR.single(PARSER.parse("color1", color));
+    }
+
+}

assira.grammar/src/main/java/net/ranides/assira/grammar/G4Node.java → assira.commons/src/main/java/net/ranides/assira/grammar/G4Node.java


+ 6 - 3
assira.grammar/src/main/java/net/ranides/assira/grammar/G4Parser.java

@@ -1,8 +1,7 @@
 package net.ranides.assira.grammar;
 package net.ranides.assira.grammar;
 
 
 
 
-import net.ranides.assira.grammar.impl.antlr.ParserGenerated;
-import net.ranides.assira.grammar.impl.antlr.ParserInterpreted;
+import net.ranides.assira.grammar.impl.ParserGenerated;
 import net.ranides.assira.reflection.IClass;
 import net.ranides.assira.reflection.IClass;
 import org.antlr.v4.runtime.Lexer;
 import org.antlr.v4.runtime.Lexer;
 import org.antlr.v4.runtime.Parser;
 import org.antlr.v4.runtime.Parser;
@@ -10,7 +9,7 @@ import org.antlr.v4.runtime.Parser;
 public interface G4Parser {
 public interface G4Parser {
 
 
     static G4Parser newInstance(String grammar) {
     static G4Parser newInstance(String grammar) {
-        return new ParserInterpreted(grammar);
+        return (G4Parser) IClass.typeinfo("net.ranides.assira.grammar.impl.G4ParserInterpreter").construct(grammar);
     }
     }
 
 
     static G4Parser newInstance(Class<? extends Lexer> lexer, Class<? extends Parser> parser) {
     static G4Parser newInstance(Class<? extends Lexer> lexer, Class<? extends Parser> parser) {
@@ -23,6 +22,10 @@ public interface G4Parser {
 
 
     G4Node parse(String rule, String text);
     G4Node parse(String rule, String text);
 
 
+    boolean validateRuleName(String ruleName);
+
+    boolean validateTokenName(String ruleName);
+
     String ruleName(int ruleIndex);
     String ruleName(int ruleIndex);
 
 
     String ruleName(Class<?> ruleType);
     String ruleName(Class<?> ruleType);

+ 8 - 2
assira.grammar/src/main/java/net/ranides/assira/grammar/G4Selector.java

@@ -11,9 +11,9 @@ import net.ranides.assira.collection.query.support.BaseIterable;
 import net.ranides.assira.collection.query.support.BaseState;
 import net.ranides.assira.collection.query.support.BaseState;
 import net.ranides.assira.functional.Consumers;
 import net.ranides.assira.functional.Consumers;
 import net.ranides.assira.functional.Predicates;
 import net.ranides.assira.functional.Predicates;
-import net.ranides.assira.grammar.properties.G4NodeProperty;
 import net.ranides.assira.generic.Pair;
 import net.ranides.assira.generic.Pair;
 import net.ranides.assira.generic.Ref;
 import net.ranides.assira.generic.Ref;
+import net.ranides.assira.grammar.properties.G4NodeProperty;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Collections;
@@ -98,7 +98,7 @@ public class G4Selector<V> {
                 return true;
                 return true;
             }
             }
         }
         }
-        if(skipName.contains(node.shortname()) || skipName.contains(node.name())) {
+        if(skipName.contains(node.shortname()) || skipName.contains(node.qualifier()) || skipName.contains(node.name())) {
             return true;
             return true;
         }
         }
 
 
@@ -134,12 +134,18 @@ public class G4Selector<V> {
         if(mapForName.containsKey(node.shortname())) {
         if(mapForName.containsKey(node.shortname())) {
             return Ref.of(mapForName.get(node.shortname()).apply(node, this));
             return Ref.of(mapForName.get(node.shortname()).apply(node, this));
         }
         }
+        if(mapForName.containsKey(node.qualifier())) {
+            return Ref.of(mapForName.get(node.qualifier()).apply(node, this));
+        }
         if(mapForName.containsKey(node.name())) {
         if(mapForName.containsKey(node.name())) {
             return Ref.of(mapForName.get(node.name()).apply(node, this));
             return Ref.of(mapForName.get(node.name()).apply(node, this));
         }
         }
         if(nativeMapForName.containsKey(node.shortname())) {
         if(nativeMapForName.containsKey(node.shortname())) {
             return Ref.of(nativeMapForName.get(node.shortname()).apply(node.unwrap(), this));
             return Ref.of(nativeMapForName.get(node.shortname()).apply(node.unwrap(), this));
         }
         }
+        if(nativeMapForName.containsKey(node.qualifier())) {
+            return Ref.of(nativeMapForName.get(node.qualifier()).apply(node.unwrap(), this));
+        }
         if(nativeMapForName.containsKey(node.name())) {
         if(nativeMapForName.containsKey(node.name())) {
             return Ref.of(nativeMapForName.get(node.name()).apply(node.unwrap(), this));
             return Ref.of(nativeMapForName.get(node.name()).apply(node.unwrap(), this));
         }
         }

+ 15 - 1
assira.grammar/src/main/java/net/ranides/assira/grammar/G4SelectorBuilder.java

@@ -4,8 +4,8 @@ import net.ranides.assira.collection.maps.CrossMap;
 import net.ranides.assira.collection.maps.OpenCrossMap;
 import net.ranides.assira.collection.maps.OpenCrossMap;
 import net.ranides.assira.collection.maps.OpenMap;
 import net.ranides.assira.collection.maps.OpenMap;
 import net.ranides.assira.collection.sets.OpenSet;
 import net.ranides.assira.collection.sets.OpenSet;
-import net.ranides.assira.grammar.properties.G4NodeProperty;
 import net.ranides.assira.generic.Pair;
 import net.ranides.assira.generic.Pair;
+import net.ranides.assira.grammar.properties.G4NodeProperty;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
@@ -266,6 +266,7 @@ public class G4SelectorBuilder<V> {
      * @return self
      * @return self
      */
      */
     public G4SelectorBuilder<V> mapRule(String ruleName, BiFunction<G4Node, G4Selector<V>, V> function) {
     public G4SelectorBuilder<V> mapRule(String ruleName, BiFunction<G4Node, G4Selector<V>, V> function) {
+        validateRuleName(ruleName);
         mapForName.put(ruleName, function);
         mapForName.put(ruleName, function);
         return this;
         return this;
     }
     }
@@ -298,6 +299,7 @@ public class G4SelectorBuilder<V> {
     }
     }
 
 
     public G4SelectorBuilder<V> mapToken(String tokenName, BiFunction<G4Node, G4Selector<V>, V> function) {
     public G4SelectorBuilder<V> mapToken(String tokenName, BiFunction<G4Node, G4Selector<V>, V> function) {
+        validateTokenName(tokenName);
         mapForName.put(tokenName, function);
         mapForName.put(tokenName, function);
         return this;
         return this;
     }
     }
@@ -368,4 +370,16 @@ public class G4SelectorBuilder<V> {
         }
         }
     }
     }
 
 
+    private void validateRuleName(String ruleName) {
+        if(parser!=null && !parser.validateRuleName(ruleName)) {
+            throw new IllegalArgumentException("Selector '" + name + "': invalid rule: " + ruleName);
+        }
+    }
+
+    private void validateTokenName(String ruleName) {
+        if(parser != null && !parser.validateTokenName(ruleName)) {
+            throw new IllegalArgumentException("Selector '" + name + "': invalid token: " + ruleName);
+        }
+    }
+
 }
 }

assira.grammar/src/main/java/net/ranides/assira/grammar/G4Support.java → assira.commons/src/main/java/net/ranides/assira/grammar/G4Support.java


+ 6 - 6
assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/NodeAbstract.java

@@ -1,12 +1,12 @@
-package net.ranides.assira.grammar.impl.antlr;
+package net.ranides.assira.grammar.impl;
 
 
 import net.ranides.assira.collection.query.CQuery;
 import net.ranides.assira.collection.query.CQuery;
-import net.ranides.assira.grammar.G4Node;
-import net.ranides.assira.grammar.properties.G4NodeProperties;
-import net.ranides.assira.grammar.properties.G4NodeProperty;
 import net.ranides.assira.generic.LazyCaller;
 import net.ranides.assira.generic.LazyCaller;
 import net.ranides.assira.generic.LazyCallers;
 import net.ranides.assira.generic.LazyCallers;
 import net.ranides.assira.generic.Ref;
 import net.ranides.assira.generic.Ref;
+import net.ranides.assira.grammar.G4Node;
+import net.ranides.assira.grammar.properties.G4NodeProperties;
+import net.ranides.assira.grammar.properties.G4NodeProperty;
 import net.ranides.assira.reflection.IClass;
 import net.ranides.assira.reflection.IClass;
 
 
 import java.util.NoSuchElementException;
 import java.util.NoSuchElementException;
@@ -52,14 +52,14 @@ abstract class NodeAbstract implements G4Node {
             if(hit.matches()) {
             if(hit.matches()) {
                 String n = hit.group(1);
                 String n = hit.group(1);
                 int i = Integer.parseInt(hit.group(2));
                 int i = Integer.parseInt(hit.group(2));
-                children().filter(v -> n.equals(v.shortname()) || n.equals(v.name())).at(i);
+                children().filter(v -> n.equals(v.shortname()) || n.equals(v.qualifier()) || n.equals(v.name())).at(i);
             }
             }
         }
         }
         if(NodeSupport.POSITION_SELECTOR.matcher(name).matches()) {
         if(NodeSupport.POSITION_SELECTOR.matcher(name).matches()) {
             int i = Integer.parseInt(name);
             int i = Integer.parseInt(name);
             return CQuery.from().optional(children().at(i));
             return CQuery.from().optional(children().at(i));
         }
         }
-        return children().filter(v -> name.equals(v.name()) || name.equals(v.shortname()));
+        return children().filter(v -> name.equals(v.name()) || name.equals(v.qualifier()) || name.equals(v.shortname()));
     }
     }
 
 
     @Override
     @Override

+ 2 - 2
assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/NodeForRule.java

@@ -1,9 +1,9 @@
-package net.ranides.assira.grammar.impl.antlr;
+package net.ranides.assira.grammar.impl;
 
 
 import net.ranides.assira.collection.query.CQuery;
 import net.ranides.assira.collection.query.CQuery;
-import net.ranides.assira.grammar.G4Node;
 import net.ranides.assira.generic.LazyCaller;
 import net.ranides.assira.generic.LazyCaller;
 import net.ranides.assira.generic.LazyCallers;
 import net.ranides.assira.generic.LazyCallers;
+import net.ranides.assira.grammar.G4Node;
 import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.misc.Interval;
 import org.antlr.v4.runtime.misc.Interval;
 import org.antlr.v4.runtime.tree.ParseTree;
 import org.antlr.v4.runtime.tree.ParseTree;

+ 1 - 1
assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/NodeForTerm.java

@@ -1,4 +1,4 @@
-package net.ranides.assira.grammar.impl.antlr;
+package net.ranides.assira.grammar.impl;
 
 
 import net.ranides.assira.collection.query.CQuery;
 import net.ranides.assira.collection.query.CQuery;
 import net.ranides.assira.grammar.G4Node;
 import net.ranides.assira.grammar.G4Node;

+ 1 - 1
assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/NodeForToken.java

@@ -1,4 +1,4 @@
-package net.ranides.assira.grammar.impl.antlr;
+package net.ranides.assira.grammar.impl;
 
 
 import net.ranides.assira.collection.query.CQuery;
 import net.ranides.assira.collection.query.CQuery;
 import net.ranides.assira.grammar.G4Node;
 import net.ranides.assira.grammar.G4Node;

+ 1 - 1
assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/NodeSupport.java

@@ -1,4 +1,4 @@
-package net.ranides.assira.grammar.impl.antlr;
+package net.ranides.assira.grammar.impl;
 
 
 import lombok.experimental.UtilityClass;
 import lombok.experimental.UtilityClass;
 
 

+ 207 - 0
assira.commons/src/main/java/net/ranides/assira/grammar/impl/ParserGenerated.java

@@ -0,0 +1,207 @@
+package net.ranides.assira.grammar.impl;
+
+import net.ranides.assira.collection.sets.OpenSet;
+import net.ranides.assira.generic.Ref;
+import net.ranides.assira.grammar.G4Node;
+import net.ranides.assira.grammar.G4Parser;
+import net.ranides.assira.reflection.IClass;
+import net.ranides.assira.reflection.IMethod;
+import net.ranides.assira.reflection.IReflectiveException;
+import net.ranides.assira.text.StringUtils;
+import org.antlr.v4.runtime.ANTLRErrorListener;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.Parser;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.atn.ATNConfigSet;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.tree.RuleNode;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Set;
+
+public class ParserGenerated implements G4Parser {
+
+    protected final IClass<? extends Lexer> lexer;
+
+    protected final IClass<? extends Parser> parser;
+
+    private final String[] lexerRules;
+
+    private final String[] parserRules;
+
+    private final Set<String> branchValidator;
+
+    public ParserGenerated(IClass<? extends Lexer> lexer, IClass<? extends Parser> parser) {
+        this.lexer = lexer;
+        this.parser = parser;
+
+        this.lexerRules = (String[])lexer.field("ruleNames").get().getStatic();
+        this.parserRules = (String[])parser.field("ruleNames").get().getStatic();
+
+        this.branchValidator = new OpenSet<>();
+        parser.inner().forEach(type -> {
+            String someName = ruleName(type.raw());
+            if(type.parent().outer() == IClass.NULL) {
+                branchValidator.add(someName);
+            } else {
+                String ruleName = ruleName(type.parent().raw());
+                branchValidator.add(NodeSupport.QUALIFIER_NAME + someName);
+                branchValidator.add(ruleName + NodeSupport.QUALIFIER_NAME + someName);
+            }
+        });
+    }
+
+    @Override
+    public G4Node parse(String rule, String text) {
+        return new MyRoot(rule, text).tree();
+    }
+
+    @Override
+    public boolean validateRuleName(String ruleName) {
+        if(ruleName.contains("#")) {
+            return branchValidator.contains(ruleName);
+        } else {
+            return Arrays.asList(parserRules).contains(ruleName);
+        }
+    }
+
+    @Override
+    public boolean validateTokenName(String tokenName) {
+        return Arrays.asList(lexerRules).contains(tokenName);
+    }
+
+    @Override
+    public String ruleName(int ruleIndex) {
+        return parserRules[ruleIndex];
+    }
+
+    @Override
+    public String ruleName(Class<?> ruleType) {
+        return StringUtils.uncapitalize(ruleType.getSimpleName().replaceAll("Context$", ""));
+    }
+
+    @Override
+    public String tokenName(int tokenIndex) {
+        if(tokenIndex <0 || tokenIndex>=lexerRules.length) {
+            return "?";
+        }
+        return lexerRules[tokenIndex-1];
+    }
+
+    private class MyRoot extends RootAbstract {
+
+        private final NodeForRule tree;
+
+        public MyRoot(String ruleName, String text) {
+            Lexer lexer = ParserGenerated.this.lexer.construct(CharStreams.fromString(text));
+
+            lexer.removeErrorListeners();
+            lexer.addErrorListener(new CustomErrorListener());
+
+            CommonTokenStream tokens = new CommonTokenStream(lexer);
+            Parser interpreter = ParserGenerated.this.parser.construct(tokens);
+
+            // @todo parser builder: with error handlers
+            interpreter.removeErrorListeners();
+            interpreter.addErrorListener(new CustomErrorListener());
+
+            IMethod rule = ParserGenerated.this.parser
+                .method(ruleName)
+                .orElseThrow(() -> new IllegalArgumentException("Unknown rule: " + ruleName));
+
+            try {
+                this.tree = new NodeForRule(this, null, (RuleNode) rule.call(interpreter));
+            } catch(IReflectiveException.CallException e) {
+                throw new IllegalArgumentException(e.getCause());
+            }
+        }
+
+        @Override
+        public G4Parser parser() {
+            return ParserGenerated.this;
+        }
+
+        @Override
+        public G4Node tree() {
+            return tree;
+        }
+
+        @Override
+        public String branchName(G4Node g4node) {
+            IClass<?> type = g4node.type();
+            if(type.parent().outer() == IClass.NULL) {
+                return NodeSupport.QUALIFIER_INDEX_DEFAULT;
+            } else {
+                return NodeSupport.QUALIFIER_NAME + ruleName(type.raw());
+            }
+        }
+
+        @Override
+        public Ref<G4Node> findLabel(G4Node g4node, String labelName) {
+            Object node = g4node.unwrap();
+            return IClass.typefor(node)
+                .field(labelName)
+                .map(f -> f.get(node))
+                .map(t -> wrap(g4node, t));
+        }
+
+    }
+
+    public static final class CustomException extends RuntimeException {
+        public CustomException(String message) {
+            super(message);
+        }
+
+        public CustomException(Throwable cause) {
+            super(cause);
+        }
+    }
+
+    // @todo reasonable error handler
+    public static final class CustomErrorListener implements ANTLRErrorListener {
+        @Override
+        public void syntaxError(Recognizer<?, ?> recognizer,
+            Object offendingSymbol,
+            int line,
+            int charPositionInLine,
+            String msg,
+            RecognitionException e) {
+            throw new CustomException(e);
+        }
+
+        @Override
+        public void reportAmbiguity(Parser recognizer,
+            DFA dfa,
+            int startIndex,
+            int stopIndex,
+            boolean exact,
+            BitSet ambigAlts,
+            ATNConfigSet configs) {
+            throw new CustomException("reportAmbiguity");
+        }
+
+        @Override
+        public void reportAttemptingFullContext(Parser recognizer,
+            DFA dfa,
+            int startIndex,
+            int stopIndex,
+            BitSet conflictingAlts,
+            ATNConfigSet configs) {
+            throw new CustomException("reportAttemptingFullContext");
+        }
+
+        @Override
+        public void reportContextSensitivity(Parser recognizer,
+            DFA dfa,
+            int startIndex,
+            int stopIndex,
+            int prediction,
+            ATNConfigSet configs) {
+            throw new CustomException("reportContextSensitivity");
+        }
+    }
+}

+ 2 - 2
assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/RootAbstract.java

@@ -1,8 +1,8 @@
-package net.ranides.assira.grammar.impl.antlr;
+package net.ranides.assira.grammar.impl;
 
 
+import net.ranides.assira.generic.Ref;
 import net.ranides.assira.grammar.G4Node;
 import net.ranides.assira.grammar.G4Node;
 import net.ranides.assira.grammar.G4Parser;
 import net.ranides.assira.grammar.G4Parser;
-import net.ranides.assira.generic.Ref;
 import org.antlr.v4.runtime.CommonToken;
 import org.antlr.v4.runtime.CommonToken;
 import org.antlr.v4.runtime.tree.RuleNode;
 import org.antlr.v4.runtime.tree.RuleNode;
 import org.antlr.v4.runtime.tree.TerminalNode;
 import org.antlr.v4.runtime.tree.TerminalNode;

assira.grammar/src/main/java/net/ranides/assira/grammar/properties/G4NodeProperties.java → assira.commons/src/main/java/net/ranides/assira/grammar/properties/G4NodeProperties.java


assira.grammar/src/main/java/net/ranides/assira/grammar/properties/G4NodeProperty.java → assira.commons/src/main/java/net/ranides/assira/grammar/properties/G4NodeProperty.java


+ 99 - 0
assira.commons/src/test/java/net/ranides/assira/awt/ColorUtils2Test.java

@@ -0,0 +1,99 @@
+package net.ranides.assira.awt;
+
+import net.ranides.assira.awt.ColorUtils;
+import net.ranides.assira.awt.ColorUtils2;
+import net.ranides.assira.grammar.G4Node;
+import net.ranides.assira.grammar.G4Parser;
+import net.ranides.assira.grammar.G4SelectorBuilder;
+import net.ranides.assira.grammar.G4Support;
+import net.ranides.assira.io.ResourceUtils;
+import net.ranides.assira.junit.NewAssert;
+import net.ranides.grammars.generated.CssColorsLexer;
+import net.ranides.grammars.generated.CssColorsParser;
+import org.junit.Test;
+
+import java.awt.*;
+import java.io.IOException;
+
+import static net.ranides.assira.junit.NewAssert.assertThrows;
+import static org.junit.Assert.assertEquals;
+
+public class ColorUtils2Test {
+
+    @Test
+    public void basic() throws IOException {
+        G4Parser gp = G4Parser.newInstance(CssColorsLexer.class, CssColorsParser.class);
+
+        G4Node out = gp.parse("color", "rgba(15,20,30,0.75)");
+
+        assertEquals(ResourceUtils.text("grammars/CssColors.tree.txt"), G4Support.printTree(out));
+        assertEquals(ResourceUtils.text("grammars/CssColors.paths.txt"), G4Support.printPath(out));
+
+        assertEquals("rgba(15,20,30,0.75)", out.child("colorRGBA").text());
+        assertEquals("0.75", out.child("colorRGBA").child("@alpha").text());
+
+        assertEquals("color/colorRGBA/componentAlpha", out.find("colorRGBA/@alpha").path());
+
+        assertThrows(e -> e.getMessage().contains("There is no path 'colorRGBA/@unknown' inside node 'color#color_rgba=rgba(15,20,30,0.75)'"), () -> {
+            out.find("colorRGBA/@unknown").path();
+        });
+
+        assertThrows(e -> e.getMessage().contains("There is no path 'unknown' inside node 'color/colorRGBA$0=rgba(15,20,30,0.75)'"), () -> {
+            out.child("colorRGBA").find("unknown").path();
+        });
+    }
+
+    @Test
+    public void wrongSelector() {
+        G4Parser parser = G4Parser.newInstance(CssColorsLexer.class, CssColorsParser.class);
+
+        // without validation
+        new G4SelectorBuilder<Color>()
+            .withName("selector:color")
+            .mapRule("invalidGrammarRule", node -> Color.BLUE)
+            .mapRule("colorRGBA#stupid", node -> Color.BLUE)
+            .mapRule("#stupid", node -> Color.BLUE)
+            .prepare();
+
+        NewAssert.assertThrows(e -> e.getMessage().contains("stupid"), () -> {
+            new G4SelectorBuilder<Color>()
+                .withName("selector:color")
+                .withParser(parser)
+                .mapRule("colorRGBA", node -> Color.BLUE)
+                .mapRule("stupid", node -> Color.BLUE)
+                .prepare();
+        });
+
+        NewAssert.assertThrows(e -> e.getMessage().contains("componentHue#color_rgba"), () -> {
+            new G4SelectorBuilder<Color>()
+                .withName("selector:color")
+                .withParser(parser)
+                .mapRule("color#color_rgba", node -> Color.BLUE)
+                .mapRule("componentHue#color_rgba", node -> Color.BLUE)
+                .prepare();
+        });
+
+        NewAssert.assertThrows(e -> e.getMessage().contains("#stupid"), () -> {
+            new G4SelectorBuilder<Color>()
+                .withName("selector:color")
+                .withParser(parser)
+                .mapRule("#color_rgba", node -> Color.BLUE)
+                .mapRule("#stupid", node -> Color.BLUE)
+                .prepare();
+        });
+
+    }
+
+    @Test
+    public void evaluator() {
+
+        assertEquals("rgba(15,20,30,0.75)", ColorUtils.asCSS3(ColorUtils2.parse("rgba ( 15, 20, 30, 0.75 )")));
+        assertEquals("rgb(15,20,30)", ColorUtils.asCSS3(ColorUtils2.parse("rgb(15,20,30)")));
+        assertEquals("#f08040", ColorUtils.asCSS2(ColorUtils2.parse("#f08040")));
+
+        assertEquals(
+            "#5080a0 #324668 #778899",
+            ColorUtils2.parseAll("rgb ( 80, 128, 160 ) #324668 #789").map(ColorUtils::asCSS2).join(" ")
+        );
+    }
+}

+ 9 - 5
assira.commons/src/test/java/net/ranides/assira/awt/ColorUtilsTest.java

@@ -100,24 +100,28 @@ public class ColorUtilsTest {
         NewAssert.assertThrows(IllegalArgumentException.class, ()->{
         NewAssert.assertThrows(IllegalArgumentException.class, ()->{
             ColorUtils.fromCSS("#10347280");
             ColorUtils.fromCSS("#10347280");
         });
         });
-        
+
         assertEquals(new Color(10, 34, 72), ColorUtils.fromCSS("rgb(10,34,72)"));
         assertEquals(new Color(10, 34, 72), ColorUtils.fromCSS("rgb(10,34,72)"));
         assertEquals(new Color(10, 34, 72, 255), ColorUtils.fromCSS("rgb(10,34,72)"));
         assertEquals(new Color(10, 34, 72, 255), ColorUtils.fromCSS("rgb(10,34,72)"));
 
 
         assertEquals(new Color(10, 34, 72, 0), ColorUtils.fromCSS("rgba(10,34,72,0.00)"));
         assertEquals(new Color(10, 34, 72, 0), ColorUtils.fromCSS("rgba(10,34,72,0.00)"));
         assertEquals(new Color(10, 34, 72, 0), ColorUtils.fromCSS("rgba (10, 34,  72, 0)"));
         assertEquals(new Color(10, 34, 72, 0), ColorUtils.fromCSS("rgba (10, 34,  72, 0)"));
-        
+
         assertEquals(new Color(10, 34, 72, 64), ColorUtils.fromCSS("rgba(10,34,72,0.25)"));
         assertEquals(new Color(10, 34, 72, 64), ColorUtils.fromCSS("rgba(10,34,72,0.25)"));
         assertEquals(new Color(10, 34, 72, 191), ColorUtils.fromCSS("rgba(10,34,72,0.75 )"));
         assertEquals(new Color(10, 34, 72, 191), ColorUtils.fromCSS("rgba(10,34,72,0.75 )"));
-          
+
         assertEquals(new Color(0,128,0), ColorUtils.fromCSS("hsl(120, 100%, 50%)"));
         assertEquals(new Color(0,128,0), ColorUtils.fromCSS("hsl(120, 100%, 50%)"));
         assertEquals(new Color(120,191,48), ColorUtils.fromCSS("hsl(90, 75%, 75%)"));
         assertEquals(new Color(120,191,48), ColorUtils.fromCSS("hsl(90, 75%, 75%)"));
         assertEquals(new Color(191,191,48), ColorUtils.fromCSS("hsl(60, 75%, 75%)"));
         assertEquals(new Color(191,191,48), ColorUtils.fromCSS("hsl(60, 75%, 75%)"));
-        
+
         assertEquals(new Color(0,128,0,0), ColorUtils.fromCSS("hsl(120, 100%, 50%, 0)"));
         assertEquals(new Color(0,128,0,0), ColorUtils.fromCSS("hsl(120, 100%, 50%, 0)"));
         assertEquals(new Color(120,191,48,64), ColorUtils.fromCSS("hsl(90, 75%, 75%, 0.25)"));
         assertEquals(new Color(120,191,48,64), ColorUtils.fromCSS("hsl(90, 75%, 75%, 0.25)"));
         assertEquals(new Color(191,191,48,191), ColorUtils.fromCSS("hsl(60, 75%, 75%, 0.75)"));
         assertEquals(new Color(191,191,48,191), ColorUtils.fromCSS("hsl(60, 75%, 75%, 0.75)"));
-        
+
+        assertEquals(new Color(0,128,0,0), ColorUtils.fromCSS("hsla(120, 100%, 50%, 0)"));
+        assertEquals(new Color(120,191,48,64), ColorUtils.fromCSS("hsla(90, 75%, 75%, 0.25)"));
+        assertEquals(new Color(191,191,48,191), ColorUtils.fromCSS("hsla(60, 75%, 75%, 0.75)"));
+
         NewAssert.assertThrows(IllegalArgumentException.class, ()->{
         NewAssert.assertThrows(IllegalArgumentException.class, ()->{
             ColorUtils.fromCSS("rgb(x");
             ColorUtils.fromCSS("rgb(x");
         });
         });

+ 20 - 0
assira.commons/src/test/resources/grammars/CssColors.paths.txt

@@ -0,0 +1,20 @@
+color = 'rgba(15,20,30,0.75)'
+color/colorRGBA = 'rgba(15,20,30,0.75)'
+color/colorRGBA/PREFIX_RGBA = 'rgba'
+color/colorRGBA/LP = '('
+color/colorRGBA/componentRGB[0] = '15'
+color/colorRGBA/componentRGB[0]/numberInt = '15'
+color/colorRGBA/componentRGB[0]/numberInt/NUMBER_INT = '15'
+color/colorRGBA/CS[0] = ','
+color/colorRGBA/componentRGB[1] = '20'
+color/colorRGBA/componentRGB[1]/numberInt = '20'
+color/colorRGBA/componentRGB[1]/numberInt/NUMBER_INT = '20'
+color/colorRGBA/CS[1] = ','
+color/colorRGBA/componentRGB[2] = '30'
+color/colorRGBA/componentRGB[2]/numberInt = '30'
+color/colorRGBA/componentRGB[2]/numberInt/NUMBER_INT = '30'
+color/colorRGBA/CS[2] = ','
+color/colorRGBA/componentAlpha = '0.75'
+color/colorRGBA/componentAlpha/numberReal = '0.75'
+color/colorRGBA/componentAlpha/numberReal/NUMBER_REAL = '0.75'
+color/colorRGBA/RP = ')'

+ 20 - 0
assira.commons/src/test/resources/grammars/CssColors.tree.txt

@@ -0,0 +1,20 @@
+color#color_rgba = 'rgba(15,20,30,0.75)'
+   colorRGBA$0 = 'rgba(15,20,30,0.75)'
+      PREFIX_RGBA = 'rgba'
+      LP = '('
+      componentRGB$0 = '15'
+         numberInt$0 = '15'
+            NUMBER_INT = '15'
+      CS = ','
+      componentRGB$0 = '20'
+         numberInt$0 = '20'
+            NUMBER_INT = '20'
+      CS = ','
+      componentRGB$0 = '30'
+         numberInt$0 = '30'
+            NUMBER_INT = '30'
+      CS = ','
+      componentAlpha$0 = '0.75'
+         numberReal$0 = '0.75'
+            NUMBER_REAL = '0.75'
+      RP = ')'

+ 224 - 0
assira.core/src/main/java/net/ranides/assira/collection/sets/ArraySet.java

@@ -0,0 +1,224 @@
+/*
+ * @author Ranides Atterwim {@literal <ranides@gmail.com>}
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+
+package net.ranides.assira.collection.sets;
+
+import net.ranides.assira.collection.BlockCollection;
+import net.ranides.assira.collection.arrays.ArrayAllocator;
+import net.ranides.assira.collection.arrays.ArraySort;
+import net.ranides.assira.collection.arrays.ArrayUtils;
+import net.ranides.assira.collection.iterators.RandomAccessIterator;
+import net.ranides.assira.generic.CompareUtils;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.SortedSet;
+
+/**
+ * Memory efficient, but immutable map.
+ * It stores elements inside sorted array and uses binary search for access.
+ *
+ * @author Ranides Atterwim {@literal <ranides@gmail.com>}
+ * @param <V> V
+ */
+public class ArraySet<V> extends ASet<V> implements BlockCollection<V> {
+
+    private static final long serialVersionUID = 1L;
+
+    private final Class<?> type;
+    private V[] data;
+    private int size;
+
+    private final Comparator<? super V> cmp;
+
+    /**
+     * Creates new map with provided keys and values.
+     * Please note, that keys must be comparable.
+     * Please note, that map does not preserve order of keys.
+     *
+     * @param data keys
+     */
+    public ArraySet(V[] data) {
+        this(data, CompareUtils.comparator());
+    }
+
+    /**
+     * Creates new map with provided keys and values.
+     * It uses comparator function for sorting keys.
+     * Please note, that map does not preserve order of keys.
+     *
+     * @param data keys
+     * @param comparator comparator
+     */
+    public ArraySet(V[] data, Comparator<? super V> comparator) {
+        this.type = data.getClass().getComponentType();
+        this.data = data.clone();
+        this.size = data.length;
+        this.cmp = comparator;
+        sort();
+    }
+
+    /**
+     * Creates new map with content from source map.
+     * Created ArrayMap uses the same comparator as source map.
+     *
+     * @param set set
+     */
+    @SuppressWarnings("unchecked")
+    public ArraySet(SortedSet<V> set) {
+        int n = set.size();
+        Object[] k = new Object[n];
+
+        int i = 0;
+        for(V item : set) {
+            k[i] = item;
+            i++;
+        }
+
+        this.type = Object.class;
+        this.data = (V[])k;
+        this.size = data.length;
+        this.cmp = set.comparator();
+    }
+    
+    private void sort() {
+      ArraySort.quickSort(data, cmp);
+    }
+
+    @Override
+    public int capacity() {
+        return data.length;
+    }
+
+    @Override
+    public boolean trim() {
+        return trim(data.length);
+    }
+
+    @Override
+    public boolean reserve(int capacity) {
+        data = ArrayAllocator.ensureCapacity(data, capacity, size);
+        return true;
+    }
+
+    @Override
+    public boolean trim(int n) {
+        if(n > capacity()) {
+            return false;
+        }
+        if(n<size) {
+            throw new IllegalArgumentException(String.format("n= %d is too small (size=%d)", n, size));
+        }
+        this.data = ArrayUtils.slice(data, 0, n);
+        return true;
+    }
+
+    public V get(int index) {
+        return data[index];
+    }
+
+    @Override
+    public ListIterator<V> iterator() {
+        return new KeyIterator(0);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public boolean contains(Object key) {
+        if(!type.isInstance(key)) {
+            return false;
+        }
+        @SuppressWarnings("unchecked")
+        int i = Arrays.binarySearch(data, 0, size, (V)key, cmp);
+        return i >= 0;
+    }
+
+    @Override
+    public int size() {
+        return size;
+    }
+
+    @Override
+    public boolean remove(Object key) {
+        if(!type.isInstance(key)) {
+            return false;
+        }
+
+        @SuppressWarnings("unchecked")
+        int pos = Arrays.binarySearch(data, 0, size, (V)key, cmp);
+        if(pos<0) {
+            return false;
+        }
+        $remove(pos);
+        return true;
+    }
+
+    @Override
+    public boolean add(V key) {
+        int pos = Arrays.binarySearch(data, 0, size, key, cmp);
+        if(pos >=0) {
+            return false;
+        } else {
+            $add(-pos - 1, key);
+            return true;
+        }
+    }
+
+    @Override
+    public void clear() {
+        size = 0;
+        Arrays.fill(data, null);
+    }
+
+    private void $remove(int index) {
+        int shift = size - index - 1;
+        if (shift > 0) {
+            System.arraycopy(data, index + 1, data, index, shift);
+        }
+
+        size--;
+        data[size] = null;
+    }
+
+    private void $add(int index, V key) {
+        data = ArrayAllocator.grow(data, size+1);
+
+        int shift = size - index;
+        if (shift > 0) {
+            System.arraycopy(data, index, data, index + 1, shift);
+        }
+        data[index] = key;
+        size++;
+    }
+
+    private class KeyIterator extends RandomAccessIterator<V> {
+
+        public KeyIterator(int index) {
+            super(index);
+        }
+
+        @Override
+        protected int size() {
+            return size;
+        }
+
+        @Override
+        protected V get(int index) {
+            return data[index];
+        }
+
+        @Override
+        protected void remove(int index) {
+            $remove(index);
+        }
+
+    }
+
+}

+ 31 - 0
assira.core/src/test/java/net/ranides/assira/collection/sets/ArraySetTest.java

@@ -0,0 +1,31 @@
+package net.ranides.assira.collection.sets;
+
+import net.ranides.test.ContractTesters;
+import net.ranides.test.data.TCollection;
+import net.ranides.test.data.TMaps;
+import net.ranides.test.data.TPoint;
+import org.junit.Test;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+public class ArraySetTest {
+    private final TCollection<TPoint> $var = TMaps.MAP_PI.keys();
+
+    private final Comparator<TPoint> $cmp = (Serializable & Comparator<TPoint>)(a, b) -> {
+        int x = Integer.compare(a.x, b.x);
+        int y = Integer.compare(a.y, b.y);
+        int z = Integer.compare(a.z, b.z);
+        return x != 0 ? x : y != 0 ? y : z;
+    };
+
+    @Test
+    public void testSuite() {
+        ContractTesters.runner()
+            .param("collection!", $var)
+            .function(new int[0], array -> new ArraySet<>($var.list(array).values(), $cmp))
+            .run();
+
+    }
+
+}

+ 8 - 6
assira.core8/src/main/java/net/ranides/assira/trace/FStackWalker8.java

@@ -6,6 +6,8 @@
  */
  */
 package net.ranides.assira.trace;
 package net.ranides.assira.trace;
 
 
+import net.ranides.assira.collection.query.CQuery;
+import net.ranides.assira.generic.Ref;
 import net.ranides.assira.generic.ValueUtils;
 import net.ranides.assira.generic.ValueUtils;
 
 
 import java.util.AbstractList;
 import java.util.AbstractList;
@@ -78,18 +80,18 @@ public final class FStackWalker8 implements TraceUtils.IStackWalker {
     }
     }
 
 
     @Override
     @Override
-    public Optional<StackTraceElement> getFrame(Predicate<StackTraceElement> filter) {
-        return new FrameList().stream().filter(filter).findFirst();
+    public Ref<StackTraceElement> getFrame(Predicate<StackTraceElement> filter) {
+        return CQuery.from().list(new FrameList()).filter(filter).first();
     }
     }
 
 
     @Override
     @Override
-    public Optional<Class<?>> getType(Predicate<Class<?>> filter) {
-        return AUTO_LIST_RESOLVER.list().stream().filter(filter).findFirst();
+    public Ref<Class<?>> getType(Predicate<Class<?>> filter) {
+        return CQuery.from().list(AUTO_LIST_RESOLVER.list()).filter(filter).first();
     }
     }
 
 
     @Override
     @Override
-    public Optional<String> getName(Predicate<String> filter) {
-        return AUTO_LIST_RESOLVER.names().stream().filter(filter).findFirst();
+    public Ref<String> getName(Predicate<String> filter) {
+        return CQuery.from().list(AUTO_LIST_RESOLVER.names()).filter(filter).first();
     }
     }
 
 
     @Override
     @Override

+ 1 - 23
assira.grammar/pom.xml

@@ -9,7 +9,7 @@
         <version>2.8.4-SNAPSHOT</version>
         <version>2.8.4-SNAPSHOT</version>
     </parent>
     </parent>
 
 
-    <artifactId>assira.grammar</artifactId>
+    <artifactId>assira.grammar-tool</artifactId>
     <packaging>jar</packaging>
     <packaging>jar</packaging>
 
 
     <name>${project.groupId}:${project.artifactId}</name>
     <name>${project.groupId}:${project.artifactId}</name>
@@ -20,28 +20,8 @@
         <maven.compiler.source>1.8</maven.compiler.source>
         <maven.compiler.source>1.8</maven.compiler.source>
         <maven.compiler.target>1.8</maven.compiler.target>
         <maven.compiler.target>1.8</maven.compiler.target>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-
-        <!-- this is last version of "antlr4" artifact compatible with JDK 8 (ANTLR 4 Tool) -->
-        <antlr.version>4.9.3</antlr.version>
     </properties>
     </properties>
 
 
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.antlr</groupId>
-                <artifactId>antlr4-maven-plugin</artifactId>
-                <version>${antlr.version}</version>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>antlr4</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-
     <dependencies>
     <dependencies>
         <dependency>
         <dependency>
             <groupId>net.ranides</groupId>
             <groupId>net.ranides</groupId>
@@ -63,12 +43,10 @@
         <dependency>
         <dependency>
             <groupId>org.antlr</groupId>
             <groupId>org.antlr</groupId>
             <artifactId>antlr4-runtime</artifactId>
             <artifactId>antlr4-runtime</artifactId>
-            <version>${antlr.version}</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>org.antlr</groupId>
             <groupId>org.antlr</groupId>
             <artifactId>antlr4</artifactId>
             <artifactId>antlr4</artifactId>
-            <version>${antlr.version}</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <groupId>org.slf4j</groupId>

+ 32 - 8
assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/ParserInterpreted.java

@@ -1,8 +1,8 @@
-package net.ranides.assira.grammar.impl.antlr;
-
+package net.ranides.assira.grammar.impl;
 
 
 import net.ranides.assira.collection.maps.CrossMap;
 import net.ranides.assira.collection.maps.CrossMap;
 import net.ranides.assira.collection.maps.OpenCrossMap;
 import net.ranides.assira.collection.maps.OpenCrossMap;
+import net.ranides.assira.collection.sets.OpenSet;
 import net.ranides.assira.grammar.G4Node;
 import net.ranides.assira.grammar.G4Node;
 import net.ranides.assira.grammar.G4Parser;
 import net.ranides.assira.grammar.G4Parser;
 import net.ranides.assira.generic.Ref;
 import net.ranides.assira.generic.Ref;
@@ -14,6 +14,7 @@ import org.antlr.v4.runtime.CharStreams;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.LexerInterpreter;
 import org.antlr.v4.runtime.LexerInterpreter;
 import org.antlr.v4.runtime.ParserInterpreter;
 import org.antlr.v4.runtime.ParserInterpreter;
+import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.misc.Pair;
 import org.antlr.v4.runtime.misc.Pair;
 import org.antlr.v4.runtime.tree.RuleNode;
 import org.antlr.v4.runtime.tree.RuleNode;
 import org.antlr.v4.tool.Alternative;
 import org.antlr.v4.tool.Alternative;
@@ -26,20 +27,29 @@ import org.antlr.v4.tool.ast.GrammarAST;
 import java.util.List;
 import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.NoSuchElementException;
+import java.util.Set;
 
 
-public class ParserInterpreted implements G4Parser {
+public class G4ParserInterpreter implements G4Parser {
 
 
     protected final Grammar grammar;
     protected final Grammar grammar;
 
 
     private final CrossMap<Integer, Integer, String> branchLabels;
     private final CrossMap<Integer, Integer, String> branchLabels;
 
 
+    private final Set<String> branchValidator;
+
     private final CrossMap<String, String, Integer> expressionLabels;
     private final CrossMap<String, String, Integer> expressionLabels;
 
 
-    public ParserInterpreted(String grammar) {
+    public G4ParserInterpreter(String grammar) {
         try {
         try {
             this.grammar = new Grammar(grammar);
             this.grammar = new Grammar(grammar);
             this.branchLabels = deduceBranchLabels(this.grammar);
             this.branchLabels = deduceBranchLabels(this.grammar);
             this.expressionLabels = deduceExpressionLabels(this.grammar);
             this.expressionLabels = deduceExpressionLabels(this.grammar);
+
+            this.branchValidator = new OpenSet<>();
+            branchLabels.forEach((ruleIndex, alt, label)-> {
+                branchValidator.add(NodeSupport.QUALIFIER_NAME + label);
+                branchValidator.add(ruleName(ruleIndex) + NodeSupport.QUALIFIER_NAME + label);
+            });
         } catch (RecognitionException e) {
         } catch (RecognitionException e) {
             throw new RuntimeException(e);
             throw new RuntimeException(e);
         }
         }
@@ -132,6 +142,20 @@ public class ParserInterpreted implements G4Parser {
         throw new UnsupportedOperationException("Awkward label '" + labelName + "' inside rule: " + ruleName);
         throw new UnsupportedOperationException("Awkward label '" + labelName + "' inside rule: " + ruleName);
     }
     }
 
 
+    @Override
+    public boolean validateRuleName(String ruleName) {
+        if(ruleName.contains("#")) {
+            return branchValidator.contains(ruleName);
+        } else {
+            return grammar.getRule(ruleName) != null;
+        }
+    }
+
+    @Override
+    public boolean validateTokenName(String tokenName) {
+        return grammar.getTokenType(tokenName) != Token.INVALID_TYPE;
+    }
+
     @Override
     @Override
     public String ruleName(int ruleIndex) {
     public String ruleName(int ruleIndex) {
         return grammar.getRule(ruleIndex).name;
         return grammar.getRule(ruleIndex).name;
@@ -157,11 +181,11 @@ public class ParserInterpreted implements G4Parser {
         private final NodeForRule tree;
         private final NodeForRule tree;
 
 
         public MyRoot(String ruleName, String text) {
         public MyRoot(String ruleName, String text) {
-            LexerInterpreter lexer = ParserInterpreted.this.grammar.createLexerInterpreter(CharStreams.fromString(text));
+            LexerInterpreter lexer = G4ParserInterpreter.this.grammar.createLexerInterpreter(CharStreams.fromString(text));
             CommonTokenStream tokens = new CommonTokenStream(lexer);
             CommonTokenStream tokens = new CommonTokenStream(lexer);
-            ParserInterpreter interpreter = ParserInterpreted.this.grammar.createGrammarParserInterpreter(tokens);
+            ParserInterpreter interpreter = G4ParserInterpreter.this.grammar.createGrammarParserInterpreter(tokens);
 
 
-            Rule rule = ParserInterpreted.this.grammar.getRule(ruleName);
+            Rule rule = G4ParserInterpreter.this.grammar.getRule(ruleName);
             if (rule == null) {
             if (rule == null) {
                 throw new IllegalArgumentException("Unknown rule: " + ruleName);
                 throw new IllegalArgumentException("Unknown rule: " + ruleName);
             }
             }
@@ -171,7 +195,7 @@ public class ParserInterpreted implements G4Parser {
 
 
         @Override
         @Override
         public G4Parser parser() {
         public G4Parser parser() {
-            return ParserInterpreted.this;
+            return G4ParserInterpreter.this;
         }
         }
 
 
         @Override
         @Override

+ 72 - 0
assira.grammar-tool/src/test/java/net/ranides/assira/grammar/InspectionTest.java

@@ -0,0 +1,72 @@
+package net.ranides.assira.grammar;
+
+import net.ranides.assira.collection.query.CQuery;
+import net.ranides.assira.io.ResourceUtils;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class InspectionTest {
+
+
+    @Test
+    public void stream() throws IOException {
+        G4Parser parser = G4Parser.newInstance(ResourceUtils.text("Calculator.g4"));
+
+        G4Node tree = parser.parse("expression", "(1 + 2) * 3 + 4^2");
+
+        List<String> list1 = CQuery.from().tree(() -> tree, v -> v.children())
+            .map(v -> v.name())
+            .sort()
+            .list();
+        List<String> list2 = CQuery.from().tree(() -> tree, v -> v.children())
+            .map(v -> v.name())
+            .distinct()
+            .sort()
+            .list();
+        List<String> list3 = CQuery.from().tree(() -> tree, v -> v.children(), v -> v.shortname().equals("number"))
+            .map(v -> v.name())
+            .distinct()
+            .sort()
+            .list();
+
+        assertTrue(list1.containsAll(list2));
+        assertTrue(list2.containsAll(list3));
+
+        assertEquals(
+            Arrays.asList(
+                "SYMBOL_ADD", "SYMBOL_LB", "SYMBOL_MUL", "SYMBOL_POW", "SYMBOL_RB",
+                "expression#expr_1", "expression#expr_2", "expression#expr_3",
+                "expression#expr_bracket", "expression#expr_number",
+                "number$1",
+                "operator1$1", "operator2#opmul", "operator3$1",
+                "operatorAdd$1", "operatorMul$1", "operatorPow$1"
+            ),
+            list3
+        );
+    }
+
+    @Test
+    public void printTree() throws IOException {
+        G4Parser parser = G4Parser.newInstance(ResourceUtils.text("Calculator.g4"));
+
+        G4Node tree1 = parser.parse("expression", "(4 + 2) * 3 ");
+
+        assertEquals(ResourceUtils.text("Calculator.tree.txt"), G4Support.printTree(tree1));
+    }
+
+    @Test
+    public void printPaths() throws IOException {
+        G4Parser g4 = G4Parser.newInstance(ResourceUtils.text("Calculator.g4"));
+
+        G4Node tree = g4.parse("expression", "(4 + 2) * 3 ");
+
+        assertEquals(ResourceUtils.text("Calculator.paths.txt"), G4Support.printPath(tree));
+    }
+
+}

+ 67 - 0
assira.grammar-tool/src/test/java/net/ranides/assira/grammar/LabelTest.java

@@ -0,0 +1,67 @@
+package net.ranides.assira.grammar;
+
+import net.ranides.assira.grammar.impl.G4ParserInterpreter;
+import net.ranides.assira.io.ResourceUtils;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.NoSuchElementException;
+
+import static net.ranides.assira.junit.NewAssert.assertThrows;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class LabelTest {
+
+    @Test
+    public void labelForExpressions() throws IOException {
+        G4Parser parser = new G4ParserInterpreter(ResourceUtils.text("LabelTest.g4"));
+
+        G4Node expr1 = parser.parse("manyLabels", "! ( 2 3 + 4 + 5 6 !");
+        assertEquals("2", expr1.child("@num1").text());
+        assertEquals("3", expr1.child("@num2").text());
+        assertEquals("5", expr1.child("@num4").text());
+        assertEquals("6", expr1.child("@num5").text());
+
+        G4Node expr2 = parser.parse("functionCall", "hello(1,2,3,4)");
+        assertEquals("1,2,3,4", expr2.child("@args").text());
+
+        G4Node expr3 = parser.parse("withToken", "((16))");
+        assertEquals("16", expr3.child("@value").text());
+
+        testLabelExpression(parser, "withLabels");
+        testLabelExpression(parser, "withoutLabels");
+        testLabelExpression(parser, "withoutLabelsRecursive");
+    }
+
+    private void testLabelExpression(G4Parser parser, String rule) {
+
+        G4Node expr2 = parser.parse(rule, "-5");
+        assertEquals("5", expr2.child("@a").text());
+        assertThrows(NoSuchElementException.class, () -> {
+            expr2.child("@b");
+        });
+
+        G4Node expr3 = parser.parse(rule, "(1+5) & 8");
+        assertEquals("(1+5)", expr3.child("@a").text());
+        assertEquals("8", expr3.child("@b").text());
+
+        G4Node expr4 = parser.parse(rule, "(1+5) * 8");
+        assertEquals("(1+5)", expr4.child("@b").text());
+        assertEquals("8", expr4.child("@a").text());
+
+        G4Node expr5 = parser.parse(rule, "(1+5) + 8");
+        assertEquals("(1+5)", expr5.child("@x").text());
+        assertEquals("8", expr5.child("@y").text());
+
+        G4Node expr6 = parser.parse(rule, "? 1 2 3");
+        assertEquals("1", expr6.child("@p").text());
+        assertEquals("2", expr6.child("@q").text());
+        assertEquals("3", expr6.child("@r").text());
+    }
+
+    // @todo G4Parser should have "coverage mode" for each rule and rule branch
+
+
+}

+ 2 - 2
assira.grammar/src/test/java/net/ranides/assira/grammar/G4NodeTest.java

@@ -9,10 +9,10 @@ import java.util.List;
 
 
 import static org.junit.Assert.*;
 import static org.junit.Assert.*;
 
 
-public class G4NodeTest {
+public class NodeTest {
 
 
     @Test
     @Test
-    public void testFind() throws IOException {
+    public void findAll() throws IOException {
         G4Parser parser = G4Parser.newInstance(ResourceUtils.text("Calculator.g4"));
         G4Parser parser = G4Parser.newInstance(ResourceUtils.text("Calculator.g4"));
 
 
         G4Selector<Number> num1 = new G4SelectorBuilder<Number>()
         G4Selector<Number> num1 = new G4SelectorBuilder<Number>()

+ 56 - 5
assira.grammar/src/test/java/net/ranides/assira/grammar/G4SelectorTest.java

@@ -1,6 +1,8 @@
 package net.ranides.assira.grammar;
 package net.ranides.assira.grammar;
 
 
+import net.ranides.assira.grammar.impl.G4ParserInterpreter;
 import net.ranides.assira.io.ResourceUtils;
 import net.ranides.assira.io.ResourceUtils;
+import net.ranides.assira.junit.NewAssert;
 import org.junit.Test;
 import org.junit.Test;
 
 
 import java.io.IOException;
 import java.io.IOException;
@@ -11,7 +13,7 @@ import java.util.NoSuchElementException;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertThrows;
 
 
-public class G4SelectorTest {
+public class SelectorTest {
 
 
     static final G4Selector<Number> num1 = new G4SelectorBuilder<Number>()
     static final G4Selector<Number> num1 = new G4SelectorBuilder<Number>()
         .withName("number")
         .withName("number")
@@ -36,13 +38,13 @@ public class G4SelectorTest {
 
 
     @Test
     @Test
     public void compose() throws IOException {
     public void compose() throws IOException {
-        G4Parser parser = G4Parser.newInstance(ResourceUtils.text("Calculator.g4"));
+        G4Parser parser = new G4ParserInterpreter(ResourceUtils.text("Calculator.g4"));
         assertEquals(34, ops1.first(parser.parse("expression", "2*3 + 7*4")).intValue() );
         assertEquals(34, ops1.first(parser.parse("expression", "2*3 + 7*4")).intValue() );
     }
     }
 
 
     @Test
     @Test
     public void skip() throws IOException {
     public void skip() throws IOException {
-        G4Parser parser = G4Parser.newInstance(ResourceUtils.text("SkipTest.g4"));
+        G4Parser parser = new G4ParserInterpreter(ResourceUtils.text("SkipTest.g4"));
 
 
         G4Selector<Integer> num1 = new G4SelectorBuilder<Integer>()
         G4Selector<Integer> num1 = new G4SelectorBuilder<Integer>()
             .withName("number")
             .withName("number")
@@ -64,7 +66,7 @@ public class G4SelectorTest {
 
 
     @Test
     @Test
     public void findIf() throws IOException {
     public void findIf() throws IOException {
-        G4Parser parser = G4Parser.newInstance(ResourceUtils.text("Calculator.g4"));
+        G4Parser parser = new G4ParserInterpreter(ResourceUtils.text("Calculator.g4"));
 
 
         G4Selector<Number> num1 = new G4SelectorBuilder<Number>()
         G4Selector<Number> num1 = new G4SelectorBuilder<Number>()
             .withName("number")
             .withName("number")
@@ -97,7 +99,7 @@ public class G4SelectorTest {
 
 
     @Test
     @Test
     public void nested() throws IOException {
     public void nested() throws IOException {
-        G4Parser parser = G4Parser.newInstance(ResourceUtils.text("Calculator.g4"));
+        G4Parser parser = new G4ParserInterpreter(ResourceUtils.text("Calculator.g4"));
 
 
         G4Selector<Number> selectNum = new G4SelectorBuilder<Number>()
         G4Selector<Number> selectNum = new G4SelectorBuilder<Number>()
             .withName("number")
             .withName("number")
@@ -142,4 +144,53 @@ public class G4SelectorTest {
         assertEquals(5, selectExpression.first(parser.parse("expression", "(6 + 9) / 3")).intValue());
         assertEquals(5, selectExpression.first(parser.parse("expression", "(6 + 9) / 3")).intValue());
     }
     }
 
 
+    @Test
+    public void wrongSelector() throws IOException {
+        G4Parser parser = new G4ParserInterpreter(ResourceUtils.text("Calculator.g4"));
+
+        // without validation: will not throw
+        new G4SelectorBuilder<Number>()
+            .withName("number")
+            .mapRule("numberInt", node -> Integer.parseInt(node.text()))
+            .mapRule("numberReal", node -> Double.parseDouble(node.text()))
+            .mapRule("stupidRule", node -> 0)
+            .mapRule("expression#expr_bracket", node -> 0) // correct
+            .mapRule("#expr_bracket", node -> 0) // correct
+            .mapRule("expression#stupid", node -> 0) // stupid
+            .mapRule("numberInt#expr_bracket", node -> 0) // stupid
+            .mapRule("#stupid", node -> 0) // stupid
+
+            .prepare();
+
+        NewAssert.assertThrows(e -> e.getMessage().contains("stupidRule"), () -> {
+            new G4SelectorBuilder<Number>()
+                .withName("number")
+                .withParser(parser)
+                .mapRule("numberReal", node -> Double.parseDouble(node.text()))
+                .mapRule("stupidRule", node -> 0)
+                .prepare();
+        });
+
+        NewAssert.assertThrows(e -> e.getMessage().contains("stupid_branch"), () -> {
+            new G4SelectorBuilder<Number>()
+                .withName("number")
+                .withParser(parser)
+                .mapRule("expression#expr_bracket", node -> 0) // correct
+                .mapRule("#expr_bracket", node -> 0) // correct
+                .mapRule("expression#stupid_branch", node -> 0) // stupid
+                .prepare();
+        });
+
+        NewAssert.assertThrows(e -> e.getMessage().contains("expression#opmul"), () -> {
+            new G4SelectorBuilder<Number>()
+                .withName("number")
+                .withParser(parser)
+                .mapRule("operator2#opmul", node -> 0) // correct
+                .mapRule("#opmul", node -> 0) // correct
+                .mapRule("expression#opmul", node -> 0) // stupid
+                .prepare();
+        });
+
+    }
+
 }
 }

+ 2 - 2
assira.grammar/src/test/resources/Calculator.g4

@@ -38,8 +38,8 @@ operator1
     ;
     ;
 
 
 operator2
 operator2
-    : operatorMul
-    | operatorDiv
+    : operatorMul #opmul
+    | operatorDiv #opdiv
     ;
     ;
 
 
 operator3
 operator3

assira.grammar/src/test/resources/Calculator.paths.txt → assira.grammar-tool/src/test/resources/Calculator.paths.txt


+ 1 - 1
assira.grammar/src/test/resources/Calculator.tree.txt

@@ -14,7 +14,7 @@ expression#expr_2 = '(4 + 2) * 3'
                numberInt$1 = '2'
                numberInt$1 = '2'
                   NUMBER_INT = '2'
                   NUMBER_INT = '2'
       SYMBOL_RB = ')'
       SYMBOL_RB = ')'
-   operator2$1 = '*'
+   operator2#opmul = '*'
       operatorMul$1 = '*'
       operatorMul$1 = '*'
          SYMBOL_MUL = '*'
          SYMBOL_MUL = '*'
    expression#expr_number = '3'
    expression#expr_number = '3'

assira.grammar/src/test/resources/LabelTest.g4 → assira.grammar-tool/src/test/resources/LabelTest.g4


assira.grammar/src/test/resources/SkipTest.g4 → assira.grammar-tool/src/test/resources/SkipTest.g4


+ 0 - 65
assira.grammar/src/main/antlr4/net/ranides/grammars/CssColors.g4

@@ -1,65 +0,0 @@
-grammar CssColors;
-
-colors
-    : color+
-    ;
-
-color
-    : hslColor
-    | hslaColor
-    | rgbColor
-    | rgbaColor
-    | hexColor
-    ;
-
-hslColor
-    : HSL LP h=numberInt CS s=numberPct CS l=numberPct RP
-    ;
-
-hslaColor
-    : HSL LP h=numberInt CS s=numberPct CS l=numberPct CS alpha=NUMBER_REAL RP
-    ;
-
-rgbColor
-    : RGB LP r=numberInt CS g=numberInt CS b=numberInt RP
-    ;
-
-rgbaColor
-    : RGBA LP r=numberInt CS g=numberInt CS b=numberInt CS alpha=NUMBER_REAL RP
-    ;
-
-hexColor
-    : NUMBER_HEX3   #hexColor3
-    | NUMBER_HEX6   #hexColor6
-    ;
-
-numberPct : NUMBER_PCT;
-
-numberInt : NUMBER_INT;
-
-NUMBER_HEX6: HEX_PREFIX HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT;
-NUMBER_HEX3: HEX_PREFIX HEX_DIGIT HEX_DIGIT HEX_DIGIT;
-
-NUMBER_REAL : INT_DIGIT* FS INT_DIGIT*;
-
-NUMBER_PCT: INT_DIGIT+ '%';
-
-NUMBER_INT: INT_DIGIT+ ;
-
-LP: '(';
-RP: ')';
-CS: ',';
-FS: '.';
-
-RGB: 'rgb';
-RGBA: 'rgba';
-HSL: 'hsl';
-HSLA: 'hsla';
-
-fragment HEX_PREFIX: '#';
-
-fragment HEX_DIGIT: ('0'..'9' | 'a'..'f' | 'A'..'F');
-
-fragment INT_DIGIT: '0'..'9';
-
-WS :  [ \t\r\n]+ -> skip ;

+ 0 - 101
assira.grammar/src/main/java/net/ranides/assira/grammar/impl/antlr/ParserGenerated.java

@@ -1,101 +0,0 @@
-package net.ranides.assira.grammar.impl.antlr;
-
-import net.ranides.assira.grammar.G4Node;
-import net.ranides.assira.grammar.G4Parser;
-import net.ranides.assira.generic.Ref;
-import net.ranides.assira.reflection.IClass;
-import net.ranides.assira.reflection.IMethod;
-import net.ranides.assira.text.StringUtils;
-import org.antlr.v4.runtime.CharStreams;
-import org.antlr.v4.runtime.CommonTokenStream;
-import org.antlr.v4.runtime.Lexer;
-import org.antlr.v4.runtime.Parser;
-import org.antlr.v4.runtime.tree.RuleNode;
-
-public class ParserGenerated implements G4Parser  {
-
-    protected final IClass<? extends Lexer> lexer;
-
-    protected final IClass<? extends Parser> parser;
-
-    private final String[] lexerRules;
-
-    private final String[] parserRules;
-
-    public ParserGenerated(IClass<? extends Lexer> lexer, IClass<? extends Parser> parser) {
-        this.lexer = lexer;
-        this.parser = parser;
-
-        this.lexerRules = (String[])lexer.field("ruleNames").get().get(null);
-        this.parserRules = (String[])parser.field("ruleNames").get().get(null);
-    }
-
-    @Override
-    public G4Node parse(String rule, String text) {
-        return new MyRoot(rule, text).tree();
-    }
-
-    @Override
-    public String ruleName(int ruleIndex) {
-        return parserRules[ruleIndex];
-    }
-
-    @Override
-    public String ruleName(Class<?> ruleType) {
-        return StringUtils.uncapitalize(ruleType.getSimpleName().replaceAll("Context$", ""));
-    }
-
-    @Override
-    public String tokenName(int tokenIndex) {
-        return lexerRules[tokenIndex-1];
-    }
-
-    private class MyRoot extends RootAbstract {
-
-        private final NodeForRule tree;
-
-        public MyRoot(String ruleName, String text) {
-            Lexer lexer = ParserGenerated.this.lexer.construct(CharStreams.fromString(text));
-            CommonTokenStream tokens = new CommonTokenStream(lexer);
-            Parser interpreter = ParserGenerated.this.parser.construct(tokens);
-
-            IMethod rule = ParserGenerated.this.parser
-                .method(ruleName)
-                .orElseThrow(() -> new IllegalArgumentException("Unknown rule: " + ruleName));
-
-            this.tree = new NodeForRule(this, null, (RuleNode)rule.call(interpreter));
-        }
-
-        @Override
-        public G4Parser parser() {
-            return ParserGenerated.this;
-        }
-
-        @Override
-        public G4Node tree() {
-            return tree;
-        }
-
-        @Override
-        public String branchName(G4Node g4node) {
-            Object node = g4node.unwrap();
-            Class<?> type = node.getClass();
-            if(type.getSuperclass().getDeclaringClass() == null) {
-                return NodeSupport.QUALIFIER_INDEX_DEFAULT;
-            } else {
-                String typename = type.getSimpleName();
-                return NodeSupport.QUALIFIER_NAME + StringUtils.uncapitalize(typename.replaceAll("Context$", ""));
-            }
-        }
-
-        @Override
-        public Ref<G4Node> findLabel(G4Node g4node, String labelName) {
-            Object node = g4node.unwrap();
-            return IClass.typefor(node)
-                .field(labelName)
-                .map(f -> f.get(node))
-                .map(t -> wrap(g4node, t));
-        }
-
-    }
-}

+ 0 - 123
assira.grammar/src/test/java/net/ranides/assira/grammar/G4ParserTest.java

@@ -1,123 +0,0 @@
-package net.ranides.assira.grammar;
-
-import net.ranides.assira.collection.query.CQuery;
-import net.ranides.assira.io.ResourceUtils;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-import static net.ranides.assira.junit.NewAssert.assertThrows;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-public class G4ParserTest {
-
-    @Test
-    public void testLabelExpressions() throws IOException {
-        G4Parser parser = G4Parser.newInstance(ResourceUtils.text("LabelTest.g4"));
-
-        G4Node expr1 = parser.parse("manyLabels", "! ( 2 3 + 4 + 5 6 !");
-        assertEquals("2", expr1.child("@num1").text());
-        assertEquals("3", expr1.child("@num2").text());
-        assertEquals("5", expr1.child("@num4").text());
-        assertEquals("6", expr1.child("@num5").text());
-
-        G4Node expr2 = parser.parse("functionCall", "hello(1,2,3,4)");
-        assertEquals("1,2,3,4", expr2.child("@args").text());
-
-        G4Node expr3 = parser.parse("withToken", "((16))");
-        assertEquals("16", expr3.child("@value").text());
-
-        testLabelExpression(parser, "withLabels");
-        testLabelExpression(parser, "withoutLabels");
-        testLabelExpression(parser, "withoutLabelsRecursive");
-    }
-
-    private void testLabelExpression(G4Parser parser, String rule) {
-
-        G4Node expr2 = parser.parse(rule, "-5");
-        assertEquals("5", expr2.child("@a").text());
-        assertThrows(NoSuchElementException.class, () -> {
-            expr2.child("@b");
-        });
-
-        G4Node expr3 = parser.parse(rule, "(1+5) & 8");
-        assertEquals("(1+5)", expr3.child("@a").text());
-        assertEquals("8", expr3.child("@b").text());
-
-        G4Node expr4 = parser.parse(rule, "(1+5) * 8");
-        assertEquals("(1+5)", expr4.child("@b").text());
-        assertEquals("8", expr4.child("@a").text());
-
-        G4Node expr5 = parser.parse(rule, "(1+5) + 8");
-        assertEquals("(1+5)", expr5.child("@x").text());
-        assertEquals("8", expr5.child("@y").text());
-
-        G4Node expr6 = parser.parse(rule, "? 1 2 3");
-        assertEquals("1", expr6.child("@p").text());
-        assertEquals("2", expr6.child("@q").text());
-        assertEquals("3", expr6.child("@r").text());
-    }
-
-    // @todo G4Parser should have "coverage mode" for each rule and rule branch
-
-    @Test
-    public void testStream() throws IOException {
-        G4Parser parser = G4Parser.newInstance(ResourceUtils.text("Calculator.g4"));
-
-        G4Node tree = parser.parse("expression", "(1 + 2) * 3 + 4^2");
-
-        List<String> list1 = CQuery.from().tree(() -> tree, v -> v.children())
-            .map(v -> v.name())
-            .sort()
-            .list();
-        List<String> list2 = CQuery.from().tree(() -> tree, v -> v.children())
-            .map(v -> v.name())
-            .distinct()
-            .sort()
-            .list();
-        List<String> list3 = CQuery.from().tree(() -> tree, v -> v.children(), v -> v.shortname().equals("number"))
-            .map(v -> v.name())
-            .distinct()
-            .sort()
-            .list();
-
-        assertTrue(list1.containsAll(list2));
-        assertTrue(list2.containsAll(list3));
-
-        assertEquals(
-            Arrays.asList(
-                "SYMBOL_ADD", "SYMBOL_LB", "SYMBOL_MUL", "SYMBOL_POW", "SYMBOL_RB",
-                "expression#expr_1", "expression#expr_2", "expression#expr_3",
-                "expression#expr_bracket", "expression#expr_number",
-                "number$1",
-                "operator1$1", "operator2$1", "operator3$1",
-                "operatorAdd$1", "operatorMul$1", "operatorPow$1"
-            ),
-            list3
-        );
-    }
-
-    @Test
-    public void printTree() throws IOException {
-        G4Parser parser = G4Parser.newInstance(ResourceUtils.text("Calculator.g4"));
-
-        G4Node tree1 = parser.parse("expression", "(4 + 2) * 3 ");
-
-        assertEquals(ResourceUtils.text("Calculator.tree.txt"), G4Support.printTree(tree1));
-    }
-
-    @Test
-    public void printPaths() throws IOException {
-        G4Parser g4 = G4Parser.newInstance(ResourceUtils.text("Calculator.g4"));
-
-        G4Node tree = g4.parse("expression", "(4 + 2) * 3 ");
-
-        assertEquals(ResourceUtils.text("Calculator.paths.txt"), G4Support.printPath(tree));
-    }
-
-
-}

+ 0 - 94
assira.grammar/src/test/java/net/ranides/assira/grammars/CssColorsTest.java

@@ -1,94 +0,0 @@
-package net.ranides.assira.grammars;
-
-import net.ranides.assira.awt.ColorUtils;
-import net.ranides.assira.grammar.G4Node;
-import net.ranides.assira.grammar.G4Parser;
-import net.ranides.assira.grammar.G4Selector;
-import net.ranides.assira.grammar.G4SelectorBuilder;
-import net.ranides.assira.grammar.G4Support;
-import net.ranides.assira.io.ResourceUtils;
-import net.ranides.grammars.CssColorsLexer;
-import net.ranides.grammars.CssColorsParser;
-import org.junit.Test;
-
-import java.awt.*;
-import java.io.IOException;
-
-import static net.ranides.assira.junit.NewAssert.assertThrows;
-import static org.junit.Assert.assertEquals;
-
-public class CssColorsTest {
-
-    @Test
-    public void basic() throws IOException {
-        G4Parser gp = G4Parser.newInstance(CssColorsLexer.class, CssColorsParser.class);
-
-        G4Node out = gp.parse("color", "rgba(15,20,30,0.75)");
-
-        assertEquals(ResourceUtils.text("CssColors.tree.txt"), G4Support.printTree(out));
-        assertEquals(ResourceUtils.text("CssColors.paths.txt"), G4Support.printPath(out));
-
-        assertEquals("rgba(15,20,30,0.75)", out.child("rgbaColor").text());
-        assertEquals("0.75", out.child("rgbaColor").child("@alpha").text());
-
-        assertEquals("color/rgbaColor/NUMBER_REAL", out.find("rgbaColor/@alpha").path());
-
-        assertThrows(e -> e.getMessage().contains("There is no path 'rgbaColor/@unknown' inside node 'color$0=rgba(15,20,30,0.75)'"), () -> {
-            out.find("rgbaColor/@unknown").path();
-        });
-
-        assertThrows(e -> e.getMessage().contains("There is no path 'unknown' inside node 'color/rgbaColor$0=rgba(15,20,30,0.75)'"), () -> {
-            out.child("rgbaColor").find("unknown").path();
-        });
-    }
-
-    @Test
-    public void evaluator() {
-
-        G4Parser parser = G4Parser.newInstance(CssColorsLexer.class, CssColorsParser.class);
-
-        G4Selector<Color> selector = new G4SelectorBuilder<Color>()
-            .withName("selector:color")
-            .withParser(parser)
-            .mapRule(CssColorsParser.RgbColorContext.class, node -> {
-                int r = Integer.parseInt(node.r.getText());
-                int g = Integer.parseInt(node.g.getText());
-                int b = Integer.parseInt(node.b.getText());
-
-                return new Color(r, g, b);
-            })
-            .mapRule("rgbaColor", node -> {
-                int r = Integer.parseInt(node.child("@r").text());
-                int g = Integer.parseInt(node.child("@g").text());
-                int b = Integer.parseInt(node.child("@b").text());
-                int alpha = Math.round(255 * Float.parseFloat(node.child("@alpha").text()));
-
-                return new Color(r, g, b, alpha);
-            })
-            .mapRule("hexColor#hexColor3", v -> {
-                int r = 17 * Integer.parseInt(v.text().substring(1,2), 16);
-                int g = 17 * Integer.parseInt(v.text().substring(2,3), 16);
-                int b = 17 * Integer.parseInt(v.text().substring(3,4), 16);
-
-                return new Color(r, g, b);
-            })
-            .mapRule("hexColor#hexColor6", v -> {
-                int r = Integer.parseInt(v.text().substring(1,3), 16);
-                int g = Integer.parseInt(v.text().substring(3,5), 16);
-                int b = Integer.parseInt(v.text().substring(5,7), 16);
-
-                return new Color(r, g, b);
-            })
-
-            .prepare();
-
-        assertEquals("rgba(15,20,30,0.75)", ColorUtils.asCSS3(selector.first(parser.parse("color", "rgba ( 15, 20, 30, 0.75 )"))));
-        assertEquals("rgb(15,20,30)", ColorUtils.asCSS3(selector.first(parser.parse("color", "rgb(15,20,30)"))));
-        assertEquals("#f08040", ColorUtils.asCSS2(selector.first(parser.parse("color", "#f08040"))));
-
-        assertEquals(
-            "#5080a0 #324668 #778899",
-            selector.stream(parser.parse("colors", "rgb ( 80, 128, 160 ) #324668 #789")).map(ColorUtils::asCSS2).join(" ")
-        );
-    }
-}

+ 0 - 15
assira.grammar/src/test/resources/CssColors.paths.txt

@@ -1,15 +0,0 @@
-color = 'rgba(15,20,30,0.75)'
-color/rgbaColor = 'rgba(15,20,30,0.75)'
-color/rgbaColor/RGBA = 'rgba'
-color/rgbaColor/LP = '('
-color/rgbaColor/numberInt[0] = '15'
-color/rgbaColor/numberInt[0]/NUMBER_INT = '15'
-color/rgbaColor/CS[0] = ','
-color/rgbaColor/numberInt[1] = '20'
-color/rgbaColor/numberInt[1]/NUMBER_INT = '20'
-color/rgbaColor/CS[1] = ','
-color/rgbaColor/numberInt[2] = '30'
-color/rgbaColor/numberInt[2]/NUMBER_INT = '30'
-color/rgbaColor/CS[2] = ','
-color/rgbaColor/NUMBER_REAL = '0.75'
-color/rgbaColor/RP = ')'

+ 0 - 15
assira.grammar/src/test/resources/CssColors.tree.txt

@@ -1,15 +0,0 @@
-color$0 = 'rgba(15,20,30,0.75)'
-   rgbaColor$0 = 'rgba(15,20,30,0.75)'
-      RGBA = 'rgba'
-      LP = '('
-      numberInt$0 = '15'
-         NUMBER_INT = '15'
-      CS = ','
-      numberInt$0 = '20'
-         NUMBER_INT = '20'
-      CS = ','
-      numberInt$0 = '30'
-         NUMBER_INT = '30'
-      CS = ','
-      NUMBER_REAL = '0.75'
-      RP = ')'

+ 4 - 3
assira.xls/src/main/java/net/ranides/assira/xls/XLSReader.java

@@ -1,5 +1,6 @@
 package net.ranides.assira.xls;
 package net.ranides.assira.xls;
 
 
+import net.ranides.assira.generic.Ref;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
@@ -106,12 +107,12 @@ public class XLSReader {
         return this;
         return this;
     }
     }
 
 
-    public Optional<Row> header() {
+    public Ref<Row> header() {
         return header(false);
         return header(false);
     }
     }
 
 
-    public Optional<Row> header(boolean force) {
-        return force || detectHeader() ? IteratorUtils.first(sh.iterator()) : Optional.empty();
+    public Ref<Row> header(boolean force) {
+        return force || detectHeader() ? IteratorUtils.first(sh.iterator()) : Ref.empty();
     }
     }
 
 
     public CQuery<Row> rows(){
     public CQuery<Row> rows(){

+ 2 - 1
assira.xls/src/main/java/net/ranides/assira/xls/XLSUtils.java

@@ -3,6 +3,7 @@ package net.ranides.assira.xls;
 import lombok.Data;
 import lombok.Data;
 import lombok.RequiredArgsConstructor;
 import lombok.RequiredArgsConstructor;
 import lombok.experimental.UtilityClass;
 import lombok.experimental.UtilityClass;
+import net.ranides.assira.generic.Ref;
 import org.apache.poi.hssf.usermodel.HSSFCellStyle;
 import org.apache.poi.hssf.usermodel.HSSFCellStyle;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.hssf.util.HSSFColor;
 import org.apache.poi.hssf.util.HSSFColor;
@@ -22,7 +23,7 @@ import java.util.Optional;
 @UtilityClass
 @UtilityClass
 public class XLSUtils {
 public class XLSUtils {
 
 
-    public static List<String> text(Optional<Row> row) {
+    public static List<String> text(Ref<Row> row) {
         return text(row.orElse(null));
         return text(row.orElse(null));
     }
     }
 
 

+ 13 - 1
pom.xml

@@ -50,6 +50,8 @@
         <assira.junit.debug>false</assira.junit.debug>
         <assira.junit.debug>false</assira.junit.debug>
         <assira.junit.logger.level>debug</assira.junit.logger.level>
         <assira.junit.logger.level>debug</assira.junit.logger.level>
 
 
+        <!-- this is last version of "antlr4" artifact compatible with JDK 8 (ANTLR 4 Tool) -->
+        <antlr.version>4.9.3</antlr.version>
 
 
         <org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>none</org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>
         <org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>none</org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>
         <org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>
         <org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>
@@ -80,7 +82,7 @@
                 <module>assira.commons</module>
                 <module>assira.commons</module>
                 <module>assira.enterprise</module>
                 <module>assira.enterprise</module>
                 <module>assira.xls</module>
                 <module>assira.xls</module>
-                <module>assira.grammar</module>
+                <module>assira.grammar-tool</module>
             </modules>
             </modules>
         </profile>
         </profile>
         <profile>
         <profile>
@@ -353,6 +355,16 @@
                 <version>1.18.20</version>
                 <version>1.18.20</version>
                 <scope>provided</scope>
                 <scope>provided</scope>
             </dependency>
             </dependency>
+            <dependency>
+                <groupId>org.antlr</groupId>
+                <artifactId>antlr4-runtime</artifactId>
+                <version>${antlr.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.antlr</groupId>
+                <artifactId>antlr4</artifactId>
+                <version>${antlr.version}</version>
+            </dependency>
         </dependencies>
         </dependencies>
     </dependencyManagement>
     </dependencyManagement>