org.snt.inmemantlr.comp.StringCodeGenPipeline.java Source code

Java tutorial

Introduction

Here is the source code for org.snt.inmemantlr.comp.StringCodeGenPipeline.java

Source

/**
 * Inmemantlr - In memory compiler for Antlr 4
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Julian Thome <julian.thome.de@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 **/

package org.snt.inmemantlr.comp;

import org.antlr.v4.codegen.CodeGenPipeline;
import org.antlr.v4.codegen.CodeGenerator;
import org.antlr.v4.codegen.model.*;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.LexerGrammar;
import org.antlr.v4.tool.ast.GrammarAST;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snt.inmemantlr.grammar.InmemantlrGrammar;
import org.snt.inmemantlr.memobjects.MemorySource;
import org.stringtemplate.v4.ST;

import java.util.*;

/**
 * extended code gen pipeline for compiling
 * antlr grammars in-memory
 */
public class StringCodeGenPipeline extends CodeGenPipeline implements CunitProvider {

    private static final Logger LOGGER = LoggerFactory.getLogger(StringCodeGenPipeline.class);

    private Grammar g;
    private String name;

    private ST parser, lexer, visitor, listener, baseListener, baseVisitor;
    private ST tokenvocab;

    /**
     * constructor
     *
     * @param g antlr grammar object
     */
    public StringCodeGenPipeline(Grammar g) {
        super(g);
        this.g = g;
        name = g.name;
        lexer = null;
        listener = null;
        visitor = null;
        baseListener = null;
        baseVisitor = null;
    }

    /**
     * check if parser is set
     *
     * @return true if parser is set, false otherwise
     */
    public boolean hasParser() {
        return parser != null;
    }

    /**
     * get parser
     *
     * @return parser
     */
    public ST getParser() {
        return parser;
    }

    /**
     * get base listener
     *
     * @return base listener
     */
    public ST getBaseListener() {
        return baseListener;
    }

    /**
     * check if base listener is set
     *
     * @return true if listener is set, false otherwise
     */
    public boolean hasBaseListener() {
        return baseListener != null;
    }

    /**
     * get lexer
     *
     * @return lexer
     */
    public ST getLexer() {
        return lexer;
    }

    /**
     * check if lexer is set
     *
     * @return true if lexer is set, false otherwise
     */
    public boolean hasLexer() {
        return lexer != null;
    }

    /**
     * get visitor
     *
     * @return visitor
     */
    public ST getVisitor() {
        return visitor;
    }

    /**
     * check if visitor is set
     *
     * @return true if visitor is set, false otherwise
     */
    public boolean hasVisitor() {
        return visitor != null;
    }

    /**
     * get listener
     *
     * @return listener
     */
    public ST getListener() {
        return listener;
    }

    /**
     * check if listener is set
     *
     * @return true if listener is set, false otherwise
     */
    public boolean hasListener() {
        return listener != null;
    }

    /**
     * get base visitor
     *
     * @return base visitor
     */
    public ST getBaseVisitor() {
        return baseVisitor;
    }

    public ST getTokenVocab() {
        return tokenvocab;
    }

    /**
     * check if visitor is set
     *
     * @return true if visitor is set, false otherwise
     */
    public boolean hasBaseVisitor() {
        return baseVisitor != null;
    }

    public boolean hasTokenVocab() {
        return tokenvocab != null;
    }

    /**
     * get grammar
     *
     * @return grammar
     */
    public Grammar getG() {
        return g;
    }

    /**
     * set grammar
     *
     * @param g grammar
     */
    public void setG(InmemantlrGrammar g) {
        this.g = g;
    }

    /**
     * compile lexer and parser
     */
    public void process() {

        CodeGenerator cgen = new CodeGenerator(g);
        IntervalSet idTypes = new IntervalSet();
        idTypes.add(ANTLRParser.ID);
        idTypes.add(ANTLRParser.RULE_REF);
        idTypes.add(ANTLRParser.TOKEN_REF);

        List<GrammarAST> idNodes = g.ast.getNodesWithType(idTypes);
        idNodes.stream().filter(idNode -> cgen.getTarget().grammarSymbolCausesIssueInGeneratedCode(idNode))
                .forEach(idNode -> g.tool.errMgr.grammarError(ErrorType.USE_OF_BAD_WORD, g.fileName,
                        idNode.getToken(), idNode.getText()));

        if (g.isLexer()) {
            lexer = cgen.generateLexer();
        } else {
            parser = cgen.generateParser();

            if (g.tool.gen_listener) {
                listener = cgen.generateListener();
                if (cgen.getTarget().wantsBaseListener()) {
                    baseListener = cgen.generateBaseListener();
                }
            }
            if (g.tool.gen_visitor) {
                visitor = cgen.generateVisitor();
                if (cgen.getTarget().wantsBaseVisitor()) {
                    baseVisitor = cgen.generateBaseVisitor();
                }
            }

            LexerGrammar lg;
            if ((lg = g.implicitLexer) != null) {
                CodeGenerator lgcg = new CodeGenerator(lg);
                lexer = lgcg.generateLexer();
            }

        }

        tokenvocab = getTokenVocabOutput();
    }

