Explorar o código

load interpreted grammar with imports

Ranides Atterwim %!s(int64=2) %!d(string=hai) anos
pai
achega
2d1c35b518

+ 22 - 1
assira.commons/src/main/java/net/ranides/assira/grammar/G4Parser.java

@@ -4,9 +4,12 @@ package net.ranides.assira.grammar;
 import net.ranides.assira.grammar.impl.ParserFactory;
 import net.ranides.assira.io.ResourceUtils;
 import net.ranides.assira.reflection.IClass;
+import net.ranides.assira.text.Charsets;
+import net.ranides.assira.text.IOStrings;
 import org.antlr.v4.runtime.Lexer;
 import org.antlr.v4.runtime.Parser;
 
+import java.io.File;
 import java.io.IOException;
 
 public interface G4Parser {
@@ -33,6 +36,8 @@ public interface G4Parser {
 
         private String source;
 
+        private String imports;
+
         private IClass<? extends Lexer> lexer;
 
         private IClass<? extends Parser> parser;
@@ -54,6 +59,19 @@ public interface G4Parser {
             return this;
         }
 
+        public G4ParserBuilder sourceFile(String source) {
+            try {
+                return source(IOStrings.read(new File(source), Charsets.UTF8));
+            } catch (IOException e) {
+                throw new G4Exception(e);
+            }
+        }
+
+        public G4ParserBuilder imports(String imports) {
+            this.imports = imports;
+            return this;
+        }
+
         public G4ParserBuilder lexer(Class<? extends Lexer> lexer) {
             return lexer(IClass.typeinfo(lexer));
         }
@@ -85,9 +103,12 @@ public interface G4Parser {
                 throw new G4Exception("You need to define only generated or interpreted parser at once");
             }
             if(parser!=null) {
+                if(imports!=null) {
+                    throw new G4Exception("Generated parsers do not need imports directory");
+                }
                 return ParserFactory.newInstance(lexer, parser, handler);
             } else {
-                return ParserFactory.newInstance(source, handler);
+                return ParserFactory.newInstance(source, imports, handler);
             }
         }
     }

+ 2 - 2
assira.commons/src/main/java/net/ranides/assira/grammar/impl/ParserFactory.java

@@ -15,8 +15,8 @@ public class ParserFactory {
         return new ParserGenerated(lexer, parser, handler);
     }
 
