private void pageImport(String value) {
   // LOG.debug("pageImport(" + value + ')');
   String[] imports = Pattern.compile(";").split(value.subSequence(0, value.length()));
   for (int ix = 0; ix < imports.length; ix++) {
     out.print("import ");
     out.print(imports[ix]);
     out.println();
   }
 }
  private void write(CharSequence text, boolean gsp) {
    if (!gsp) {
      out.print(text);
      return;
    }

    for (int ix = 0, ixz = text.length(); ix < ixz; ix++) {
      char c = text.charAt(ix);
      String rep = null;
      if (Character.isWhitespace(c)) {
        for (ix++; ix < ixz; ix++) {
          if (Character.isWhitespace(text.charAt(ix))) {
            continue;
          }
          ix--;
          rep = " ";
          break;
        }
      } else if (c == '&') {
        if (match("&semi;", text, ix)) {
          rep = ";";
          ix += 5;
        } else if (match("&amp;", text, ix)) {
          rep = "&";
          ix += 4;
        } else if (match("&lt;", text, ix)) {
          rep = "<";
          ix += 3;
        } else if (match("&gt;", text, ix)) {
          rep = ">";
          ix += 3;
        }
      } else if (c == '<') {
        if (match("<br>", text, ix) || match("<hr>", text, ix)) {
          rep = "\n";
          // incrementLineNumber();
          ix += 3;
        } else {
          int end = match(PARA_BREAK, text, ix);
          if (end <= 0) end = match(ROW_BREAK, text, ix);
          if (end > 0) {
            rep = "\n";
            // incrementLineNumber();
            ix = end;
          }
        }
      }
      if (rep != null) {
        out.print(rep);
      } else {
        out.print(c);
      }
    }
  }
  private void script(boolean gsp) {
    flushTagBuffering();
    if (!finalPass) return;

    LOG.debug("parse: script");

    out.println();
    write(scan.getToken().trim(), gsp);
    out.println();
    out.println();
  }
  private void declare(boolean gsp) {
    if (finalPass) {
      return;
    }

    LOG.debug("parse: declare");

    out.println();
    write(scan.getToken().trim(), gsp);
    out.println();
    out.println();
  }
  private void expr() {
    if (!finalPass) return;

    LOG.debug("parse: expr");

    String text = scan.getToken().trim();
    text = getExpressionText(text);
    if (text != null && text.length() > 2 && text.startsWith("(") && text.endsWith(")")) {
      out.printlnToResponse(
          GroovyPage.EXPRESSION_OUT_STATEMENT, text.substring(1, text.length() - 1));
    } else {
      out.printlnToResponse(GroovyPage.EXPRESSION_OUT_STATEMENT, text);
    }
  }
 public void writeLineNumbers(File filename) throws IOException {
   DataOutputStream dataOut = null;
   try {
     dataOut = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(filename)));
     int lineNumbersCount = out.getCurrentLineNumber() - 1;
     int[] lineNumbers = out.getLineNumbers();
     dataOut.writeInt(lineNumbersCount);
     for (int i = 0; i < lineNumbersCount; i++) {
       dataOut.writeInt(lineNumbers[i]);
     }
   } finally {
     SpringIOUtils.closeQuietly(dataOut);
   }
 }
 /**
  * Write to the outputstream ONLY if the string is not blank, else we hold it back in case it is
  * to be swallowed between tags
  */
 @SuppressWarnings("unused")
 private void bufferedPrintlnToResponse(String s) {
   if (currentlyBufferingWhitespace) {
     whitespaceBuffer.append(s);
   } else {
     flushTagBuffering();
     out.printlnToResponse(s);
   }
 }
  public void generateGsp(Writer target, boolean precompileMode) {
    this.precompileMode = precompileMode;

    out = new GSPWriter(target, this);
    if (packageName != null && packageName.length() > 0) {
      out.println("package " + packageName);
      out.println();
    }
    page();
    finalPass = true;
    scan.reset();
    previousContentWasNonWhitespace = false;
    currentlyBufferingWhitespace = false;
    page();

    out.close();
    scan = null;
  }
  /**
   * Adds the line numbers array to the end of the generated Groovy ModuleNode in a way suitable for
   * the LineNumberTransform AST transform to operate on it
   */
  private void addLineNumbers() {
    out.println();
    out.println("@LineNumber(");
    out.print("\tlines = [");
    // get the line numbers here.  this will mean that the last 2 lines will not be captured in the
    // line number information, but that's OK since a user cannot set a breakpoint there anyway.
    int[] lineNumbers = filterTrailing0s(out.getLineNumbers());

    for (int i = 0; i < lineNumbers.length; i++) {
      out.print(lineNumbers[i]);
      if (i < lineNumbers.length - 1) {
        out.print(", ");
      }
    }
    out.println("],");
    out.println("\tsourceName = \"" + sourceName + "\"");
    out.println(")");
    out.println("class ___LineNumberPlaceholder { }");
  }
  private void scriptletExpr() {
    if (!finalPass) {
      return;
    }

    LOG.debug("parse: expr");

    String text = scan.getToken().trim();
    out.printlnToResponse(text);
  }
 private void writeTagBodyStart(TagMeta tm) {
   if (tm.bufferMode) {
     tm.bufferMode = false;
     if (!bodyVarsDefined.contains(tm.tagIndex)) {
       // out.print("def ");
       bodyVarsDefined.add(tm.tagIndex);
     }
     out.println("createTagBody(" + tm.tagIndex + ", {->");
     closureLevel++;
   }
 }
  private void endTag() {
    if (!finalPass) return;

    String tagName = scan.getToken().trim();
    String ns = scan.getNamespace();

    if (tagMetaStack.isEmpty())
      throw new GrailsTagException(
          "Found closing Grails tag with no opening [" + tagName + "]",
          pageName,
          getCurrentOutputLineNumber());

    TagMeta tm = tagMetaStack.pop();
    String lastInStack = tm.name;
    String lastNamespaceInStack = tm.namespace;

    // if the tag name is blank then it has been closed by the start tag ie <tag />
    if (GrailsStringUtils.isBlank(tagName)) {
      tagName = lastInStack;
    }

    if (!lastInStack.equals(tagName) || !lastNamespaceInStack.equals(ns)) {
      throw new GrailsTagException(
          "Grails tag [" + lastNamespaceInStack + ":" + lastInStack + "] was not closed",
          pageName,
          getCurrentOutputLineNumber());
    }

    if (GroovyPage.DEFAULT_NAMESPACE.equals(ns) && tagRegistry.isSyntaxTag(tagName)) {
      if (tm.instance instanceof GroovySyntaxTag) {
        GroovySyntaxTag tag = (GroovySyntaxTag) tm.instance;
        tag.doEndTag();
      } else {
        throw new GrailsTagException(
            "Grails tag [" + tagName + "] was not closed", pageName, getCurrentOutputLineNumber());
      }
    } else {
      int bodyTagIndex = -1;
      if (!tm.emptyTag && !tm.bufferMode) {
        bodyTagIndex = tagIndex;
        out.println("})");
        closureLevel--;
      }

      if (tm.bufferMode && tm.bufferPartNumber != -1) {
        if (!bodyVarsDefined.contains(tm.tagIndex)) {
          // out.print("def ");
          bodyVarsDefined.add(tm.tagIndex);
        }
        out.println("createClosureForHtmlPart(" + tm.bufferPartNumber + ", " + tm.tagIndex + ")");
        bodyTagIndex = tm.tagIndex;
        tm.bufferMode = false;
      }

      if (jspTags.containsKey(ns)) {
        String uri = jspTags.get(ns);
        out.println("jspTag = getJspTag('" + uri + "', '" + tagName + "')");
        out.println(
            "if (!jspTag) throw new GrailsTagException('Unknown JSP tag "
                + ns
                + ":"
                + tagName
                + "')");
        out.print("jspTag.doTag(out," + attrsVarsMapDefinition.get(tagIndex) + ",");
        if (bodyTagIndex > -1) {
          out.print("getBodyClosure(" + bodyTagIndex + ")");
        } else {
          out.print("null");
        }
        out.println(")");
      } else {
        if (tm.hasAttributes) {
          out.println(
              "invokeTag('"
                  + tagName
                  + "','"
                  + ns
                  + "',"
                  + getCurrentOutputLineNumber()
                  + ","
                  + attrsVarsMapDefinition.get(tagIndex)
                  + ","
                  + bodyTagIndex
                  + ")");
        } else {
          out.println(
              "invokeTag('"
                  + tagName
                  + "','"
                  + ns
                  + "',"
                  + getCurrentOutputLineNumber()
                  + ",[:],"
                  + bodyTagIndex
                  + ")");
        }
      }
    }

    tm.bufferMode = false;

    tagIndex--;
  }
  private void page() {

    LOG.debug("parse: page");

    if (finalPass) {
      out.println();
      if (pluginAnnotation != null) {
        out.println(pluginAnnotation);
      }
      out.print("class ");
      out.print(className);
      out.println(" extends GroovyPage {");

      out.println(
          "public String getGroovyPageFileName() { \"" + pageName.replaceAll("\\\\", "/") + "\" }");
      out.println("public Object run() {");
      /*
      out.println("def params = binding.params");
      out.println("def request = binding.request");
      out.println("def flash = binding.flash");
      out.println("def response = binding.response");
      */
      out.println("Writer " + GroovyPage.OUT + " = getOut()");
      out.println("Writer " + GroovyPage.EXPRESSION_OUT + " = getExpressionOut()");
      // out.println("JspTagLib jspTag");
      if (sitemeshPreprocessMode) {
        out.println("registerSitemeshPreprocessMode()");
      }
    }

    loop:
    for (; ; ) {
      if (doNextScan) {
        state = scan.nextToken();
      } else {
        doNextScan = true;
      }

      // Flush any buffered whitespace if there's not a possibility of more whitespace
      // or a new tag which will handle flushing as necessary
      if ((state != GSTART_TAG) && (state != HTML)) {
        flushBufferedWhiteSpace();
        previousContentWasNonWhitespace = false; // well, we don't know
      }

      switch (state) {
        case EOF:
          break loop;
        case HTML:
          html();
          break;
        case JEXPR:
          scriptletExpr();
          break;
        case JSCRIPT:
          script(false);
          break;
        case JDIRECT:
          direct();
          break;
        case JDECLAR:
          declare(false);
          break;
        case GEXPR:
          expr();
          break;
        case GSCRIPT:
          script(true);
          break;
        case GDIRECT:
          direct();
          break;
        case GDECLAR:
          declare(true);
          break;
        case GSTART_TAG:
          startTag();
          break;
        case GEND_EMPTY_TAG:
        case GEND_TAG:
          endTag();
          break;
      }
    }

    if (finalPass) {
      if (!tagMetaStack.isEmpty()) {
        throw new GrailsTagException(
            "Grails tags were not closed! [" + tagMetaStack + "] in GSP " + pageName + "",
            pageName,
            getCurrentOutputLineNumber());
      }

      out.println("}");

      out.println("public static final Map " + CONSTANT_NAME_JSP_TAGS + " = new HashMap()");
      if (jspTags != null && jspTags.size() > 0) {
        out.println("static {");
        for (Map.Entry<String, String> entry : jspTags.entrySet()) {
          out.print("\t" + CONSTANT_NAME_JSP_TAGS + ".put('");
          out.print(escapeGroovy(entry.getKey()));
          out.print("','");
          out.print(escapeGroovy(entry.getValue()));
          out.println("')");
        }
        out.println("}");
      }

      out.println("protected void init() {");
      out.println("\tthis.jspTags = " + CONSTANT_NAME_JSP_TAGS);
      out.println("}");

      out.println(
          "public static final String "
              + CONSTANT_NAME_CONTENT_TYPE
              + " = '"
              + escapeGroovy(contentType)
              + "'");

      out.println(
          "public static final long " + CONSTANT_NAME_LAST_MODIFIED + " = " + lastModified + "L");

      out.println(
          "public static final String "
              + CONSTANT_NAME_EXPRESSION_CODEC
              + " = '"
              + escapeGroovy(expressionCodecDirectiveValue)
              + "'");
      out.println(
          "public static final String "
              + CONSTANT_NAME_STATIC_CODEC
              + " = '"
              + escapeGroovy(staticCodecDirectiveValue)
              + "'");
      out.println(
          "public static final String "
              + CONSTANT_NAME_OUT_CODEC
              + " = '"
              + escapeGroovy(outCodecDirectiveValue)
              + "'");
      out.println(
          "public static final String "
              + CONSTANT_NAME_TAGLIB_CODEC
              + " = '"
              + escapeGroovy(taglibCodecDirectiveValue)
              + "'");

      out.println("}");

      if (shouldAddLineNumbers()) {
        addLineNumbers();
      }
    } else {
      for (int i = 0; i < DEFAULT_IMPORTS.length; i++) {
        out.print("import ");
        out.println(DEFAULT_IMPORTS[i]);
      }
    }
  }
 private void htmlPartPrintlnRaw(int partNumber) {
   out.print("printHtmlPart(");
   out.print(String.valueOf(partNumber));
   out.print(")");
   out.println();
 }
 public int[] getLineNumberMatrix() {
   return out.getLineNumbers();
 }