    ST getTokenVocabOutput() {
        ST vocabFileST = new ST(CodeGenerator.vocabFilePattern);
        Map<String, Integer> tokens = new LinkedHashMap<>();
        // make constants for the token names
        for (String t : g.tokenNameToTypeMap.keySet()) {
            int tokenType = g.tokenNameToTypeMap.get(t);
            if (tokenType >= Token.MIN_USER_TOKEN_TYPE) {
                tokens.put(t, tokenType);
            }
        }
        vocabFileST.add("tokenvocab", tokens);

        // now dump the strings
        Map<String, Integer> literals = new LinkedHashMap<>();
        for (String literal : g.stringLiteralToTypeMap.keySet()) {
            int tokenType = g.stringLiteralToTypeMap.get(literal);
            if (tokenType >= Token.MIN_USER_TOKEN_TYPE) {
                literals.put(literal, tokenType);
            }
        }
        vocabFileST.add("literals", literals);

        return vocabFileST;
    }

    /**
     * get parser name
     *
     * @return parser name
     */
    public String getParserName() {
        ParserFile f = (ParserFile) parser.getAttributes().get("file");
        LOGGER.debug("parser name {}", modFile(f));
        return modFile(f);
    }

    /**
     * get lexer name
     *
     * @return lexer name
     */
    public String getLexerName() {
        LexerFile f = (LexerFile) lexer.getAttributes().get("lexerFile");
        LOGGER.debug("lexer name {}", modFile(f));
        return modFile(f);
    }

    /**
     * get visitor name
     *
     * @return visitor name
     */
    public String getVisitorName() {
        VisitorFile f = (VisitorFile) listener.getAttributes().get("file");
        LOGGER.debug("listener name {}", modFile(f));
        return modFile(f);
    }

    /**
     * get base visitor name
     *
     * @return base visitor name
     */
    public String getBaseVisitorName() {
        BaseVisitorFile f = (BaseVisitorFile) listener.getAttributes().get("file");
        LOGGER.debug("listener name {}", modFile(f));
        return modFile(f);
    }

    /**
     * get listener name
     *
     * @return listener name
     */
    public String getListenerName() {
        ListenerFile f = (ListenerFile) listener.getAttributes().get("file");
        LOGGER.debug("listener name {}", modFile(f));
        return modFile(f);
    }

    /**
     * get base listener name
     *
     * @return base listener name
     */
    public String getBaseListenerName() {
        BaseListenerFile f = (BaseListenerFile) baseListener.getAttributes().get("file");
        LOGGER.debug("base listener name {}", modFile(f));
        return modFile(f);
    }

    public String getTokenVocabFileName() {
        return g.name + CodeGenerator.VOCAB_FILE_EXTENSION;
    }

    @SuppressWarnings("unchecked")
    public String getTokenVocabString() {
        Map<String, Integer> vocab = (Map<String, Integer>) tokenvocab.getAttribute("tokenvocab");
        Map<String, Integer> lit = (Map<String, Integer>) tokenvocab.getAttribute("literals");

        StringBuilder sb = new StringBuilder();
        vocab.forEach((s, i) -> sb.append(s).append("=").append(i.toString()).append("\n"));
        lit.forEach((s, i) -> sb.append(s).append("=").append(i.toString()).append("\n"));
        return sb.toString();
    }

    private String modFile(OutputFile f) {
        return FilenameUtils.removeExtension(f.fileName);
    }

    @Override
    public String toString() {
        return name;
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }

    @Override
    public boolean equals(Object o) {
        return o instanceof StringCodeGenPipeline && name.equals(((StringCodeGenPipeline) o).name);
    }

    @Override
    public Collection<MemorySource> getItems() {
        List<MemorySource> ret = new Vector<>();
        if (hasLexer()) {
            ret.add(new MemorySource(getLexerName(), getLexer().render()));
        }
        if (hasBaseListener()) {
            ret.add(new MemorySource(getBaseListenerName(), getBaseListener().render()));
        }
        if (hasBaseVisitor()) {
            ret.add(new MemorySource(getBaseVisitorName(), getBaseVisitor().render()));
        }
        if (hasParser()) {
            ret.add(new MemorySource(getParserName(), getParser().render()));
        }
        if (hasListener()) {
            ret.add(new MemorySource(getListenerName(), getListener().render()));
        }
        if (hasVisitor()) {
            ret.add(new MemorySource(getVisitorName(), getVisitor().render()));
        }
        return ret;
    }

    @Override
    public boolean hasItems() {
        return getItems().size() > 0;
    }
}