/* * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.clearsilver.jsilver.syntax; import com.google.clearsilver.jsilver.autoescape.EscapeMode; import com.google.clearsilver.jsilver.exceptions.JSilverIOException; import com.google.clearsilver.jsilver.syntax.analysis.DepthFirstAdapter; import com.google.clearsilver.jsilver.syntax.node.EOF; import com.google.clearsilver.jsilver.syntax.node.Node; import com.google.clearsilver.jsilver.syntax.node.Start; import com.google.clearsilver.jsilver.syntax.node.Token; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.Reader; /** * Dumps the syntax tree to text. Useful for debugging and understanding how the tree is structured. */ public class SyntaxTreeDumper extends DepthFirstAdapter { private final Appendable out; private final String newLine = System.getProperty("line.separator"); private int indent; public SyntaxTreeDumper(Appendable out) { this.out = out; } /** * Dumps to System.out. */ public SyntaxTreeDumper() { this(System.out); } @Override public void defaultIn(Node node) { write(nodeName(node) + " {"); indent++; } @Override public void defaultOut(Node node) { indent--; write("}"); } @Override public void defaultCase(Node node) { write(nodeName(node)); } private String nodeName(Node node) { if (node instanceof Start || node instanceof EOF) { return node.getClass().getSimpleName(); } else if (node instanceof Token) { Token token = (Token) node; String tokenType = token.getClass().getSimpleName().substring(1); return tokenType + " [line:" + token.getLine() + ",pos:" + token.getPos() + "] \"" + escape(token.getText()) + "\""; } else { // Turn PSomeProduction, AConcreteSomeProduction // Into SomeProduction, Concrete String p = node.getClass().getSuperclass().getSimpleName().substring(1); String a = node.getClass().getSimpleName().substring(1); a = a.substring(0, a.length() - p.length()); return "<" + a + ">" + p; } } private String escape(String text) { StringBuilder result = new StringBuilder(); for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); switch (c) { case '\\': result.append("\\\\"); break; case '"': result.append("\\\""); break; case '\n': result.append("\\n"); break; case '\r': result.append("\\r"); break; case '\t': result.append("\\t"); break; default: result.append(c); } } return result.toString(); } private void write(String text) { try { // Write to temp string in case output isn't buffered. StringBuilder line = new StringBuilder(); for (int i = 0; i < indent; i++) { line.append(" "); } line.append(text); line.append(newLine); out.append(line); } catch (IOException e) { throw new JSilverIOException(e); } } /** * Simple command line tool for parsing a template and dumping out the AST. */ public static void main(String[] args) throws IOException { if (args.length == 0) { System.err.println("Provide filename of template."); return; } String filename = args[0]; Reader reader = new BufferedReader(new FileReader(filename)); try { SyntaxTreeBuilder builder = new SyntaxTreeBuilder(); TemplateSyntaxTree tree = builder.parse(reader, filename, EscapeMode.ESCAPE_NONE); tree.apply(new SyntaxTreeDumper(System.out)); } finally { reader.close(); } } }