001 
002 /*
003  *  Descripter 1.0 - Java Script Engines
004  *  Copyright (C) 2010-2015  Jianjun Liu (J.J.Liu)
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package org.descripter.js;
021 
022 import org.descripter.js.api.Script;
023 
024 /**
025  * <p>An abstract base class for JavaScript parser visitors.</p>
026  * 
027  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.descripter.org" target="_blank">http://www.descripter.org</a>
028  * @since Descripter 1.0
029  */
030 public abstract class Visitor<S extends Script<?>> extends Script<S>
031 {
032     /**
033      * <p><tt>true</tt> for debug mode; <tt>false</tt>, otherwise.</p>
034      * @since Descripter 1.0
035      */
036     public final static boolean DEBUG = false;
037 
038     /**
039      * <p>Prints debug information for an object.</p>
040      * <p>This method simply prints out the simple class name of the specified object.</p>
041      * @param o The object
042      * @since Descripter 1.0
043      */
044     protected final void debug(Object o) {
045         print(o.getClass().getSimpleName());
046     }
047 
048     /**
049      * <p>Constructs a visitor of this type.</p>
050      * @param script A script context.
051      * @since Descripter 1.0
052      */
053     protected Visitor(S script) {
054         super(script);
055     }
056 
057     /**
058      * <p>Executes the current script context.</p>
059      * <p>This method simply throws an {@link UnsupportedOperationException}.</p>
060      * @since Descripter 1.0
061      */
062     @Override
063     public final void run() {
064         throw new UnsupportedOperationException();
065     }
066 
067     /**
068      * <p>Concatenates the arguments with the specified separator.</p>
069      * @param sep The separator
070      * @param args The arguments
071      * @return The concatenated string
072      * @since Descripter 1.0
073      */
074     protected static String concat(String sep, Object...args) {
075         StringBuilder sb = new StringBuilder();
076         if (args != null && args.length > 0) {
077             sb.append(args[0]);
078             for (int i = 1; i < args.length; i++) {
079                 if (sep != null) {
080                     sb.append(sep);
081                 }
082                 sb.append(args[i]);
083             }
084         }
085         return sb.toString();
086     }
087 
088     /**
089      * <p>Concatenates the arguments without a separator.</p>
090      * @param args The arguments
091      * @return The concatenated string
092      * @since Descripter 1.0
093      */
094     protected static String cat(Object...args) {
095         return concat(null, args);
096     }
097 
098     /**
099      * <p>Concatenates the arguments with a space separator.</p>
100      * @param args The arguments
101      * @return The concatenated string
102      * @since Descripter 1.0
103      */
104     protected static String cats(Object...args) {
105         return concat(" ", args);
106     }
107 
108     /**
109      * <p>Concatenates the arguments with a new-line separator.</p>
110      * @param args The arguments
111      * @return The concatenated string
112      * @since Descripter 1.0
113      */
114     protected static String catn(Object...args) {
115         return concat(System.lineSeparator(), args);
116     }
117 
118     /**
119      * <p>Concatenates the arguments with a comma separator.</p>
120      * @param args The arguments
121      * @return The concatenated string
122      * @since Descripter 1.0
123      */
124     protected static String list(Object...args) {
125         return concat(", ", args);
126     }
127 
128     /**
129      * <p>Groups an argument.</p>
130      * @param arg The argument to parenthesize
131      * @return The string of the parenthesized argument.
132      * @since Descripter 1.0
133      */
134     protected static String arg(Object arg) {
135         return cat("(", arg, ")");
136     }
137 
138     /**
139      * <p>Groups a list of the base and the arguments.</p>
140      * @param base The base argument
141      * @param args The arguments
142      * @return The string of the parenthesized list of the base and the arguments.
143      * @since Descripter 1.0
144      */
145     protected static String args(Object base, Object...args) {
146         return args != null && args.length > 0 ? arg(list(base, list(args))) : arg(base);
147     }
148 
149     /**
150      * <p>Casts the argument to an array.</p>
151      * @param data The argument
152      * @return The array of {@link Object}.
153      * @since Descripter 1.0
154      */
155     protected static Object[] arr(Object data) {
156         return (Object[])data;
157     }
158 
159     /**
160      * <p>Returns a boolean evaluation of an argument when necessary.</p>
161      * @param arg The argument
162      * @return The boolean evaluation of the argument.
163      * @since Descripter 1.0
164      */
165     protected static Object car(Object arg) {
166         return arg instanceof Bool ? arg : cat("bool", arg(arg));
167     }
168 
169     /**
170      * <p>Returns a conditional action over an argument.</p>
171      * @param arg The argument
172      * @return The conditional action over the argument.
173      * @since Descripter 1.0
174      */
175     protected static String cnd(String act, Object arg) {
176         return cat(act, arg(arg));
177     }
178 
179     /**
180      * <p>Appends a new-line to the argument.</p>
181      * @param arg The argument
182      * @return The appended string.
183      * @since Descripter 1.0
184      */
185     protected static String ln(Object arg) {
186         return cat(arg, "\n");
187     }
188 
189     /**
190      * <p>Prepends a tab to the argument.</p>
191      * @param arg The argument
192      * @return The prepended string.
193      * @since Descripter 1.0
194      */
195     protected static String tab(Object arg) {
196         return cat("\t", arg);
197     }
198 
199     /**
200      * <p>Prepends two tabs to the argument.</p>
201      * @param arg The argument
202      * @return The prepended string.
203      * @since Descripter 1.0
204      */
205     protected static String tab2(Object arg) {
206         return cat("\t\t", arg);
207     }
208 
209     /**
210      * <p>Prepends three tabs to the argument.</p>
211      * @param arg The argument
212      * @return The prepended string.
213      * @since Descripter 1.0
214      */
215     protected static String tab3(Object arg) {
216         return tab(tab2(arg));
217     }
218 
219     /**
220      * <p>Prepends four tabs to the argument.</p>
221      * @param arg The argument
222      * @return The prepended string.
223      * @since Descripter 1.0
224      */
225     protected static String tab4(Object arg) {
226         return tab2(tab2(arg));
227     }
228 
229     /**
230      * <p>Returns an invocation over an object without arguments.</p>
231      * @param o The {@link Object} to invoke
232      * @return The invocation over the object without arguments.
233      * @since Descripter 1.0
234      */
235     protected static String def(Object o) {
236         return cat(o, "()");
237     }
238 
239     /**
240      * <p>Returns an expression of a generic type with a parameter.</p>
241      * @param t The generic type
242      * @param p The parameter
243      * @return The expression of the generic type with the parameter.
244      * @since Descripter 1.0
245      */
246     protected static String par(Object t, Object p) {
247         return cat(t, "<", p, ">");
248     }
249 
250     /**
251      * <p>Returns an expression of a member reference to an object.</p>
252      * @param obj The base object
253      * @param ref The member to reference
254      * @return The expression of the member reference to the object.
255      * @since Descripter 1.0
256      */
257     protected static String ref(Object obj, Object ref) {
258         return cat(obj, ".", ref);
259     }
260 
261     /**
262      * <p>Returns an expression to execute a base object.</p>
263      * @param bas The base object to execute
264      * @return The expression to execute the base object.
265      * @since Descripter 1.0
266      */
267     protected static String run(Object bas) {
268         return def(ref(bas, "run"));
269     }
270 
271     /**
272      * <p>Returns an invocation of a function with arguments.</p>
273      * @param fun The function to invoke
274      * @param args The arguments to pass to the invocation
275      * @return The invocation of the function with the arguments.
276      * @since Descripter 1.0
277      */
278     protected static String inv(String fun, Object... args) {
279         return cat(fun, arg(list(args)));
280     }
281 
282     /**
283      * <p>Returns a new expression of a class with arguments.</p>
284      * @param cls The class to construct
285      * @param args The arguments to pass to the constructor
286      * @return The construction of the class with the arguments.
287      * @since Descripter 1.0
288      */
289     protected static String nevv(String cls, Object... args) {
290         return cats("new", inv(cls, args));
291     }
292 
293     /**
294      * <p>Returns a cast expression of a type over an argument.</p>
295      * @param type The target type to cast
296      * @param arg The argument to cast
297      * @return The cast expression of the type over the argument.
298      * @since Descripter 1.0
299      */
300     protected static String cast(String type, Object arg) {
301         return cat(arg(type), arg);
302     }
303 
304     /**
305      * <p>Returns a statement from an argument.</p>
306      * @param arg The argument
307      * @return The string of the statement.
308      * @since Descripter 1.0
309      */
310     protected static String stmt(Object arg) {
311         return cat(arg, ";");
312     }
313 
314     /**
315      * <p>Returns a Java string literal from a JavaScript one.</p>
316      * @param s A JavaScript string literal
317      * @return The escaped Java string literal.
318      * @since Descripter 1.0
319      */
320     protected static final String str(String s) {
321         return qt(esc(s.substring(1, s.length() - 1)));
322     }
323 
324     /**
325      * <p>Escapes a string.</p>
326      * @param s The string to escape
327      * @return The escaped string.
328      * @since Descripter 1.0
329      */
330     protected static final String esc(String s) {
331         int len = s.length();
332         StringBuilder sb = new StringBuilder(len);
333         for (int i = 0; i < len; i++) {
334             char c = s.charAt(i);
335             if (c > 0xfff) {
336                 sb.append("\\u").append(Integer.toHexString(c));
337             } else if (c > 0xff) {
338                 sb.append("\\u0").append(Integer.toHexString(c));
339             } else if (c > 0x7f) {
340                 sb.append("\\u00").append(Integer.toHexString(c));
341             } else if (c < 32) {
342                 switch (c) {
343                     case '\b':
344                         sb.append('\\').append('b');
345                         break;
346                     case '\n':
347                         sb.append('\\').append('n');
348                         break;
349                     case '\t':
350                         sb.append('\\').append('t');
351                         break;
352                     case '\f':
353                         sb.append('\\').append('f');
354                         break;
355                     case '\r':
356                         sb.append('\\').append('r');
357                         break;
358                     default :
359                         if (c > 0xf) {
360                             sb.append("\\u00").append(Integer.toHexString(c));
361                         } else {
362                             sb.append("\\u000").append(Integer.toHexString(c));
363                         }
364                         break;
365                 }
366             } else {
367                 switch (c) {
368                     case '"':
369                         sb.append('\\').append('"');
370                         break;
371                     case '\\':
372                         sb.append('\\').append('\\');
373                         break;
374                     default :
375                         sb.append(c);
376                         break;
377                 }
378             }
379         }
380         return sb.toString();
381     }
382 
383     /**
384      * <p>Returns a double-quoted string literal for Java source.</p>
385      * @param s A string
386      * @return The Java string literal.
387      * @since Descripter 1.0
388      */
389     protected static final String qt(String s) {
390         return cat("\"", s, "\"");
391     }
392 
393     /**
394      * <p>Returns an assignment expression.</p>
395      * @param var The variable
396      * @param arg The value argument
397      * @return The string of the assignment expression.
398      * @since Descripter 1.0
399      */
400     protected static final String asg(Object var, Object arg) {
401         return cat(var, ".", "assign", arg(arg));
402     }
403 }