コード例 #1
0
  protected Mustache compile(
      final Reader reader,
      String tag,
      final AtomicInteger currentLine,
      String file,
      String sm,
      String em,
      boolean startOfLine)
      throws MustacheException {
    if (reader == null) {
      throw new MustacheException("Reader is null");
    }
    Reader br;
    if (reader.markSupported()) {
      br = reader;
    } else {
      br = new BufferedReader(reader);
    }
    try {
      boolean sawCR = false;
      int startLine = currentLine.get();
      MustacheVisitor mv = mf.createMustacheVisitor();
      // Now we grab the mustache template
      boolean onlywhitespace = true;
      // Starting a new line
      boolean iterable = currentLine.get() != 0;
      currentLine.compareAndSet(0, 1);
      StringBuilder out = new StringBuilder();
      try {
        int c;
        while ((c = br.read()) != -1) {
          if (c == '\r') {
            sawCR = true;
            continue;
          }
          // Increment the line
          if (c == '\n') {
            currentLine.incrementAndGet();
            if (!iterable || (iterable && !onlywhitespace)) {
              if (sawCR) out.append("\r");
              out.append("\n");
            }
            out = write(mv, out, file, currentLine.intValue(), startOfLine);

            iterable = false;
            onlywhitespace = true;
            startOfLine = true;
            continue;
          }
          sawCR = false;
          // Check for a mustache start
          if (c == sm.charAt(0)) {
            br.mark(1);
            if (sm.length() == 1 || br.read() == sm.charAt(1)) {
              // Two mustaches, now capture command
              StringBuilder sb = new StringBuilder();
              while ((c = br.read()) != -1) {
                br.mark(1);
                if (c == em.charAt(0)) {
                  if (em.length() > 1) {
                    if (br.read() == em.charAt(1)) {
                      // Matched end
                      break;
                    } else {
                      // Only one
                      br.reset();
                    }
                  } else break;
                }
                sb.append((char) c);
              }
              final String command = mf.translate(sb.toString());
              if (command.length() == 0) {
                throw new MustacheException("Empty mustache in " + file + ":" + currentLine);
              }
              final char ch = command.charAt(0);
              final String variable = command.substring(1).trim();
              switch (ch) {
                case '#':
                case '^':
                case '<':
                case '$':
                  {
                    boolean oldStartOfLine = startOfLine;
                    startOfLine = startOfLine & onlywhitespace;
                    int line = currentLine.get();
                    final Mustache mustache =
                        compile(br, variable, currentLine, file, sm, em, startOfLine);
                    int lines = currentLine.get() - line;
                    if (!onlywhitespace || lines == 0) {
                      write(mv, out, file, currentLine.intValue(), oldStartOfLine);
                    }
                    out = new StringBuilder();
                    switch (ch) {
                      case '#':
                        mv.iterable(
                            new TemplateContext(sm, em, file, line, startOfLine),
                            variable,
                            mustache);
                        break;
                      case '^':
                        mv.notIterable(
                            new TemplateContext(sm, em, file, line, startOfLine),
                            variable,
                            mustache);
                        break;
                      case '<':
                        mv.extend(
                            new TemplateContext(sm, em, file, line, startOfLine),
                            variable,
                            mustache);
                        break;
                      case '$':
                        mv.name(
                            new TemplateContext(sm, em, file, line, startOfLine),
                            variable,
                            mustache);
                        break;
                    }
                    iterable = lines != 0;
                    break;
                  }
                case '/':
                  {
                    // Tag end
                    if (!startOfLine || !onlywhitespace) {
                      write(mv, out, file, currentLine.intValue(), startOfLine);
                    }
                    if (!variable.equals(tag)) {
                      throw new MustacheException(
                          "Mismatched start/end tags: "
                              + tag
                              + " != "
                              + variable
                              + " in "
                              + file
                              + ":"
                              + currentLine);
                    }

                    return mv.mustache(new TemplateContext(sm, em, file, 0, startOfLine));
                  }
                case '>':
                  {
                    out = write(mv, out, file, currentLine.intValue(), startOfLine);
                    startOfLine = startOfLine & onlywhitespace;
                    mv.partial(
                        new TemplateContext(sm, em, file, currentLine.get(), startOfLine),
                        variable);
                    break;
                  }
                case '{':
                  {
                    out = write(mv, out, file, currentLine.intValue(), startOfLine);
                    // Not escaped
                    String name = variable;
                    if (em.charAt(1) != '}') {
                      name = variable.substring(0, variable.length() - 1);
                    } else {
                      if (br.read() != '}') {
                        throw new MustacheException(
                            "Improperly closed variable in " + file + ":" + currentLine);
                      }
                    }
                    final String finalName = name;
                    mv.value(
                        new TemplateContext(sm, em, file, currentLine.get(), false),
                        finalName,
                        false);
                    break;
                  }
                case '&':
                  {
                    // Not escaped
                    out = write(mv, out, file, currentLine.intValue(), startOfLine);
                    mv.value(
                        new TemplateContext(sm, em, file, currentLine.get(), false),
                        variable,
                        false);
                    break;
                  }
                case '%':
                  // Pragmas
                  out = write(mv, out, file, currentLine.intValue(), startOfLine);
                  int index = variable.indexOf(" ");
                  String pragma;
                  String args;
                  if (index == -1) {
                    pragma = variable;
                    args = null;
                  } else {
                    pragma = variable.substring(0, index);
                    args = variable.substring(index + 1);
                  }
                  mv.pragma(
                      new TemplateContext(sm, em, file, currentLine.get(), startOfLine),
                      pragma,
                      args);
                  break;
                case '!':
                  // Comment
                  mv.comment(
                      new TemplateContext(sm, em, file, currentLine.get(), startOfLine), variable);
                  out = write(mv, out, file, currentLine.intValue(), startOfLine);
                  break;
                case '=':
                  // Change delimiters
                  out = write(mv, out, file, currentLine.intValue(), startOfLine);
                  String delimiters = command.replaceAll("\\s+", "");
                  int length = delimiters.length();
                  if (length > 6 || length / 2 * 2 != length) {
                    throw new MustacheException("Invalid delimiter string");
                  }
                  sm = delimiters.substring(1, length / 2);
                  em = delimiters.substring(length / 2, length - 1);
                  break;
                default:
                  {
                    if (c == -1) {
                      throw new MustacheException(
                          "Improperly closed variable in " + file + ":" + currentLine);
                    }
                    // Reference
                    out = write(mv, out, file, currentLine.intValue(), startOfLine);
                    mv.value(
                        new TemplateContext(sm, em, file, currentLine.get(), false),
                        command.trim(),
                        true);
                    break;
                  }
              }
              // Additional text is no longer at the start of the line
              startOfLine = false;
              continue;
            } else {
              // Only one
              br.reset();
            }
          }
          onlywhitespace = onlywhitespace && (c == ' ' || c == '\t' || c == '\r');
          out.append((char) c);
        }
        write(mv, out, file, currentLine.intValue(), startOfLine);
        if (tag == null) {
          br.close();
        } else {
          throw new MustacheException("Failed to close '" + tag + "' tag at line " + startLine);
        }
      } catch (IOException e) {
        throw new MustacheException("Failed to read", e);
      }
      mv.eof(new TemplateContext(sm, em, file, currentLine.get(), startOfLine));
      return mv.mustache(new TemplateContext(sm, em, file, 0, startOfLine));
    } catch (MustacheException me) {
      try {
        // We're going to blow the whole stack of compilation and
        // close the readers on the way up.
        br.close();
      } catch (IOException e) {
        // Ignore IOExceptions on close
      }
      throw me;
    }
  }
コード例 #2
0
 /** Ignore empty strings and append to the previous code if it was also a write. */
 private StringBuilder write(
     MustacheVisitor mv, StringBuilder out, String file, int line, boolean startOfLine) {
   String text = out.toString();
   mv.write(new TemplateContext(null, null, file, line, startOfLine), text);
   return new StringBuilder();
 }