View Javadoc

1   package net.sf.jstp;
2   
3   import java.io.*;
4   import java.util.*;
5   
6   public class JstpTranslator
7   {    
8       static public void translate(String pkgName, String className, Reader input, Writer output) throws IOException, JstpParserException
9       {
10          String RENDER_METHOD = "public void render(java.io.PrintWriter out)";
11          String TEXT_WRAPPER  = "out.print";
12          String EXPR_WRAPPER  = "String.valueOf";
13          String INDENTATION   = "    ";
14          boolean WS_GOBBLING  = true;
15  
16          PrintWriter out = (output instanceof PrintWriter)? (PrintWriter)output : new PrintWriter(output);
17  
18          JstpParser parser = new JstpParser(input);
19          parser.parse();
20  
21          String superClassName = null;
22          String importList = null;
23          List declarations = new ArrayList();
24          List renderSegments = new ArrayList();
25  
26          for(int i=0; i<parser.elements.size(); i++)
27          {
28              JstpElement elem = (JstpElement)parser.elements.get(i);
29              switch(elem.type)
30              {
31                  case JstpElement.TYPE_COMMENT :
32                      //nothing
33                      break;
34  
35                  case JstpElement.TYPE_DECLARATION :
36                      declarations.add(elem);
37                      break;
38  
39                  case JstpElement.TYPE_SCRIPTLET :
40                      renderSegments.add(elem);
41                      break;
42  
43                  case JstpElement.TYPE_EXPRESSION :
44                      if(isBlank(elem.content))
45                          throw new JstpParserException("empty expression", elem.row,  elem.col); 
46                      renderSegments.add(elem);
47                      break;
48  
49                  case JstpElement.TYPE_TEXT :
50                      renderSegments.add(elem);
51                      break;
52  
53                  case JstpElement.TYPE_DIRECTIVE :
54                      if(!elem.directiveName.equals("page"))
55                          throw new JstpParserException("directive "+elem.directiveName+" not supported", elem.row,  elem.col);
56                      for(Iterator ater=elem.directiveAttributes.keySet().iterator(); ater.hasNext();)
57                      {
58                          String attrName = (String)ater.next();
59                          String attrValue = (String)elem.directiveAttributes.get(attrName);
60                          if(attrName.equals("package"))
61                              pkgName = attrValue;
62                          else if(attrName.equals("extends"))
63                              superClassName = attrValue;
64                          else if(attrName.equals("import"))
65                              importList = attrValue;
66                          else if(attrName.equals("render-method"))
67                              RENDER_METHOD = attrValue;
68                          else if(attrName.equals("text-wrapper"))
69                              TEXT_WRAPPER = attrValue;
70                          else if(attrName.equals("expr-wrapper"))
71                              EXPR_WRAPPER = attrValue;
72                          else if(attrName.equals("ws-gobbling"))
73                              WS_GOBBLING = attrValue.equals("true");
74                          else
75                              throw new JstpParserException("page directive attribute "+attrName+" not supported", elem.row,  elem.col);
76                      }
77                      break;
78  
79                  default : 
80                      throw new JstpParserException("internal error, unknown segment type "+elem.type, elem.row,  elem.col);
81              }
82          }
83  
84          out.println("/* The following code was generated by JstpTranslator on "+Calendar.getInstance().getTime()+" */");
85          if(pkgName!=null)
86              out.println("package "+pkgName+";");
87          out.println();
88  
89          if(importList!=null)
90          {
91              StringTokenizer tknz = new StringTokenizer(importList, ", \t\f\r\n");
92              while(tknz.hasMoreTokens())
93                  out.println("import "+tknz.nextToken()+";");
94              out.println();
95          }
96  
97          out.print("public class "+className);
98          if(superClassName!=null)
99              out.println(" extends "+superClassName);
100         else
101             out.println();
102         out.println("{");
103 
104         for(Iterator iter=declarations.iterator(); iter.hasNext();)
105         {
106             JstpElement decl = (JstpElement)iter.next();
107             out.println(decl.content.toString());
108         }
109 
110         out.println(INDENTATION+RENDER_METHOD);
111         out.println(INDENTATION+"{");
112         for(Iterator iter=renderSegments.iterator(); iter.hasNext();)
113         {
114             JstpElement elem = (JstpElement)iter.next();
115             switch(elem.type)
116             {
117                 case JstpElement.TYPE_SCRIPTLET :
118                     out.println(elem.content.toString());
119                     break;
120                     
121                 case JstpElement.TYPE_EXPRESSION :
122                     out.print(INDENTATION+INDENTATION +TEXT_WRAPPER+'(' );
123                     out.print(    EXPR_WRAPPER+'('+elem.content+')'     );
124                     out.println(");");
125                     break;
126                     
127                 case JstpElement.TYPE_TEXT :
128                     boolean gobbled = false;
129                     if(WS_GOBBLING && isBlank(elem.content))
130                     {
131                         char last = elem.content.charAt(elem.content.length()-1);
132                         JstpElement porn = (last=='\r' || last=='\n')? elem.prev : elem.next;
133                         gobbled = porn!=null && porn.type!=JstpElement.TYPE_TEXT && porn.type!=JstpElement.TYPE_EXPRESSION;
134                     }
135                     if(!gobbled)
136                     {
137                         out.print(INDENTATION+INDENTATION +TEXT_WRAPPER+'(' );
138                         out.print(    toJavaStringLiteral(elem.content)     );
139                         out.println(");");
140                     }
141                     break;
142                     
143                 default : 
144                     throw new Error("assertion error, not a render segment type "+elem.type);
145             }
146         }
147         out.println(INDENTATION+"}");
148 
149         out.println("}");
150     }
151 
152     static public void main(String args[]) throws Exception
153     {
154         if(args.length!=1 && args.length!=2)
155         {
156             System.out.println("usage: java net.sf.jstp.JstpTranslator jstpFile [javaFile]");
157             System.exit(1);
158         }
159         
160         File srcFile = new File(args[0]);
161         String className = srcFile.getName();
162         int y = className.indexOf('.');
163         if(y!=-1)
164             className = className.substring(0, y);
165         
166         File desFile = args.length==1 ?
167                 new File(srcFile.getParent(), className+".java") :
168                 new File(args[1]);
169         if(!desFile.getParentFile().exists())
170             desFile.getParentFile().mkdirs();
171         
172         InputStream in = null;
173         OutputStream out = null;
174         try
175         {
176             in = new BufferedInputStream(new FileInputStream(srcFile));
177             out = new BufferedOutputStream(new FileOutputStream(desFile));
178             Reader reader = new InputStreamReader(in);
179             Writer writer = new OutputStreamWriter(out);
180             
181             try
182             {
183                 JstpTranslator.translate(null, className, reader, writer);
184                 System.out.println("generated "+desFile);
185             }
186             catch (JstpParserException e)
187             {
188                 throw new Error("error translating "+srcFile+" ("+e.row+":"+e.col+") "+e, e);
189             }
190             
191             writer.flush();
192         }
193         finally
194         {
195             if(out!=null) out.close();
196             if(in!=null) in.close();
197         }
198     }
199     
200     
201     //--------------------------------------------------------
202     
203     static boolean isBlank(StringBuffer buf)
204     {
205         for(int i=0; i<buf.length(); i++)
206         {
207             if(!Character.isSpace(buf.charAt(i)))
208                 return false;
209         }
210         return true;
211     }
212     static String toJavaStringLiteral(StringBuffer in)
213     {
214         StringBuffer out = new StringBuffer();
215         out.append('"');
216         for(int i=0; i<in.length(); i++)
217         {
218             char c = in.charAt(i);
219             switch(c)
220             {
221                 case '\b' : out.append('//').append('b'); break;
222                 case '\t' : out.append('//').append('t'); break;
223                 case '\n' : out.append('//').append('n'); break;
224                 case '\f' : out.append('//').append('f'); break;
225                 case '\r' : out.append('//').append('r'); break;
226                 case '\"' : out.append('//').append('\"'); break;
227                 case '//' : out.append('//').append('//'); break;
228                 default   : out.append(c);
229             }
230         }
231         out.append('"');
232         return out.toString();
233     }
234 
235     
236     
237 }