-    public static G4Parser newInstance(String grammar, G4ErrorHandler handler) {
-        return (G4Parser) Li.INTERPRETER.construct(grammar, handler);
+    public static G4Parser newInstance(String grammar, String imports, G4ErrorHandler handler) {
+        return (G4Parser) Li.INTERPRETER.construct(grammar, imports, handler);
     }
 
     private static class Li {

+ 71 - 3
assira.g4interpreter/src/main/java/net/ranides/assira/grammar/impl/G4ParserInterpreter.java

@@ -1,5 +1,6 @@
 package net.ranides.assira.grammar.impl;
 
+import lombok.Data;
 import net.ranides.assira.collection.lists.ListUtils;
 import net.ranides.assira.collection.maps.CrossMap;
 import net.ranides.assira.collection.maps.OpenCrossMap;
@@ -11,9 +12,14 @@ import net.ranides.assira.grammar.G4Parser;
 import net.ranides.assira.generic.Ref;
 import net.ranides.assira.grammar.G4ParserCoverage;
 import net.ranides.assira.text.StringUtils;
+import org.antlr.runtime.ANTLRStringStream;
 import org.antlr.runtime.RecognitionException;
 import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.TreeVisitor;
+import org.antlr.runtime.tree.TreeVisitorAction;
+import org.antlr.v4.Tool;
 import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo;
+import org.antlr.v4.parse.GrammarASTAdaptor;
 import org.antlr.v4.runtime.CharStreams;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.LexerInterpreter;
@@ -22,12 +28,15 @@ import org.antlr.v4.runtime.Token;
 import org.antlr.v4.runtime.Vocabulary;
 import org.antlr.v4.runtime.misc.Pair;
 import org.antlr.v4.runtime.tree.RuleNode;
+import org.antlr.v4.tool.ANTLRMessage;
+import org.antlr.v4.tool.ANTLRToolListener;
 import org.antlr.v4.tool.Alternative;
 import org.antlr.v4.tool.Grammar;
 import org.antlr.v4.tool.LabelElementPair;
 import org.antlr.v4.tool.Rule;
 import org.antlr.v4.tool.ast.AltAST;
 import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.GrammarRootAST;
 
 import java.util.List;
 import java.util.Map;
@@ -46,9 +55,14 @@ public class G4ParserInterpreter implements G4Parser {
 
     private final CrossMap<String, String, Integer> expressionLabels;
 
-    public G4ParserInterpreter(String grammar, G4ErrorHandler handler) {
+    public G4ParserInterpreter(String grammar, String imports, G4ErrorHandler handler) {
         try {
-            this.grammar = new Grammar(grammar);
+            if(imports == null) {
+                this.grammar = new Grammar(grammar, new ANTLRToolListenerAdapter(handler));
+            } else {
+                this.grammar = newGrammar(grammar, imports, handler);
+            }
+
             this.handler = handler;
             this.branchLabels = deduceBranchLabels(this.grammar);
             this.expressionLabels = deduceExpressionLabels(this.grammar);
@@ -63,6 +77,39 @@ public class G4ParserInterpreter implements G4Parser {
         }
     }
 
+    private Grammar newGrammar(String grammarText, String imports, G4ErrorHandler handler) throws RecognitionException {
+        Tool tool = new Tool();
+        tool.addListener(new ANTLRToolListenerAdapter(handler));
+
+        ANTLRStringStream in = new ANTLRStringStream(grammarText);
+        in.name = "((string))";
+
+        GrammarRootAST ast = tool.parse(in.name, in);
+        if ( ast==null ) {
+            throw new UnsupportedOperationException();
+        }
+
+        if (ast.tokenStream == null) {
+            throw new IllegalStateException("expected ast to have a token stream");
+        }
+
+        Grammar out = new Grammar(tool, ast);
+
+        in.name = out.fileName = out.name + ".g4";
+        tool.libDirectory = imports;
+
+        new TreeVisitor(new GrammarASTAdaptor()).visit(ast, new TreeVisitorAction() {
+            @Override
+            public Object pre(Object t) { ((GrammarAST)t).g = out; return t; }
+            @Override
+            public Object post(Object t) { return t; }
+        });
+
+        tool.process(out, false);
+
+        return out;
+    }
+
     /**
      * Tricky method: we deduce alternative labels for every rule
      */
@@ -188,7 +235,7 @@ public class G4ParserInterpreter implements G4Parser {
     public G4ParserCoverage rules() {
         Vocabulary v = grammar.getVocabulary();
         List<String> tokens = ListUtils.produce(v.getMaxTokenType() + 1, v::getSymbolicName);
-        throw new UnsupportedOperationException("TODO"); // @TODO implement
+        throw new UnsupportedOperationException("TODO"); // @TODO implement that
     }
 
     private class MyRoot extends RootAbstract {
@@ -247,4 +294,25 @@ public class G4ParserInterpreter implements G4Parser {
             }
         }
     }
+
+    @Data
+    private static final class ANTLRToolListenerAdapter implements ANTLRToolListener {
+
+        private final G4ErrorHandler handler;
+
+        @Override
+        public void info(String msg) {
+            handler.onError(msg, new G4Exception(msg));
+        }
+
+        @Override
+        public void error(ANTLRMessage msg) {
+            handler.onError(msg.toString(), msg.getCause());
+        }
+
+        @Override
+        public void warning(ANTLRMessage msg) {
+            handler.onError(msg.toString(), msg.getCause());
+        }
+    }
 }

+ 8 - 3
assira.ui/pom.xml

@@ -51,12 +51,17 @@
         </dependency>
         <dependency>
             <groupId>net.ranides</groupId>
-            <artifactId>assira.junit</artifactId>
+            <artifactId>assira.g4interpreter</artifactId>
+            <type>jar</type>
         </dependency>
         <dependency>
-            <groupId>org.antlr</groupId>
-            <artifactId>antlr4-runtime</artifactId>
+            <groupId>net.ranides</groupId>
+            <artifactId>assira.junit</artifactId>
         </dependency>
+<!--        <dependency>-->
+<!--            <groupId>org.antlr</groupId>-->
+<!--            <artifactId>antlr4-runtime</artifactId>-->
+<!--        </dependency>-->
 
         <dependency>
             <groupId>junit</groupId>

+ 36 - 1
assira.ui/src/test/java/net/ranides/assira/ui/primitives/CssParserTest.java

@@ -1,13 +1,17 @@
 package net.ranides.assira.ui.primitives;
 
+import net.ranides.assira.grammar.G4ErrorHandler;
 import net.ranides.assira.grammar.G4Node;
 import net.ranides.assira.grammar.G4Parser;
 import net.ranides.assira.grammar.G4ParserCoverage;
 import net.ranides.assira.grammar.G4Selector;
 import net.ranides.assira.grammar.G4SelectorBuilder;
 import net.ranides.assira.grammar.G4Support;
+import net.ranides.assira.grammar.impl.G4ParserInterpreter;
+import net.ranides.assira.io.IOStreams;
 import net.ranides.assira.io.ResourceUtils;
 import net.ranides.assira.junit.NewAssert;
+import net.ranides.assira.text.IOStrings;
 import net.ranides.assira.ui.helpers.ColorUtils;
 import net.ranides.grammars.generated.CssGrammarLexer;
 import net.ranides.grammars.generated.CssGrammarParser;
@@ -15,8 +19,10 @@ import org.junit.Ignore;
 import org.junit.Test;
 
 import java.awt.*;
+import java.io.File;
 import java.io.IOException;
 import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 
 import static net.ranides.assira.junit.NewAssert.assertThrows;
@@ -81,7 +87,36 @@ public class CssParserTest {
 
     @Ignore("manual")
     @Test
-    public void grammarCoverage() {
+    public void grammarInterpretedCoverage() throws IOException {
+        G4Parser g4 = G4Parser
+            .builder()
+            .sourceFile(
+                "src\\main\\antlr4\\net\\ranides\\grammars\\generated\\CssGrammar.g4")
+            .imports("src\\main\\antlr4\\imports")
+            .handler((message, error) -> System.out.println(message))
+            .build();
+
+        Color color = CssParser.COLOR.single(g4.parse("root_color", "#446600"));
+        assertEquals(new Color(68,102,0), color);
+
+//            .rules();
+//
+//        info.use(IGNORE);
+//
+//        info.use(CssParser.NUMBER);
+//        info.use(CssParser.SIZE_UNIT);
+//        info.use(CssParser.COLOR);
+//        info.use(CssParser.BORDER_STYLE);
+//        info.use(CssParser.BORDER_SIZE);
+//        info.use(CssParser.BORDER_SIZE_COMPONENT);
+//        info.use(CssParser.BORDER);
+//
+//        printCoverage(info);
+    }
+
+    @Ignore("manual")
+    @Test
+    public void grammarGeneratedCoverage() {
         G4ParserCoverage info = G4Parser.builder()
             .lexer(CssGrammarLexer.class)
             .parser(CssGrammarParser.class)

+ 5 - 0
pom.xml

@@ -241,6 +241,11 @@
                 <artifactId>assira.commons</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>net.ranides</groupId>
+                <artifactId>assira.g4interpreter</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>net.ranides</groupId>
                 <artifactId>assira.core</artifactId>