Package org.antlr.v4.codegen

Source Code of org.antlr.v4.codegen.OutputModelController

/*
* [The "BSD license"]
*  Copyright (c) 2012 Terence Parr
*  Copyright (c) 2012 Sam Harwell
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*  1. Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*  2. Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in the
*     documentation and/or other materials provided with the distribution.
*  3. The name of the author may not be used to endorse or promote products
*     derived from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
*  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
*  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
*  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
*  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
*  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.antlr.v4.codegen;

import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo;
import org.antlr.v4.codegen.model.Action;
import org.antlr.v4.codegen.model.AltBlock;
import org.antlr.v4.codegen.model.BaseListenerFile;
import org.antlr.v4.codegen.model.BaseVisitorFile;
import org.antlr.v4.codegen.model.Choice;
import org.antlr.v4.codegen.model.CodeBlockForAlt;
import org.antlr.v4.codegen.model.CodeBlockForOuterMostAlt;
import org.antlr.v4.codegen.model.LabeledOp;
import org.antlr.v4.codegen.model.LeftRecursiveRuleFunction;
import org.antlr.v4.codegen.model.Lexer;
import org.antlr.v4.codegen.model.LexerFile;
import org.antlr.v4.codegen.model.ListenerFile;
import org.antlr.v4.codegen.model.OutputModelObject;
import org.antlr.v4.codegen.model.Parser;
import org.antlr.v4.codegen.model.ParserFile;
import org.antlr.v4.codegen.model.RuleActionFunction;
import org.antlr.v4.codegen.model.RuleFunction;
import org.antlr.v4.codegen.model.RuleSempredFunction;
import org.antlr.v4.codegen.model.SrcOp;
import org.antlr.v4.codegen.model.StarBlock;
import org.antlr.v4.codegen.model.VisitorFile;
import org.antlr.v4.codegen.model.decl.CodeBlock;
import org.antlr.v4.misc.Utils;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.parse.GrammarASTAdaptor;
import org.antlr.v4.tool.Alternative;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.LeftRecursiveRule;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.ActionAST;
import org.antlr.v4.tool.ast.BlockAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.PredAST;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/** This receives events from SourceGenTriggers.g and asks factory to do work.
*  Then runs extensions in order on resulting SrcOps to get final list.
**/
public class OutputModelController {
  /** Who does the work? Doesn't have to be CoreOutputModelFactory. */
  public OutputModelFactory delegate;

  /** Post-processing CodeGeneratorExtension objects; done in order given. */
  public List<CodeGeneratorExtension> extensions = new ArrayList<CodeGeneratorExtension>();

  /** While walking code in rules, this is set to the tree walker that
   *  triggers actions.
   */
  public SourceGenTriggers walker;

  /** Context set by the SourceGenTriggers.g */
  public int codeBlockLevel = -1;
  public int treeLevel = -1;
  public OutputModelObject root; // normally ParserFile, LexerFile, ...
  public Stack<RuleFunction> currentRule = new Stack<RuleFunction>();
  public Alternative currentOuterMostAlt;
  public CodeBlock currentBlock;
  public CodeBlockForOuterMostAlt currentOuterMostAlternativeBlock;

  public OutputModelController(OutputModelFactory factory) {
    this.delegate = factory;
  }

  public void addExtension(CodeGeneratorExtension ext) { extensions.add(ext); }

  /** Build a file with a parser containing rule functions. Use the
   *  controller as factory in SourceGenTriggers so it triggers codegen
   *  extensions too, not just the factory functions in this factory.
   */
  public OutputModelObject buildParserOutputModel() {
    Grammar g = delegate.getGrammar();
    CodeGenerator gen = delegate.getGenerator();
    ParserFile file = parserFile(gen.getRecognizerFileName());
    setRoot(file);
    Parser parser = parser(file);
    file.parser = parser;

    for (Rule r : g.rules.values()) {
      buildRuleFunction(parser, r);
    }

    return file;
  }

