/**
   * Gets the output.
   *
   * @return the output
   * @throws GrammarGenerationException the grammar generation exception
   */
  public String getOutput() throws GrammarGenerationException {
    if (grammarName == null) {
      throw new GrammarGenerationException("Grammar name not set");
    }
    String parserMembers =
        parserMembersTemplate
            .replace("%Lexer%", grammarName + "Lexer")
            .replace("%Parser%", grammarName + "Parser");

    parserMembers = parserMembers.replace("%syntaxUUID%", syntaxUUID.toString());

    int newLinesLength = NEWLINES.length();

    int grammarLength =
        getGrammarHeader().length()
            + lexerHeader.length()
            + lexerMembers.length()
            + 20
            + additionalLexerMembers.length()
            + parserHeader.length()
            + parserMembers.length()
            + lexerString.length()
            + (newLinesLength * 5)
            + 10; // Slack for if I miscalculated

    if (grammarOptions != null) {
      grammarLength += grammarOptions.length() + 12;
    }

    for (AbstractAntlr3Rule rule : rules) {
      grammarLength += rule.getLength() + newLinesLength;
    }

    VarStringBuffer buf = new VarStringBuffer(grammarLength);
    buf.append(getGrammarHeader());
    buf.append("\r\noptions {", "superClass=", parserSuperClass.getSimpleName(), ";");
    if (grammarOptions != null && !grammarOptions.trim().equals("")) {
      buf.append(grammarOptions);
    }
    buf.append("}");

    buf.append(
        NEWLINES,
        lexerHeader.replace("%package%", targetPackage),
        NEWLINES,
        "@lexer::members {",
        lexerMembers,
        additionalLexerMembers,
        '}',
        NEWLINES,
        parserHeader
            .replace("%package%", targetPackage)
            .replaceAll("%superclass%", parserSuperClass.getCanonicalName()),
        NEWLINES,
        parserMembers,
        NEWLINES);

    for (AbstractAntlr3Rule rule : rules) {
      rule.addToSerializationBuffer(buf);
      buf.append(NEWLINES);
    }
    buf.append(lexerString);

    return buf.toString();
  }
  /**
   * Adds the template.
   *
   * @param template the template
   * @throws SyntaxParsingException
   * @throws MetaModelLookupException
   */
  public void addTemplate(OperatorTemplate template, RuleBodyBufferFactory ruleBodyBufferFactory)
      throws MetaModelLookupException, SyntaxElementException {

    VarStringBuffer rulebody =
        new VarStringBuffer(); // first add ANTLR rule to Rulebody, then Java elements

    Collection<Operator> ops = template.getOperators();
    boolean allOperatorsPostFix = true;
    for (Operator operator : ops) {
      if (!operator.isPostfix()) {
        allOperatorsPostFix = false;
      }
    }
    if (allOperatorsPostFix) {
      // TODO: Understand and Support specific operator templates
      // throw new RuntimeException("Operator Template with all operators being postfix not
      // supported yet");
    }
    try {
      ResolvedNameAndReferenceBean<Type> refbean = resolutionHelper.resolve(template);

      String returnDeclaration =
          concat("java.lang.String opName, Object left, org.antlr.runtime.Token firstToken");

      String metaObjectListParam = namingHelper.getMetaTypeListParameter(refbean);
      StringBuilder initString = new StringBuilder(); // TODO cleanup string construction
      if (template.isIsReferenceOnly()) {
        initString.append(
            concat(
                "List<String> metaType=",
                metaObjectListParam,
                ";\n",
                ObservationDirectivesHelper.getEnterTemplateNotification(template),
                "IModelElementProxy ret=(getBacktrackingLevel()==0) ?  createReferenceProxy(metaType) : null;\n\n"));
      } else {
        initString.append(
            concat(
                "List<String> metaType=",
                metaObjectListParam,
                ";\n",
                ObservationDirectivesHelper.getEnterTemplateNotification(template),
                "IModelElementProxy ret=(getBacktrackingLevel()==0) ? createModelElementProxy(metaType, ",
                template.isIsContext(),
                ", false"));
        ContextTags tags = template.getContextTags();
        if (tags != null && tags.getTags() != null && tags.getTags().size() > 0) {
          initString.append(", new String[]{");
          for (Iterator<String> iterator = tags.getTags().iterator(); iterator.hasNext(); ) {
            String tag = iterator.next();
            initString.append("\"").append(tag).append("\"");
            if (iterator.hasNext()) {
              initString.append(", ");
            }
          }
          initString.append("}");
        }
        initString.append(") : null;\n\n");
      }

      if (template.getTemplateSequence() != null) {
        Sequence sequence = template.getTemplateSequence();
        String rulefragment = ruleBodyBufferFactory.getNewRuleBodyFragment(sequence);
        rulebody.append(rulefragment);
      }

      rulebody.append("{\n");

      String operatorStorageName = getOperatorStorageName(template);
      if (operatorStorageName != null) {
        rulebody.append("setProperty(ret,\"", operatorStorageName, "\" , opName);\n");
      } else {
        rulebody.append("// discarding operator name instead of storing it here\n");
      }
      rulebody.append("setProperty(ret,\"", getSourceStorageName(template), "\" , left);\n");
      rulebody.append("ret2 = createOrResolve(ret, firstToken);\n");
      rulebody.append("onRuleElementCreationCommited(ret2);\n");
      if (template.isIsContext()) {
        rulebody.append("leaveContext();\n");
        // leave context after sub-elements are done with add to context
      }
      rulebody.append("\n}");

      writer.addRule(
          new OperatorTemplateProductionRule(
              namingHelper.getRuleName(template),
              returnDeclaration,
              "Object ret2",
              initString.toString(),
              rulebody.toString()));
    } catch (NameResolutionFailedException e) {
      throw new SyntaxElementException(
          "OperatorTemplate name could not be resolved: " + MessageHelper.getTemplateName(template),
          template,
          e);
    }
  }