SyntaxTreeBuilder.java revision 56ed4167b942ec265f9cee70ac4d71d10b3835ce
1/* 2 * Copyright (C) 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.clearsilver.jsilver.syntax; 18 19import com.google.clearsilver.jsilver.autoescape.EscapeMode; 20import com.google.clearsilver.jsilver.exceptions.JSilverBadSyntaxException; 21import com.google.clearsilver.jsilver.exceptions.JSilverIOException; 22import com.google.clearsilver.jsilver.syntax.lexer.Lexer; 23import com.google.clearsilver.jsilver.syntax.lexer.LexerException; 24import com.google.clearsilver.jsilver.syntax.node.Start; 25import com.google.clearsilver.jsilver.syntax.node.Switch; 26import com.google.clearsilver.jsilver.syntax.parser.Parser; 27import com.google.clearsilver.jsilver.syntax.parser.ParserException; 28 29import java.io.IOException; 30import java.io.PushbackReader; 31import java.io.Reader; 32import java.util.Arrays; 33 34/** 35 * Parses a JSilver text template into an abstract syntax tree (AST). 36 * <p/> 37 * Acts as a facade around SableCC generated code. The simplest way to process the resulting tree is 38 * to use a visitor by extending 39 * {@link com.google.clearsilver.jsilver.syntax.analysis.DepthFirstAdapter} and passing it to 40 * {@link Start#apply(com.google.clearsilver.jsilver.syntax.node.Switch)}. 41 * <p/> 42 * <h3>Example:</h3> 43 * 44 * <pre> 45 * SyntaxTreeBuilder builder = new SyntaxTreeBuilder(); 46 * Start tree = builder.parse(myTemplate, "some-template.cs"); 47 * // Dump out the tree 48 * tree.apply(new SyntaxTreeDumper(System.out)); 49 * </pre> 50 * 51 */ 52public class SyntaxTreeBuilder { 53 54 public SyntaxTreeBuilder() {} 55 56 /** 57 * Size of buffer in PushbackReader... needs to be large enough to parse CS opening tag and push 58 * back if it is not valid. e.g. "<?csX" : not a tag, so pushback. 59 */ 60 private static final int PUSHBACK_SIZE = "<?cs ".length(); 61 62 /** 63 * Syntax tree optimizers, declared in the order they must be applied: 64 * <ol> 65 * <li>Type resultion makes the abstract tree concrete and must come first. 66 * <li>Sequence optimization simplifies the tree and should come before most other optimizations. 67 * <li>Inline rewriting to remove data nodes from 'inline' sections. This should come before any 68 * optimization of variables. 69 * <li>Var optimization simplifies complex var expressions and must come after both type 70 * resolution and sequence optimization. 71 * </ol> 72 */ 73 protected final Switch typeResolver = new TypeResolver(); 74 protected final Switch sequenceOptimizer = new SequenceOptimizer(); 75 protected final Switch inlineRewriter = new InlineRewriter(); 76 protected final Switch varOptimizer = new VarOptimizer(Arrays.asList("html", "js", "url")); 77 78 /** 79 * Perform any additional processing on the tree. EscapeMode and templateName are required by 80 * AutoEscaper. 81 * 82 * @param root The AST to post process. 83 * @param escapeMode The escaping mode to apply to the given AST. If this is not 84 * EscapeMode.ESCAPE_NONE, AutoEscaper will be called on the AST. 85 * @param templateName The name of template being processed. Passed to AutoEscaper, which uses it 86 * when displaying error messages. 87 */ 88 protected void process(Start root, EscapeMode escapeMode, String templateName) { 89 root.apply(typeResolver); 90 root.apply(sequenceOptimizer); 91 root.apply(inlineRewriter); 92 // Temporarily disabled ('cos it doesn't quite work) 93 // root.apply(varOptimizer); 94 95 if (!escapeMode.equals(EscapeMode.ESCAPE_NONE)) { 96 // AutoEscaper contains per-AST context like HTML parser object. 97 // Therefore, instantiating a new AutoEscaper each time. 98 root.apply(new AutoEscaper(escapeMode, templateName)); 99 } 100 } 101 102 /** 103 * @param templateName Used for meaningful error messages. 104 * @param escapeMode Run {@link AutoEscaper} on the abstract syntax tree created from template. 105 */ 106 public TemplateSyntaxTree parse(Reader input, String templateName, EscapeMode escapeMode) 107 throws JSilverIOException, JSilverBadSyntaxException { 108 try { 109 PushbackReader pushbackReader = new PushbackReader(input, PUSHBACK_SIZE); 110 Lexer lexer = new Lexer(pushbackReader); 111 Parser parser = new Parser(lexer); 112 Start root = parser.parse(); 113 process(root, escapeMode, templateName); 114 return new TemplateSyntaxTree(root); 115 } catch (IOException exception) { 116 throw new JSilverIOException(exception); 117 } catch (ParserException exception) { 118 throw new JSilverBadSyntaxException(exception.getMessage(), exception.getToken().getText(), 119 templateName, exception.getToken().getLine(), exception.getToken().getPos(), exception); 120 } catch (LexerException exception) { 121 throw new JSilverBadSyntaxException(exception.getMessage(), null, templateName, 122 JSilverBadSyntaxException.UNKNOWN_POSITION, JSilverBadSyntaxException.UNKNOWN_POSITION, 123 exception); 124 } 125 } 126} 127