  public OutputModelObject buildLexerOutputModel() {
    CodeGenerator gen = delegate.getGenerator();
    LexerFile file = lexerFile(gen.getRecognizerFileName());
    setRoot(file);
    file.lexer = lexer(file);

    Grammar g = delegate.getGrammar();
    for (Rule r : g.rules.values()) {
      buildLexerRuleActions(file.lexer, r);
    }

    return file;
  }

  public OutputModelObject buildListenerOutputModel() {
    CodeGenerator gen = delegate.getGenerator();
    return new ListenerFile(delegate, gen.getListenerFileName());
  }

  public OutputModelObject buildBaseListenerOutputModel() {
    CodeGenerator gen = delegate.getGenerator();
    return new BaseListenerFile(delegate, gen.getBaseListenerFileName());
  }

  public OutputModelObject buildVisitorOutputModel() {
    CodeGenerator gen = delegate.getGenerator();
    return new VisitorFile(delegate, gen.getVisitorFileName());
  }

  public OutputModelObject buildBaseVisitorOutputModel() {
    CodeGenerator gen = delegate.getGenerator();
    return new BaseVisitorFile(delegate, gen.getBaseVisitorFileName());
  }

  public ParserFile parserFile(String fileName) {
    ParserFile f = delegate.parserFile(fileName);
    for (CodeGeneratorExtension ext : extensions) f = ext.parserFile(f);
    return f;
  }

  public Parser parser(ParserFile file) {
    Parser p = delegate.parser(file);
    for (CodeGeneratorExtension ext : extensions) p = ext.parser(p);
    return p;
  }

  public LexerFile lexerFile(String fileName) {
    return new LexerFile(delegate, fileName);
  }

  public Lexer lexer(LexerFile file) {
    return new Lexer(delegate, file);
  }

  /** Create RuleFunction per rule and update sempreds,actions of parser
   *  output object with stuff found in r.
   */
  public void buildRuleFunction(Parser parser, Rule r) {
    RuleFunction function = rule(r);
    parser.funcs.add(function);
    pushCurrentRule(function);
    function.fillNamedActions(delegate, r);

    if ( r instanceof LeftRecursiveRule ) {
      buildLeftRecursiveRuleFunction((LeftRecursiveRule)r,
                       (LeftRecursiveRuleFunction)function);
    }
    else {
      buildNormalRuleFunction(r, function);
    }

    Grammar g = getGrammar();
    for (ActionAST a : r.actions) {
      if ( a instanceof PredAST ) {
        PredAST p = (PredAST)a;
        RuleSempredFunction rsf = parser.sempredFuncs.get(r);
        if ( rsf==null ) {
          rsf = new RuleSempredFunction(delegate, r, function.ctxType);
          parser.sempredFuncs.put(r, rsf);
        }
        rsf.actions.put(g.sempreds.get(p), new Action(delegate, p));
      }
    }

    popCurrentRule();
  }

  public void buildLeftRecursiveRuleFunction(LeftRecursiveRule r, LeftRecursiveRuleFunction function) {
    buildNormalRuleFunction(r, function);

    // now inject code to start alts
    CodeGenerator gen = delegate.getGenerator();
    STGroup codegenTemplates = gen.getTemplates();

    // pick out alt(s) for primaries
    CodeBlockForOuterMostAlt outerAlt = (CodeBlockForOuterMostAlt)function.code.get(0);
    List<CodeBlockForAlt> primaryAltsCode = new ArrayList<CodeBlockForAlt>();
    SrcOp primaryStuff = outerAlt.ops.get(0);
    if ( primaryStuff instanceof Choice ) {
      Choice primaryAltBlock = (Choice) primaryStuff;
      primaryAltsCode.addAll(primaryAltBlock.alts);
    }
    else { // just a single alt I guess; no block
      primaryAltsCode.add((CodeBlockForAlt)primaryStuff);
    }

    // pick out alt(s) for op alts
    StarBlock opAltStarBlock = (StarBlock)outerAlt.ops.get(1);
    CodeBlockForAlt altForOpAltBlock = opAltStarBlock.alts.get(0);
    List<CodeBlockForAlt> opAltsCode = new ArrayList<CodeBlockForAlt>();
    SrcOp opStuff = altForOpAltBlock.ops.get(0);
    if ( opStuff instanceof AltBlock ) {
      AltBlock opAltBlock = (AltBlock)opStuff;
      opAltsCode.addAll(opAltBlock.alts);
    }
    else { // just a single alt I guess; no block
      opAltsCode.add((CodeBlockForAlt)opStuff);
    }

    // Insert code in front of each primary alt to create specialized ctx if there was a label
    for (int i = 0; i < primaryAltsCode.size(); i++) {
      LeftRecursiveRuleAltInfo altInfo = r.recPrimaryAlts.get(i);
      if ( altInfo.altLabel==null ) continue;
      ST altActionST = codegenTemplates.getInstanceOf("recRuleReplaceContext");
      altActionST.add("ctxName", Utils.capitalize(altInfo.altLabel));
      Action altAction =
        new Action(delegate, function.altLabelCtxs.get(altInfo.altLabel), altActionST);
      CodeBlockForAlt alt = primaryAltsCode.get(i);
      alt.insertOp(0, altAction);
    }

    // Insert code to set ctx.stop after primary block and before op * loop
    ST setStopTokenAST = codegenTemplates.getInstanceOf("recRuleSetStopToken");
    Action setStopTokenAction = new Action(delegate, function.ruleCtx, setStopTokenAST);
    outerAlt.insertOp(1, setStopTokenAction);

    // Insert code to set _prevctx at start of * loop
    ST setPrevCtx = codegenTemplates.getInstanceOf("recRuleSetPrevCtx");
    Action setPrevCtxAction = new Action(delegate, function.ruleCtx, setPrevCtx);
    opAltStarBlock.addIterationOp(setPrevCtxAction);

    // Insert code in front of each op alt to create specialized ctx if there was an alt label
    for (int i = 0; i < opAltsCode.size(); i++) {
      ST altActionST;
      LeftRecursiveRuleAltInfo altInfo = r.recOpAlts.getElement(i);
      String templateName;
      if ( altInfo.altLabel!=null ) {
        templateName = "recRuleLabeledAltStartAction";
        altActionST = codegenTemplates.getInstanceOf(templateName);
        altActionST.add("currentAltLabel", altInfo.altLabel);
      }
      else {
        templateName = "recRuleAltStartAction";
        altActionST = codegenTemplates.getInstanceOf(templateName);
        altActionST.add("ctxName", Utils.capitalize(r.name));
      }
      altActionST.add("ruleName", r.name);
      // add label of any lr ref we deleted
      altActionST.add("label", altInfo.leftRecursiveRuleRefLabel);
      if (altActionST.impl.formalArguments.containsKey("isListLabel")) {
        altActionST.add("isListLabel", altInfo.isListLabel);
      }
      else if (altInfo.isListLabel) {
        delegate.getGenerator().tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, "isListLabel");
      }
      Action altAction =
        new Action(delegate, function.altLabelCtxs.get(altInfo.altLabel), altActionST);
      CodeBlockForAlt alt = opAltsCode.get(i);
      alt.insertOp(0, altAction);
    }
  }

  public void buildNormalRuleFunction(Rule r, RuleFunction function) {
    CodeGenerator gen = delegate.getGenerator();
    // TRIGGER factory functions for rule alts, elements
    GrammarASTAdaptor adaptor = new GrammarASTAdaptor(r.ast.token.getInputStream());
    GrammarAST blk = (GrammarAST)r.ast.getFirstChildWithType(ANTLRParser.BLOCK);
    CommonTreeNodeStream nodes = new CommonTreeNodeStream(adaptor,blk);
    walker = new SourceGenTriggers(nodes, this);
    try {
      // walk AST of rule alts/elements
      function.code = DefaultOutputModelFactory.list(walker.block(null, null));
      function.hasLookaheadBlock = walker.hasLookaheadBlock;
    }
    catch (org.antlr.runtime.RecognitionException e){
      e.printStackTrace(System.err);
    }

    function.ctxType = gen.getTarget().getRuleFunctionContextStructName(function);

    function.postamble = rulePostamble(function, r);
  }

  public void buildLexerRuleActions(Lexer lexer, final Rule r) {
    if (r.actions.isEmpty()) {
      return;
    }

    CodeGenerator gen = delegate.getGenerator();
    Grammar g = delegate.getGrammar();
    String ctxType = gen.getTarget().getRuleFunctionContextStructName(r);
    RuleActionFunction raf = lexer.actionFuncs.get(r);
    if ( raf==null ) {
      raf = new RuleActionFunction(delegate, r, ctxType);
    }

    for (ActionAST a : r.actions) {
      if ( a instanceof PredAST ) {
        PredAST p = (PredAST)a;
        RuleSempredFunction rsf = lexer.sempredFuncs.get(r);
        if ( rsf==null ) {
          rsf = new RuleSempredFunction(delegate, r, ctxType);
          lexer.sempredFuncs.put(r, rsf);
        }
        rsf.actions.put(g.sempreds.get(p), new Action(delegate, p));
      }
      else if ( a.getType()== ANTLRParser.ACTION ) {
        raf.actions.put(g.lexerActions.get(a), new Action(delegate, a));
      }
    }

    if (!raf.actions.isEmpty() && !lexer.actionFuncs.containsKey(r)) {
      // only add to lexer if the function actually contains actions
      lexer.actionFuncs.put(r, raf);
    }
  }

  public RuleFunction rule(Rule r) {
    RuleFunction rf = delegate.rule(r);
    for (CodeGeneratorExtension ext : extensions) rf = ext.rule(rf);
    return rf;
  }

  public List<SrcOp> rulePostamble(RuleFunction function, Rule r) {
    List<SrcOp> ops = delegate.rulePostamble(function, r);
    for (CodeGeneratorExtension ext : extensions) ops = ext.rulePostamble(ops);
    return ops;
  }

  public Grammar getGrammar() { return delegate.getGrammar(); }

  public CodeGenerator getGenerator() { return delegate.getGenerator(); }

  public CodeBlockForAlt alternative(Alternative alt, boolean outerMost) {
    CodeBlockForAlt blk = delegate.alternative(alt, outerMost);
    if ( outerMost ) {
      currentOuterMostAlternativeBlock = (CodeBlockForOuterMostAlt)blk;
    }
    for (CodeGeneratorExtension ext : extensions) blk = ext.alternative(blk, outerMost);
    return blk;
  }

  public CodeBlockForAlt finishAlternative(CodeBlockForAlt blk, List<SrcOp> ops,
                       boolean outerMost)
  {
    blk = delegate.finishAlternative(blk, ops);
    for (CodeGeneratorExtension ext : extensions) blk = ext.finishAlternative(blk, outerMost);
    return blk;
  }

  public List<SrcOp> ruleRef(GrammarAST ID, GrammarAST label, GrammarAST args) {
    List<SrcOp> ops = delegate.ruleRef(ID, label, args);
    for (CodeGeneratorExtension ext : extensions) {
      ops = ext.ruleRef(ops);
    }
    return ops;
  }

  public List<SrcOp> tokenRef(GrammarAST ID, GrammarAST label, GrammarAST args)
  {
    List<SrcOp> ops = delegate.tokenRef(ID, label, args);
    for (CodeGeneratorExtension ext : extensions) {
      ops = ext.tokenRef(ops);
    }
    return ops;
  }

  public List<SrcOp> stringRef(GrammarAST ID, GrammarAST label) {
    List<SrcOp> ops = delegate.stringRef(ID, label);
    for (CodeGeneratorExtension ext : extensions) {
      ops = ext.stringRef(ops);
    }
    return ops;
  }

  /** (A|B|C) possibly with ebnfRoot and label */
  public List<SrcOp> set(GrammarAST setAST, GrammarAST labelAST, boolean invert) {
    List<SrcOp> ops = delegate.set(setAST, labelAST, invert);
    for (CodeGeneratorExtension ext : extensions) {
      ops = ext.set(ops);
    }
    return ops;
  }

  public CodeBlockForAlt epsilon(Alternative alt, boolean outerMost) {
    CodeBlockForAlt blk = delegate.epsilon(alt, outerMost);
    for (CodeGeneratorExtension ext : extensions) blk = ext.epsilon(blk);
    return blk;
  }

  public List<SrcOp> wildcard(GrammarAST ast, GrammarAST labelAST) {
    List<SrcOp> ops = delegate.wildcard(ast, labelAST);
    for (CodeGeneratorExtension ext : extensions) {
      ops = ext.set(ops);
    }
    return ops;
  }

  public List<SrcOp> action(ActionAST ast) {
    List<SrcOp> ops = delegate.action(ast);
    for (CodeGeneratorExtension ext : extensions) ops = ext.action(ops);
    return ops;
  }

  public List<SrcOp> sempred(ActionAST ast) {
    List<SrcOp> ops = delegate.sempred(ast);
    for (CodeGeneratorExtension ext : extensions) ops = ext.sempred(ops);
    return ops;
  }

  public Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts, GrammarAST label) {
    Choice c = delegate.getChoiceBlock(blkAST, alts, label);
    for (CodeGeneratorExtension ext : extensions) c = ext.getChoiceBlock(c);
    return c;
  }

  public Choice getEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) {
    Choice c = delegate.getEBNFBlock(ebnfRoot, alts);
    for (CodeGeneratorExtension ext : extensions) c = ext.getEBNFBlock(c);
    return c;
  }

  public boolean needsImplicitLabel(GrammarAST ID, LabeledOp op) {
    boolean needs = delegate.needsImplicitLabel(ID, op);
    for (CodeGeneratorExtension ext : extensions) needs |= ext.needsImplicitLabel(ID, op);
    return needs;
  }

  public OutputModelObject getRoot() { return root; }

  public void setRoot(OutputModelObject root) { this.root = root; }

  public RuleFunction getCurrentRuleFunction() {
    if ( !currentRule.isEmpty() )  return currentRule.peek();
    return null;
  }

  public void pushCurrentRule(RuleFunction r) { currentRule.push(r); }

  public RuleFunction popCurrentRule() {
    if ( !currentRule.isEmpty() ) return currentRule.pop();
    return null;
  }

  public Alternative getCurrentOuterMostAlt() { return currentOuterMostAlt; }

  public void setCurrentOuterMostAlt(Alternative currentOuterMostAlt) { this.currentOuterMostAlt = currentOuterMostAlt; }

  public void setCurrentBlock(CodeBlock blk) {
    currentBlock = blk;
  }

  public CodeBlock getCurrentBlock() {
    return currentBlock;
  }

  public void setCurrentOuterMostAlternativeBlock(CodeBlockForOuterMostAlt currentOuterMostAlternativeBlock) {
    this.currentOuterMostAlternativeBlock = currentOuterMostAlternativeBlock;
  }

  public CodeBlockForOuterMostAlt getCurrentOuterMostAlternativeBlock() {
    return currentOuterMostAlternativeBlock;
  }

  public int getCodeBlockLevel() { return codeBlockLevel; }
}
TOP

Related Classes of org.antlr.v4.codegen.OutputModelController

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.