golf 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. data/golf.gemspec +1 -1
  2. data/lib/golf/version.rb +1 -1
  3. metadata +1 -121
  4. data/golf-java/README.markdown +0 -41
  5. data/golf-java/THANKS.markdown +0 -14
  6. data/golf-java/build/classes.zip +0 -0
  7. data/golf-java/build/com/thinkminimo/golf/GolfResource$MimeMapping$MimeMappingSingleton.class +0 -0
  8. data/golf-java/build/com/thinkminimo/golf/GolfResource$MimeMapping.class +0 -0
  9. data/golf-java/build/com/thinkminimo/golf/GolfResource.class +0 -0
  10. data/golf-java/build/com/thinkminimo/golf/GolfServlet$1.class +0 -0
  11. data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfContext.class +0 -0
  12. data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfParams.class +0 -0
  13. data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfSession.class +0 -0
  14. data/golf-java/build/com/thinkminimo/golf/GolfServlet$PermanentRedirectException.class +0 -0
  15. data/golf-java/build/com/thinkminimo/golf/GolfServlet$RedirectException.class +0 -0
  16. data/golf-java/build/com/thinkminimo/golf/GolfServlet$StoredJSVM.class +0 -0
  17. data/golf-java/build/com/thinkminimo/golf/GolfServlet.class +0 -0
  18. data/golf-java/build/com/thinkminimo/golf/JsonpTunnel.class +0 -0
  19. data/golf-java/build/com/thinkminimo/golf/Main$1.class +0 -0
  20. data/golf-java/build/com/thinkminimo/golf/Main$RingList.class +0 -0
  21. data/golf-java/build/com/thinkminimo/golf/Main.class +0 -0
  22. data/golf-java/build/com/thinkminimo/golf/ProxyServlet.class +0 -0
  23. data/golf-java/build/com/yahoo/platform/yui/compressor/CssCompressor.class +0 -0
  24. data/golf-java/build/com/yahoo/platform/yui/compressor/JarClassLoader.class +0 -0
  25. data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptCompressor.class +0 -0
  26. data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.class +0 -0
  27. data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptToken.class +0 -0
  28. data/golf-java/build/com/yahoo/platform/yui/compressor/ScriptOrFnScope.class +0 -0
  29. data/golf-java/build/depends.zip +0 -0
  30. data/golf-java/build/golf +0 -2
  31. data/golf-java/build/org/json/JSONArray.class +0 -0
  32. data/golf-java/build/org/json/JSONException.class +0 -0
  33. data/golf-java/build/org/json/JSONObject$1.class +0 -0
  34. data/golf-java/build/org/json/JSONObject$Null.class +0 -0
  35. data/golf-java/build/org/json/JSONObject.class +0 -0
  36. data/golf-java/build/org/json/JSONString.class +0 -0
  37. data/golf-java/build/org/json/JSONStringer.class +0 -0
  38. data/golf-java/build/org/json/JSONTokener.class +0 -0
  39. data/golf-java/build/org/json/JSONWriter.class +0 -0
  40. data/golf-java/build/resources.zip +0 -0
  41. data/golf-java/build.xml +0 -174
  42. data/golf-java/dist/golf.zip +0 -0
  43. data/golf-java/lib/ant-launcher.jar +0 -0
  44. data/golf-java/lib/ant.jar +0 -0
  45. data/golf-java/lib/commons-codec-1.4.jar +0 -0
  46. data/golf-java/lib/commons-collections-3.2.1.jar +0 -0
  47. data/golf-java/lib/commons-fileupload-1.2.1.jar +0 -0
  48. data/golf-java/lib/commons-httpclient-3.1.jar +0 -0
  49. data/golf-java/lib/commons-io-1.4.jar +0 -0
  50. data/golf-java/lib/commons-lang-2.4.jar +0 -0
  51. data/golf-java/lib/commons-logging-1.1.1.jar +0 -0
  52. data/golf-java/lib/cssparser-0.9.5.jar +0 -0
  53. data/golf-java/lib/getopt-0.1-dev.jar +0 -0
  54. data/golf-java/lib/htmlunit-2.6.jar +0 -0
  55. data/golf-java/lib/htmlunit-core-js-2.6.jar +0 -0
  56. data/golf-java/lib/java-xmlbuilder-1.jar +0 -0
  57. data/golf-java/lib/jets3t-0.7.0.jar +0 -0
  58. data/golf-java/lib/jetty-6.1.15.jar +0 -0
  59. data/golf-java/lib/jetty-util-6.1.15.jar +0 -0
  60. data/golf-java/lib/log4j-1.2.15.jar +0 -0
  61. data/golf-java/lib/nekohtml-1.9.13.jar +0 -0
  62. data/golf-java/lib/sac-1.3.jar +0 -0
  63. data/golf-java/lib/serializer-2.7.1.jar +0 -0
  64. data/golf-java/lib/servlet-api-2.5-20081211.jar +0 -0
  65. data/golf-java/lib/xalan-2.7.1.jar +0 -0
  66. data/golf-java/lib/xercesImpl-2.9.1.jar +0 -0
  67. data/golf-java/lib/xml-apis-1.3.04.jar +0 -0
  68. data/golf-java/resources/app_error.html +0 -60
  69. data/golf-java/resources/error.html +0 -29
  70. data/golf-java/resources/forcebot.txt +0 -0
  71. data/golf-java/resources/forceclient.txt +0 -0
  72. data/golf-java/resources/forceproxy.txt +0 -0
  73. data/golf-java/resources/head.html +0 -0
  74. data/golf-java/resources/jquery.address.js +0 -439
  75. data/golf-java/resources/jquery.golf.js +0 -945
  76. data/golf-java/resources/jquery.js +0 -4376
  77. data/golf-java/resources/jsdetect.html +0 -23
  78. data/golf-java/resources/loading.gif +0 -0
  79. data/golf-java/resources/new.html +0 -45
  80. data/golf-java/resources/new.static.html +0 -45
  81. data/golf-java/resources/noscript.forceclient.html +0 -11
  82. data/golf-java/resources/noscript.html +0 -18
  83. data/golf-java/resources/noscript.static.html +0 -15
  84. data/golf-java/resources/project.xml +0 -21
  85. data/golf-java/resources/proxy_project.xml +0 -11
  86. data/golf-java/resources/proxy_web.xml +0 -40
  87. data/golf-java/resources/static_project.xml +0 -37
  88. data/golf-java/resources/version +0 -1
  89. data/golf-java/resources/web.xml +0 -36
  90. data/golf-java/resources/welcome2golf.html +0 -50
  91. data/golf-java/src/com/thinkminimo/golf/GolfResource.java +0 -582
  92. data/golf-java/src/com/thinkminimo/golf/GolfServlet.java +0 -1055
  93. data/golf-java/src/com/thinkminimo/golf/JsonpTunnel.java +0 -86
  94. data/golf-java/src/com/thinkminimo/golf/Main.java +0 -1299
  95. data/golf-java/src/com/thinkminimo/golf/ProxyServlet.java +0 -577
  96. data/golf-java/src/com/yahoo/platform/yui/compressor/CssCompressor.java +0 -188
  97. data/golf-java/src/com/yahoo/platform/yui/compressor/JarClassLoader.java +0 -158
  98. data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java +0 -1281
  99. data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java +0 -55
  100. data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java +0 -28
  101. data/golf-java/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java +0 -160
  102. data/golf-java/src/org/json/JSONArray.java +0 -934
  103. data/golf-java/src/org/json/JSONException.java +0 -27
  104. data/golf-java/src/org/json/JSONObject.java +0 -1550
  105. data/golf-java/src/org/json/JSONString.java +0 -18
  106. data/golf-java/src/org/json/JSONStringer.java +0 -78
  107. data/golf-java/src/org/json/JSONTokener.java +0 -422
  108. data/golf-java/src/org/json/JSONWriter.java +0 -323
  109. data/golf-java/test/client/golftest/README.markdown +0 -3
  110. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.css +0 -114
  111. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.html +0 -17
  112. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.js +0 -81
  113. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/asc.gif +0 -0
  114. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/bg.gif +0 -0
  115. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/desc.gif +0 -0
  116. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/test/test.html +0 -1
  117. data/golf-java/test/client/golftest/controller.js +0 -131
  118. data/golf-java/test/client/golftest/forceclient.txt +0 -0
  119. data/golf-java/test/client/golftest/forceproxy.txt +0 -0
  120. data/golf-java/test/client/golftest/head.html +0 -1
  121. data/golf-java/test/client/golftest/scripts/jquery.tablesort.js +0 -75
  122. data/golf-java/test/client/golftest/styles/style.css +0 -18
  123. data/golf-java/test/client/golftest/test/test.html +0 -1
@@ -1,1281 +0,0 @@
1
- /*
2
- * YUI Compressor
3
- * Author: Julien Lecomte <jlecomte@yahoo-inc.com>
4
- * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
5
- * Code licensed under the BSD License:
6
- * http://developer.yahoo.net/yui/license.txt
7
- */
8
-
9
- package com.yahoo.platform.yui.compressor;
10
-
11
- import net.sourceforge.htmlunit.corejs.javascript.*;
12
-
13
- import java.io.IOException;
14
- import java.io.Reader;
15
- import java.io.Writer;
16
- import java.util.*;
17
- import java.util.regex.Matcher;
18
- import java.util.regex.Pattern;
19
-
20
- public class JavaScriptCompressor {
21
-
22
- static final ArrayList ones;
23
- static final ArrayList twos;
24
- static final ArrayList threes;
25
-
26
- static final Set builtin = new HashSet();
27
- static final Map literals = new Hashtable();
28
- static final Set reserved = new HashSet();
29
-
30
- static {
31
-
32
- // This list contains all the 3 characters or less built-in global
33
- // symbols available in a browser. Please add to this list if you
34
- // see anything missing.
35
- builtin.add("NaN");
36
- builtin.add("top");
37
-
38
- ones = new ArrayList();
39
- for (char c = 'a'; c <= 'z'; c++)
40
- ones.add(Character.toString(c));
41
- for (char c = 'A'; c <= 'Z'; c++)
42
- ones.add(Character.toString(c));
43
-
44
- twos = new ArrayList();
45
- for (int i = 0; i < ones.size(); i++) {
46
- String one = (String) ones.get(i);
47
- for (char c = 'a'; c <= 'z'; c++)
48
- twos.add(one + Character.toString(c));
49
- for (char c = 'A'; c <= 'Z'; c++)
50
- twos.add(one + Character.toString(c));
51
- for (char c = '0'; c <= '9'; c++)
52
- twos.add(one + Character.toString(c));
53
- }
54
-
55
- // Remove two-letter JavaScript reserved words and built-in globals...
56
- twos.remove("as");
57
- twos.remove("is");
58
- twos.remove("do");
59
- twos.remove("if");
60
- twos.remove("in");
61
- twos.removeAll(builtin);
62
-
63
- threes = new ArrayList();
64
- for (int i = 0; i < twos.size(); i++) {
65
- String two = (String) twos.get(i);
66
- for (char c = 'a'; c <= 'z'; c++)
67
- threes.add(two + Character.toString(c));
68
- for (char c = 'A'; c <= 'Z'; c++)
69
- threes.add(two + Character.toString(c));
70
- for (char c = '0'; c <= '9'; c++)
71
- threes.add(two + Character.toString(c));
72
- }
73
-
74
- // Remove three-letter JavaScript reserved words and built-in globals...
75
- threes.remove("for");
76
- threes.remove("int");
77
- threes.remove("new");
78
- threes.remove("try");
79
- threes.remove("use");
80
- threes.remove("var");
81
- threes.removeAll(builtin);
82
-
83
- // That's up to ((26+26)*(1+(26+26+10)))*(1+(26+26+10))-8
84
- // (206,380 symbols per scope)
85
-
86
- // The following list comes from org/mozilla/javascript/Decompiler.java...
87
- literals.put(new Integer(Token.GET), "get ");
88
- literals.put(new Integer(Token.SET), "set ");
89
- literals.put(new Integer(Token.TRUE), "true");
90
- literals.put(new Integer(Token.FALSE), "false");
91
- literals.put(new Integer(Token.NULL), "null");
92
- literals.put(new Integer(Token.THIS), "this");
93
- literals.put(new Integer(Token.FUNCTION), "function");
94
- literals.put(new Integer(Token.COMMA), ",");
95
- literals.put(new Integer(Token.LC), "{");
96
- literals.put(new Integer(Token.RC), "}");
97
- literals.put(new Integer(Token.LP), "(");
98
- literals.put(new Integer(Token.RP), ")");
99
- literals.put(new Integer(Token.LB), "[");
100
- literals.put(new Integer(Token.RB), "]");
101
- literals.put(new Integer(Token.DOT), ".");
102
- literals.put(new Integer(Token.NEW), "new ");
103
- literals.put(new Integer(Token.DELPROP), "delete ");
104
- literals.put(new Integer(Token.IF), "if");
105
- literals.put(new Integer(Token.ELSE), "else");
106
- literals.put(new Integer(Token.FOR), "for");
107
- literals.put(new Integer(Token.IN), " in ");
108
- literals.put(new Integer(Token.WITH), "with");
109
- literals.put(new Integer(Token.WHILE), "while");
110
- literals.put(new Integer(Token.DO), "do");
111
- literals.put(new Integer(Token.TRY), "try");
112
- literals.put(new Integer(Token.CATCH), "catch");
113
- literals.put(new Integer(Token.FINALLY), "finally");
114
- literals.put(new Integer(Token.THROW), "throw");
115
- literals.put(new Integer(Token.SWITCH), "switch");
116
- literals.put(new Integer(Token.BREAK), "break");
117
- literals.put(new Integer(Token.CONTINUE), "continue");
118
- literals.put(new Integer(Token.CASE), "case");
119
- literals.put(new Integer(Token.DEFAULT), "default");
120
- literals.put(new Integer(Token.RETURN), "return");
121
- literals.put(new Integer(Token.VAR), "var ");
122
- literals.put(new Integer(Token.SEMI), ";");
123
- literals.put(new Integer(Token.ASSIGN), "=");
124
- literals.put(new Integer(Token.ASSIGN_ADD), "+=");
125
- literals.put(new Integer(Token.ASSIGN_SUB), "-=");
126
- literals.put(new Integer(Token.ASSIGN_MUL), "*=");
127
- literals.put(new Integer(Token.ASSIGN_DIV), "/=");
128
- literals.put(new Integer(Token.ASSIGN_MOD), "%=");
129
- literals.put(new Integer(Token.ASSIGN_BITOR), "|=");
130
- literals.put(new Integer(Token.ASSIGN_BITXOR), "^=");
131
- literals.put(new Integer(Token.ASSIGN_BITAND), "&=");
132
- literals.put(new Integer(Token.ASSIGN_LSH), "<<=");
133
- literals.put(new Integer(Token.ASSIGN_RSH), ">>=");
134
- literals.put(new Integer(Token.ASSIGN_URSH), ">>>=");
135
- literals.put(new Integer(Token.HOOK), "?");
136
- literals.put(new Integer(Token.OBJECTLIT), ":");
137
- literals.put(new Integer(Token.COLON), ":");
138
- literals.put(new Integer(Token.OR), "||");
139
- literals.put(new Integer(Token.AND), "&&");
140
- literals.put(new Integer(Token.BITOR), "|");
141
- literals.put(new Integer(Token.BITXOR), "^");
142
- literals.put(new Integer(Token.BITAND), "&");
143
- literals.put(new Integer(Token.SHEQ), "===");
144
- literals.put(new Integer(Token.SHNE), "!==");
145
- literals.put(new Integer(Token.EQ), "==");
146
- literals.put(new Integer(Token.NE), "!=");
147
- literals.put(new Integer(Token.LE), "<=");
148
- literals.put(new Integer(Token.LT), "<");
149
- literals.put(new Integer(Token.GE), ">=");
150
- literals.put(new Integer(Token.GT), ">");
151
- literals.put(new Integer(Token.INSTANCEOF), " instanceof ");
152
- literals.put(new Integer(Token.LSH), "<<");
153
- literals.put(new Integer(Token.RSH), ">>");
154
- literals.put(new Integer(Token.URSH), ">>>");
155
- literals.put(new Integer(Token.TYPEOF), "typeof");
156
- literals.put(new Integer(Token.VOID), "void ");
157
- literals.put(new Integer(Token.CONST), "const ");
158
- literals.put(new Integer(Token.NOT), "!");
159
- literals.put(new Integer(Token.BITNOT), "~");
160
- literals.put(new Integer(Token.POS), "+");
161
- literals.put(new Integer(Token.NEG), "-");
162
- literals.put(new Integer(Token.INC), "++");
163
- literals.put(new Integer(Token.DEC), "--");
164
- literals.put(new Integer(Token.ADD), "+");
165
- literals.put(new Integer(Token.SUB), "-");
166
- literals.put(new Integer(Token.MUL), "*");
167
- literals.put(new Integer(Token.DIV), "/");
168
- literals.put(new Integer(Token.MOD), "%");
169
- literals.put(new Integer(Token.COLONCOLON), "::");
170
- literals.put(new Integer(Token.DOTDOT), "..");
171
- literals.put(new Integer(Token.DOTQUERY), ".(");
172
- literals.put(new Integer(Token.XMLATTR), "@");
173
-
174
- // See http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Reserved_Words
175
-
176
- // JavaScript 1.5 reserved words
177
- reserved.add("break");
178
- reserved.add("case");
179
- reserved.add("catch");
180
- reserved.add("continue");
181
- reserved.add("default");
182
- reserved.add("delete");
183
- reserved.add("do");
184
- reserved.add("else");
185
- reserved.add("finally");
186
- reserved.add("for");
187
- reserved.add("function");
188
- reserved.add("if");
189
- reserved.add("in");
190
- reserved.add("instanceof");
191
- reserved.add("new");
192
- reserved.add("return");
193
- reserved.add("switch");
194
- reserved.add("this");
195
- reserved.add("throw");
196
- reserved.add("try");
197
- reserved.add("typeof");
198
- reserved.add("var");
199
- reserved.add("void");
200
- reserved.add("while");
201
- reserved.add("with");
202
- // Words reserved for future use
203
- reserved.add("abstract");
204
- reserved.add("boolean");
205
- reserved.add("byte");
206
- reserved.add("char");
207
- reserved.add("class");
208
- reserved.add("const");
209
- reserved.add("debugger");
210
- reserved.add("double");
211
- reserved.add("enum");
212
- reserved.add("export");
213
- reserved.add("extends");
214
- reserved.add("final");
215
- reserved.add("float");
216
- reserved.add("goto");
217
- reserved.add("implements");
218
- reserved.add("import");
219
- reserved.add("int");
220
- reserved.add("interface");
221
- reserved.add("long");
222
- reserved.add("native");
223
- reserved.add("package");
224
- reserved.add("private");
225
- reserved.add("protected");
226
- reserved.add("public");
227
- reserved.add("short");
228
- reserved.add("static");
229
- reserved.add("super");
230
- reserved.add("synchronized");
231
- reserved.add("throws");
232
- reserved.add("transient");
233
- reserved.add("volatile");
234
- // These are not reserved, but should be taken into account
235
- // in isValidIdentifier (See jslint source code)
236
- reserved.add("arguments");
237
- reserved.add("eval");
238
- reserved.add("true");
239
- reserved.add("false");
240
- reserved.add("Infinity");
241
- reserved.add("NaN");
242
- reserved.add("null");
243
- reserved.add("undefined");
244
- }
245
-
246
- private static int countChar(String haystack, char needle) {
247
- int idx = 0;
248
- int count = 0;
249
- int length = haystack.length();
250
- while (idx < length) {
251
- char c = haystack.charAt(idx++);
252
- if (c == needle) {
253
- count++;
254
- }
255
- }
256
- return count;
257
- }
258
-
259
- private static int printSourceString(String source, int offset, StringBuffer sb) {
260
- int length = source.charAt(offset);
261
- ++offset;
262
- if ((0x8000 & length) != 0) {
263
- length = ((0x7FFF & length) << 16) | source.charAt(offset);
264
- ++offset;
265
- }
266
- if (sb != null) {
267
- String str = source.substring(offset, offset + length);
268
- sb.append(str);
269
- }
270
- return offset + length;
271
- }
272
-
273
- private static int printSourceNumber(String source,
274
- int offset, StringBuffer sb) {
275
- double number = 0.0;
276
- char type = source.charAt(offset);
277
- ++offset;
278
- if (type == 'S') {
279
- if (sb != null) {
280
- number = source.charAt(offset);
281
- }
282
- ++offset;
283
- } else if (type == 'J' || type == 'D') {
284
- if (sb != null) {
285
- long lbits;
286
- lbits = (long) source.charAt(offset) << 48;
287
- lbits |= (long) source.charAt(offset + 1) << 32;
288
- lbits |= (long) source.charAt(offset + 2) << 16;
289
- lbits |= (long) source.charAt(offset + 3);
290
- if (type == 'J') {
291
- number = lbits;
292
- } else {
293
- number = Double.longBitsToDouble(lbits);
294
- }
295
- }
296
- offset += 4;
297
- } else {
298
- // Bad source
299
- throw new RuntimeException();
300
- }
301
- if (sb != null) {
302
- sb.append(ScriptRuntime.numberToString(number, 10));
303
- }
304
- return offset;
305
- }
306
-
307
- private static ArrayList parse(Reader in, ErrorReporter reporter)
308
- throws IOException, EvaluatorException {
309
-
310
- CompilerEnvirons env = new CompilerEnvirons();
311
- Parser parser = new Parser(env, reporter);
312
- parser.parse(in, null, 1);
313
- String source = ""; //FIXME parser.getEncodedSource();
314
-
315
- int offset = 0;
316
- int length = source.length();
317
- ArrayList tokens = new ArrayList();
318
- StringBuffer sb = new StringBuffer();
319
-
320
- while (offset < length) {
321
- int tt = source.charAt(offset++);
322
- switch (tt) {
323
-
324
- case Token.NAME:
325
- case Token.REGEXP:
326
- case Token.STRING:
327
- sb.setLength(0);
328
- offset = printSourceString(source, offset, sb);
329
- tokens.add(new JavaScriptToken(tt, sb.toString()));
330
- break;
331
-
332
- case Token.NUMBER:
333
- sb.setLength(0);
334
- offset = printSourceNumber(source, offset, sb);
335
- tokens.add(new JavaScriptToken(tt, sb.toString()));
336
- break;
337
-
338
- default:
339
- String literal = (String) literals.get(new Integer(tt));
340
- if (literal != null) {
341
- tokens.add(new JavaScriptToken(tt, literal));
342
- }
343
- break;
344
- }
345
- }
346
-
347
- return tokens;
348
- }
349
-
350
- private static void processStringLiterals(ArrayList tokens, boolean merge) {
351
-
352
- String tv;
353
- int i, length = tokens.size();
354
- JavaScriptToken token, prevToken, nextToken;
355
-
356
- if (merge) {
357
-
358
- // Concatenate string literals that are being appended wherever
359
- // it is safe to do so. Note that we take care of the case:
360
- // "a" + "b".toUpperCase()
361
-
362
- for (i = 0; i < length; i++) {
363
- token = (JavaScriptToken) tokens.get(i);
364
- switch (token.getType()) {
365
-
366
- case Token.ADD:
367
- if (i > 0 && i < length) {
368
- prevToken = (JavaScriptToken) tokens.get(i - 1);
369
- nextToken = (JavaScriptToken) tokens.get(i + 1);
370
- if (prevToken.getType() == Token.STRING && nextToken.getType() == Token.STRING &&
371
- (i == length - 1 || ((JavaScriptToken) tokens.get(i + 2)).getType() != Token.DOT)) {
372
- tokens.set(i - 1, new JavaScriptToken(Token.STRING,
373
- prevToken.getValue() + nextToken.getValue()));
374
- tokens.remove(i + 1);
375
- tokens.remove(i);
376
- i = i - 1;
377
- length = length - 2;
378
- break;
379
- }
380
- }
381
- }
382
- }
383
-
384
- }
385
-
386
- // Second pass...
387
-
388
- for (i = 0; i < length; i++) {
389
- token = (JavaScriptToken) tokens.get(i);
390
- if (token.getType() == Token.STRING) {
391
- tv = token.getValue();
392
-
393
- // Finally, add the quoting characters and escape the string. We use
394
- // the quoting character that minimizes the amount of escaping to save
395
- // a few additional bytes.
396
-
397
- char quotechar;
398
- int singleQuoteCount = countChar(tv, '\'');
399
- int doubleQuoteCount = countChar(tv, '"');
400
- if (doubleQuoteCount <= singleQuoteCount) {
401
- quotechar = '"';
402
- } else {
403
- quotechar = '\'';
404
- }
405
-
406
- tv = quotechar + escapeString(tv, quotechar) + quotechar;
407
-
408
- // String concatenation transforms the old script scheme:
409
- // '<scr'+'ipt ...><'+'/script>'
410
- // into the following:
411
- // '<script ...></script>'
412
- // which breaks if this code is embedded inside an HTML document.
413
- // Since this is not the right way to do this, let's fix the code by
414
- // transforming all "</script" into "<\/script"
415
-
416
- if (tv.indexOf("</script") >= 0) {
417
- tv = tv.replaceAll("<\\/script", "<\\\\/script");
418
- }
419
-
420
- tokens.set(i, new JavaScriptToken(Token.STRING, tv));
421
- }
422
- }
423
- }
424
-
425
- // Add necessary escaping that was removed in Rhino's tokenizer.
426
- private static String escapeString(String s, char quotechar) {
427
-
428
- assert quotechar == '"' || quotechar == '\'';
429
-
430
- if (s == null) {
431
- return null;
432
- }
433
-
434
- StringBuffer sb = new StringBuffer();
435
- for (int i = 0, L = s.length(); i < L; i++) {
436
- int c = s.charAt(i);
437
- if (c == quotechar) {
438
- sb.append("\\");
439
- }
440
- sb.append((char) c);
441
- }
442
-
443
- return sb.toString();
444
- }
445
-
446
- /*
447
- * Simple check to see whether a string is a valid identifier name.
448
- * If a string matches this pattern, it means it IS a valid
449
- * identifier name. If a string doesn't match it, it does not
450
- * necessarily mean it is not a valid identifier name.
451
- */
452
- private static final Pattern SIMPLE_IDENTIFIER_NAME_PATTERN = Pattern.compile("^[a-zA-Z_][a-zA-Z0-9_]*$");
453
-
454
- private static boolean isValidIdentifier(String s) {
455
- Matcher m = SIMPLE_IDENTIFIER_NAME_PATTERN.matcher(s);
456
- return (m.matches() && !reserved.contains(s));
457
- }
458
-
459
- /*
460
- * Transforms obj["foo"] into obj.foo whenever possible, saving 3 bytes.
461
- */
462
- private static void optimizeObjectMemberAccess(ArrayList tokens) {
463
-
464
- String tv;
465
- int i, length;
466
- JavaScriptToken token;
467
-
468
- for (i = 0, length = tokens.size(); i < length; i++) {
469
-
470
- if (((JavaScriptToken) tokens.get(i)).getType() == Token.LB &&
471
- i > 0 && i < length - 2 &&
472
- ((JavaScriptToken) tokens.get(i - 1)).getType() == Token.NAME &&
473
- ((JavaScriptToken) tokens.get(i + 1)).getType() == Token.STRING &&
474
- ((JavaScriptToken) tokens.get(i + 2)).getType() == Token.RB) {
475
- token = (JavaScriptToken) tokens.get(i + 1);
476
- tv = token.getValue();
477
- tv = tv.substring(1, tv.length() - 1);
478
- if (isValidIdentifier(tv)) {
479
- tokens.set(i, new JavaScriptToken(Token.DOT, "."));
480
- tokens.set(i + 1, new JavaScriptToken(Token.NAME, tv));
481
- tokens.remove(i + 2);
482
- i = i + 2;
483
- length = length - 1;
484
- }
485
- }
486
- }
487
- }
488
-
489
- /*
490
- * Transforms 'foo': ... into foo: ... whenever possible, saving 2 bytes.
491
- */
492
- private static void optimizeObjLitMemberDecl(ArrayList tokens) {
493
-
494
- String tv;
495
- int i, length;
496
- JavaScriptToken token;
497
-
498
- for (i = 0, length = tokens.size(); i < length; i++) {
499
- if (((JavaScriptToken) tokens.get(i)).getType() == Token.OBJECTLIT &&
500
- i > 0 && ((JavaScriptToken) tokens.get(i - 1)).getType() == Token.STRING) {
501
- token = (JavaScriptToken) tokens.get(i - 1);
502
- tv = token.getValue();
503
- tv = tv.substring(1, tv.length() - 1);
504
- if (isValidIdentifier(tv)) {
505
- tokens.set(i - 1, new JavaScriptToken(Token.NAME, tv));
506
- }
507
- }
508
- }
509
- }
510
-
511
- private ErrorReporter logger;
512
-
513
- private boolean munge;
514
- private boolean verbose;
515
-
516
- private static final int BUILDING_SYMBOL_TREE = 1;
517
- private static final int CHECKING_SYMBOL_TREE = 2;
518
-
519
- private int mode;
520
- private int offset;
521
- private int braceNesting;
522
- private ArrayList tokens;
523
- private Stack scopes = new Stack();
524
- private ScriptOrFnScope globalScope = new ScriptOrFnScope(-1, null);
525
- private Hashtable indexedScopes = new Hashtable();
526
-
527
- public JavaScriptCompressor(Reader in, ErrorReporter reporter)
528
- throws IOException, EvaluatorException {
529
-
530
- this.logger = reporter;
531
- this.tokens = parse(in, reporter);
532
- }
533
-
534
- public void compress(Writer out, int linebreak, boolean munge, boolean verbose,
535
- boolean preserveAllSemiColons, boolean disableOptimizations)
536
- throws IOException {
537
-
538
- this.munge = munge;
539
- this.verbose = verbose;
540
-
541
- processStringLiterals(this.tokens, !disableOptimizations);
542
-
543
- if (!disableOptimizations) {
544
- optimizeObjectMemberAccess(this.tokens);
545
- optimizeObjLitMemberDecl(this.tokens);
546
- }
547
-
548
- buildSymbolTree();
549
- // DO NOT TOUCH this.tokens BETWEEN THESE TWO PHASES (BECAUSE OF this.indexedScopes)
550
- mungeSymboltree();
551
- StringBuffer sb = printSymbolTree(linebreak, preserveAllSemiColons);
552
-
553
- out.write(sb.toString());
554
- }
555
-
556
- private ScriptOrFnScope getCurrentScope() {
557
- return (ScriptOrFnScope) scopes.peek();
558
- }
559
-
560
- private void enterScope(ScriptOrFnScope scope) {
561
- scopes.push(scope);
562
- }
563
-
564
- private void leaveCurrentScope() {
565
- scopes.pop();
566
- }
567
-
568
- private JavaScriptToken consumeToken() {
569
- return (JavaScriptToken) tokens.get(offset++);
570
- }
571
-
572
- private JavaScriptToken getToken(int delta) {
573
- return (JavaScriptToken) tokens.get(offset + delta);
574
- }
575
-
576
- /*
577
- * Returns the identifier for the specified symbol defined in
578
- * the specified scope or in any scope above it. Returns null
579
- * if this symbol does not have a corresponding identifier.
580
- */
581
- private JavaScriptIdentifier getIdentifier(String symbol, ScriptOrFnScope scope) {
582
- JavaScriptIdentifier identifier;
583
- while (scope != null) {
584
- identifier = scope.getIdentifier(symbol);
585
- if (identifier != null) {
586
- return identifier;
587
- }
588
- scope = scope.getParentScope();
589
- }
590
- return null;
591
- }
592
-
593
- /*
594
- * If either 'eval' or 'with' is used in a local scope, we must make
595
- * sure that all containing local scopes don't get munged. Otherwise,
596
- * the obfuscation would potentially introduce bugs.
597
- */
598
- private void protectScopeFromObfuscation(ScriptOrFnScope scope) {
599
- assert scope != null;
600
-
601
- if (scope == globalScope) {
602
- // The global scope does not get obfuscated,
603
- // so we don't need to worry about it...
604
- return;
605
- }
606
-
607
- // Find the highest local scope containing the specified scope.
608
- while (scope.getParentScope() != globalScope) {
609
- scope = scope.getParentScope();
610
- }
611
-
612
- assert scope.getParentScope() == globalScope;
613
- scope.preventMunging();
614
- }
615
-
616
- private String getDebugString(int max) {
617
- assert max > 0;
618
- StringBuffer result = new StringBuffer();
619
- int start = Math.max(offset - max, 0);
620
- int end = Math.min(offset + max, tokens.size());
621
- for (int i = start; i < end; i++) {
622
- JavaScriptToken token = (JavaScriptToken) tokens.get(i);
623
- if (i == offset - 1) {
624
- result.append(" ---> ");
625
- }
626
- result.append(token.getValue());
627
- if (i == offset - 1) {
628
- result.append(" <--- ");
629
- }
630
- }
631
- return result.toString();
632
- }
633
-
634
- private void warn(String message, boolean showDebugString) {
635
- if (verbose) {
636
- if (showDebugString) {
637
- message = message + "\n" + getDebugString(10);
638
- }
639
- logger.warning(message, null, -1, null, -1);
640
- }
641
- }
642
-
643
- private void parseFunctionDeclaration() {
644
-
645
- String symbol;
646
- JavaScriptToken token;
647
- ScriptOrFnScope currentScope, fnScope;
648
- JavaScriptIdentifier identifier;
649
-
650
- currentScope = getCurrentScope();
651
-
652
- token = consumeToken();
653
- if (token.getType() == Token.NAME) {
654
- if (mode == BUILDING_SYMBOL_TREE) {
655
- // Get the name of the function and declare it in the current scope.
656
- symbol = token.getValue();
657
- if (currentScope.getIdentifier(symbol) != null) {
658
- warn("The function " + symbol + " has already been declared in the same scope...", true);
659
- }
660
- currentScope.declareIdentifier(symbol);
661
- }
662
- token = consumeToken();
663
- }
664
-
665
- assert token.getType() == Token.LP;
666
- if (mode == BUILDING_SYMBOL_TREE) {
667
- fnScope = new ScriptOrFnScope(braceNesting, currentScope);
668
- indexedScopes.put(new Integer(offset), fnScope);
669
- } else {
670
- fnScope = (ScriptOrFnScope) indexedScopes.get(new Integer(offset));
671
- }
672
-
673
- // Parse function arguments.
674
- int argpos = 0;
675
- while ((token = consumeToken()).getType() != Token.RP) {
676
- assert token.getType() == Token.NAME ||
677
- token.getType() == Token.COMMA;
678
- if (token.getType() == Token.NAME && mode == BUILDING_SYMBOL_TREE) {
679
- symbol = token.getValue();
680
- identifier = fnScope.declareIdentifier(symbol);
681
- if (symbol.equals("$super") && argpos == 0) {
682
- // Exception for Prototype 1.6...
683
- identifier.preventMunging();
684
- }
685
- argpos++;
686
- }
687
- }
688
-
689
- token = consumeToken();
690
- assert token.getType() == Token.LC;
691
- braceNesting++;
692
-
693
- token = getToken(0);
694
- if (token.getType() == Token.STRING &&
695
- getToken(1).getType() == Token.SEMI) {
696
- // This is a hint. Hints are empty statements that look like
697
- // "localvar1:nomunge, localvar2:nomunge"; They allow developers
698
- // to prevent specific symbols from getting obfuscated (some heretic
699
- // implementations, such as Prototype 1.6, require specific variable
700
- // names, such as $super for example, in order to work appropriately.
701
- // Note: right now, only "nomunge" is supported in the right hand side
702
- // of a hint. However, in the future, the right hand side may contain
703
- // other values.
704
- consumeToken();
705
- String hints = token.getValue();
706
- // Remove the leading and trailing quotes...
707
- hints = hints.substring(1, hints.length() - 1).trim();
708
- StringTokenizer st1 = new StringTokenizer(hints, ",");
709
- while (st1.hasMoreTokens()) {
710
- String hint = st1.nextToken();
711
- int idx = hint.indexOf(':');
712
- if (idx <= 0 || idx >= hint.length() - 1) {
713
- if (mode == BUILDING_SYMBOL_TREE) {
714
- // No need to report the error twice, hence the test...
715
- warn("Invalid hint syntax: " + hint, true);
716
- }
717
- break;
718
- }
719
- String variableName = hint.substring(0, idx).trim();
720
- String variableType = hint.substring(idx + 1).trim();
721
- if (mode == BUILDING_SYMBOL_TREE) {
722
- fnScope.addHint(variableName, variableType);
723
- } else if (mode == CHECKING_SYMBOL_TREE) {
724
- identifier = fnScope.getIdentifier(variableName);
725
- if (identifier != null) {
726
- if (variableType.equals("nomunge")) {
727
- identifier.preventMunging();
728
- } else {
729
- warn("Unsupported hint value: " + hint, true);
730
- }
731
- } else {
732
- warn("Hint refers to an unknown identifier: " + hint, true);
733
- }
734
- }
735
- }
736
- }
737
-
738
- parseScope(fnScope);
739
- }
740
-
741
- private void parseCatch() {
742
-
743
- String symbol;
744
- JavaScriptToken token;
745
- ScriptOrFnScope currentScope;
746
- JavaScriptIdentifier identifier;
747
-
748
- token = getToken(-1);
749
- assert token.getType() == Token.CATCH;
750
- token = consumeToken();
751
- assert token.getType() == Token.LP;
752
- token = consumeToken();
753
- assert token.getType() == Token.NAME;
754
-
755
- symbol = token.getValue();
756
- currentScope = getCurrentScope();
757
-
758
- if (mode == BUILDING_SYMBOL_TREE) {
759
- // We must declare the exception identifier in the containing function
760
- // scope to avoid errors related to the obfuscation process. No need to
761
- // display a warning if the symbol was already declared here...
762
- currentScope.declareIdentifier(symbol);
763
- } else {
764
- identifier = getIdentifier(symbol, currentScope);
765
- identifier.incrementRefcount();
766
- }
767
-
768
- token = consumeToken();
769
- assert token.getType() == Token.RP;
770
- }
771
-
772
- private void parseExpression() {
773
-
774
- // Parse the expression until we encounter a comma or a semi-colon
775
- // in the same brace nesting, bracket nesting and paren nesting.
776
- // Parse functions if any...
777
-
778
- String symbol;
779
- JavaScriptToken token;
780
- ScriptOrFnScope currentScope;
781
- JavaScriptIdentifier identifier;
782
-
783
- int expressionBraceNesting = braceNesting;
784
- int bracketNesting = 0;
785
- int parensNesting = 0;
786
-
787
- int length = tokens.size();
788
-
789
- while (offset < length) {
790
-
791
- token = consumeToken();
792
- currentScope = getCurrentScope();
793
-
794
- switch (token.getType()) {
795
-
796
- case Token.SEMI:
797
- case Token.COMMA:
798
- if (braceNesting == expressionBraceNesting &&
799
- bracketNesting == 0 &&
800
- parensNesting == 0) {
801
- return;
802
- }
803
- break;
804
-
805
- case Token.FUNCTION:
806
- parseFunctionDeclaration();
807
- break;
808
-
809
- case Token.LC:
810
- braceNesting++;
811
- break;
812
-
813
- case Token.RC:
814
- braceNesting--;
815
- assert braceNesting >= expressionBraceNesting;
816
- break;
817
-
818
- case Token.LB:
819
- bracketNesting++;
820
- break;
821
-
822
- case Token.RB:
823
- bracketNesting--;
824
- break;
825
-
826
- case Token.LP:
827
- parensNesting++;
828
- break;
829
-
830
- case Token.RP:
831
- parensNesting--;
832
- break;
833
-
834
- case Token.NAME:
835
- symbol = token.getValue();
836
-
837
- if (mode == BUILDING_SYMBOL_TREE) {
838
-
839
- if (symbol.equals("eval")) {
840
-
841
- protectScopeFromObfuscation(currentScope);
842
- warn("Using 'eval' is not recommended." + (munge ? " Moreover, using 'eval' reduces the level of compression!" : ""), true);
843
-
844
- }
845
-
846
- } else if (mode == CHECKING_SYMBOL_TREE) {
847
-
848
- if ((offset < 2 ||
849
- (getToken(-2).getType() != Token.DOT &&
850
- getToken(-2).getType() != Token.GET &&
851
- getToken(-2).getType() != Token.SET)) &&
852
- getToken(0).getType() != Token.OBJECTLIT) {
853
-
854
- identifier = getIdentifier(symbol, currentScope);
855
-
856
- if (identifier == null) {
857
-
858
- if (symbol.length() <= 3 && !builtin.contains(symbol)) {
859
- // Here, we found an undeclared and un-namespaced symbol that is
860
- // 3 characters or less in length. Declare it in the global scope.
861
- // We don't need to declare longer symbols since they won't cause
862
- // any conflict with other munged symbols.
863
- globalScope.declareIdentifier(symbol);
864
- warn("Found an undeclared symbol: " + symbol, true);
865
- }
866
-
867
- } else {
868
-
869
- identifier.incrementRefcount();
870
- }
871
- }
872
- }
873
- break;
874
- }
875
- }
876
- }
877
-
878
- private void parseScope(ScriptOrFnScope scope) {
879
-
880
- String symbol;
881
- JavaScriptToken token;
882
- JavaScriptIdentifier identifier;
883
-
884
- int length = tokens.size();
885
-
886
- enterScope(scope);
887
-
888
- while (offset < length) {
889
-
890
- token = consumeToken();
891
-
892
- switch (token.getType()) {
893
-
894
- case Token.VAR:
895
-
896
- if (mode == BUILDING_SYMBOL_TREE && scope.incrementVarCount() > 1) {
897
- warn("Try to use a single 'var' statement per scope.", true);
898
- }
899
-
900
- /* FALLSTHROUGH */
901
-
902
- case Token.CONST:
903
-
904
- // The var keyword is followed by at least one symbol name.
905
- // If several symbols follow, they are comma separated.
906
- for (; ;) {
907
- token = consumeToken();
908
-
909
- assert token.getType() == Token.NAME;
910
-
911
- if (mode == BUILDING_SYMBOL_TREE) {
912
- symbol = token.getValue();
913
- if (scope.getIdentifier(symbol) == null) {
914
- scope.declareIdentifier(symbol);
915
- } else {
916
- warn("The variable " + symbol + " has already been declared in the same scope...", true);
917
- }
918
- }
919
-
920
- token = getToken(0);
921
-
922
- assert token.getType() == Token.SEMI ||
923
- token.getType() == Token.ASSIGN ||
924
- token.getType() == Token.COMMA ||
925
- token.getType() == Token.IN;
926
-
927
- if (token.getType() == Token.IN) {
928
- break;
929
- } else {
930
- parseExpression();
931
- token = getToken(-1);
932
- if (token.getType() == Token.SEMI) {
933
- break;
934
- }
935
- }
936
- }
937
- break;
938
-
939
- case Token.FUNCTION:
940
- parseFunctionDeclaration();
941
- break;
942
-
943
- case Token.LC:
944
- braceNesting++;
945
- break;
946
-
947
- case Token.RC:
948
- braceNesting--;
949
- assert braceNesting >= scope.getBraceNesting();
950
- if (braceNesting == scope.getBraceNesting()) {
951
- leaveCurrentScope();
952
- return;
953
- }
954
- break;
955
-
956
- case Token.WITH:
957
- if (mode == BUILDING_SYMBOL_TREE) {
958
- // Inside a 'with' block, it is impossible to figure out
959
- // statically whether a symbol is a local variable or an
960
- // object member. As a consequence, the only thing we can
961
- // do is turn the obfuscation off for the highest scope
962
- // containing the 'with' block.
963
- protectScopeFromObfuscation(scope);
964
- warn("Using 'with' is not recommended." + (munge ? " Moreover, using 'with' reduces the level of compression!" : ""), true);
965
- }
966
- break;
967
-
968
- case Token.CATCH:
969
- parseCatch();
970
- break;
971
-
972
- case Token.NAME:
973
- symbol = token.getValue();
974
-
975
- if (mode == BUILDING_SYMBOL_TREE) {
976
-
977
- if (symbol.equals("eval")) {
978
-
979
- protectScopeFromObfuscation(scope);
980
- warn("Using 'eval' is not recommended." + (munge ? " Moreover, using 'eval' reduces the level of compression!" : ""), true);
981
-
982
- }
983
-
984
- } else if (mode == CHECKING_SYMBOL_TREE) {
985
-
986
- if ((offset < 2 || getToken(-2).getType() != Token.DOT) &&
987
- getToken(0).getType() != Token.OBJECTLIT) {
988
-
989
- identifier = getIdentifier(symbol, scope);
990
-
991
- if (identifier == null) {
992
-
993
- if (symbol.length() <= 3 && !builtin.contains(symbol)) {
994
- // Here, we found an undeclared and un-namespaced symbol that is
995
- // 3 characters or less in length. Declare it in the global scope.
996
- // We don't need to declare longer symbols since they won't cause
997
- // any conflict with other munged symbols.
998
- globalScope.declareIdentifier(symbol);
999
- warn("Found an undeclared symbol: " + symbol, true);
1000
- }
1001
-
1002
- } else {
1003
-
1004
- identifier.incrementRefcount();
1005
- }
1006
- }
1007
- }
1008
- break;
1009
- }
1010
- }
1011
- }
1012
-
1013
- private void buildSymbolTree() {
1014
- offset = 0;
1015
- braceNesting = 0;
1016
- scopes.clear();
1017
- indexedScopes.clear();
1018
- indexedScopes.put(new Integer(0), globalScope);
1019
- mode = BUILDING_SYMBOL_TREE;
1020
- parseScope(globalScope);
1021
- }
1022
-
1023
- private void mungeSymboltree() {
1024
-
1025
- if (!munge) {
1026
- return;
1027
- }
1028
-
1029
- // One problem with obfuscation resides in the use of undeclared
1030
- // and un-namespaced global symbols that are 3 characters or less
1031
- // in length. Here is an example:
1032
- //
1033
- // var declaredGlobalVar;
1034
- //
1035
- // function declaredGlobalFn() {
1036
- // var localvar;
1037
- // localvar = abc; // abc is an undeclared global symbol
1038
- // }
1039
- //
1040
- // In the example above, there is a slim chance that localvar may be
1041
- // munged to 'abc', conflicting with the undeclared global symbol
1042
- // abc, creating a potential bug. The following code detects such
1043
- // global symbols. This must be done AFTER the entire file has been
1044
- // parsed, and BEFORE munging the symbol tree. Note that declaring
1045
- // extra symbols in the global scope won't hurt.
1046
- //
1047
- // Note: Since we go through all the tokens to do this, we also use
1048
- // the opportunity to count how many times each identifier is used.
1049
-
1050
- offset = 0;
1051
- braceNesting = 0;
1052
- scopes.clear();
1053
- mode = CHECKING_SYMBOL_TREE;
1054
- parseScope(globalScope);
1055
- globalScope.munge();
1056
- }
1057
-
1058
- private StringBuffer printSymbolTree(int linebreakpos, boolean preserveAllSemiColons)
1059
- throws IOException {
1060
-
1061
- offset = 0;
1062
- braceNesting = 0;
1063
- scopes.clear();
1064
-
1065
- String symbol;
1066
- JavaScriptToken token;
1067
- ScriptOrFnScope currentScope;
1068
- JavaScriptIdentifier identifier;
1069
-
1070
- int length = tokens.size();
1071
- StringBuffer result = new StringBuffer();
1072
-
1073
- int linestartpos = 0;
1074
-
1075
- enterScope(globalScope);
1076
-
1077
- while (offset < length) {
1078
-
1079
- token = consumeToken();
1080
- symbol = token.getValue();
1081
- currentScope = getCurrentScope();
1082
-
1083
- switch (token.getType()) {
1084
-
1085
- case Token.NAME:
1086
-
1087
- if (offset >= 2 && getToken(-2).getType() == Token.DOT ||
1088
- getToken(0).getType() == Token.OBJECTLIT) {
1089
-
1090
- result.append(symbol);
1091
-
1092
- } else {
1093
-
1094
- identifier = getIdentifier(symbol, currentScope);
1095
- if (identifier != null) {
1096
- if (identifier.getMungedValue() != null) {
1097
- result.append(identifier.getMungedValue());
1098
- } else {
1099
- result.append(symbol);
1100
- }
1101
- if (currentScope != globalScope && identifier.getRefcount() == 0) {
1102
- warn("The symbol " + symbol + " is declared but is apparently never used.\nThis code can probably be written in a more compact way.", true);
1103
- }
1104
- } else {
1105
- result.append(symbol);
1106
- }
1107
- }
1108
- break;
1109
-
1110
- case Token.REGEXP:
1111
- case Token.NUMBER:
1112
- case Token.STRING:
1113
- result.append(symbol);
1114
- break;
1115
-
1116
- case Token.ADD:
1117
- case Token.SUB:
1118
- result.append((String) literals.get(new Integer(token.getType())));
1119
- if (offset < length) {
1120
- token = getToken(0);
1121
- if (token.getType() == Token.INC ||
1122
- token.getType() == Token.DEC ||
1123
- token.getType() == Token.ADD ||
1124
- token.getType() == Token.DEC) {
1125
- // Handle the case x +/- ++/-- y
1126
- // We must keep a white space here. Otherwise, x +++ y would be
1127
- // interpreted as x ++ + y by the compiler, which is a bug (due
1128
- // to the implicit assignment being done on the wrong variable)
1129
- result.append(' ');
1130
- } else if (token.getType() == Token.POS && getToken(-1).getType() == Token.ADD ||
1131
- token.getType() == Token.NEG && getToken(-1).getType() == Token.SUB) {
1132
- // Handle the case x + + y and x - - y
1133
- result.append(' ');
1134
- }
1135
- }
1136
- break;
1137
-
1138
- case Token.FUNCTION:
1139
- result.append("function");
1140
- token = consumeToken();
1141
- if (token.getType() == Token.NAME) {
1142
- result.append(' ');
1143
- symbol = token.getValue();
1144
- identifier = getIdentifier(symbol, currentScope);
1145
- assert identifier != null;
1146
- if (identifier.getMungedValue() != null) {
1147
- result.append(identifier.getMungedValue());
1148
- } else {
1149
- result.append(symbol);
1150
- }
1151
- if (currentScope != globalScope && identifier.getRefcount() == 0) {
1152
- warn("The symbol " + symbol + " is declared but is apparently never used.\nThis code can probably be written in a more compact way.", true);
1153
- }
1154
- token = consumeToken();
1155
- }
1156
- assert token.getType() == Token.LP;
1157
- result.append('(');
1158
- currentScope = (ScriptOrFnScope) indexedScopes.get(new Integer(offset));
1159
- enterScope(currentScope);
1160
- while ((token = consumeToken()).getType() != Token.RP) {
1161
- assert token.getType() == Token.NAME || token.getType() == Token.COMMA;
1162
- if (token.getType() == Token.NAME) {
1163
- symbol = token.getValue();
1164
- identifier = getIdentifier(symbol, currentScope);
1165
- assert identifier != null;
1166
- if (identifier.getMungedValue() != null) {
1167
- result.append(identifier.getMungedValue());
1168
- } else {
1169
- result.append(symbol);
1170
- }
1171
- } else if (token.getType() == Token.COMMA) {
1172
- result.append(',');
1173
- }
1174
- }
1175
- result.append(')');
1176
- token = consumeToken();
1177
- assert token.getType() == Token.LC;
1178
- result.append('{');
1179
- braceNesting++;
1180
- token = getToken(0);
1181
- if (token.getType() == Token.STRING &&
1182
- getToken(1).getType() == Token.SEMI) {
1183
- // This is a hint. Skip it!
1184
- consumeToken();
1185
- consumeToken();
1186
- }
1187
- break;
1188
-
1189
- case Token.RETURN:
1190
- case Token.TYPEOF:
1191
- result.append(literals.get(new Integer(token.getType())));
1192
- // No space needed after 'return' and 'typeof' when followed
1193
- // by '(', '[', '{', a string or a regexp.
1194
- if (offset < length) {
1195
- token = getToken(0);
1196
- if (token.getType() != Token.LP &&
1197
- token.getType() != Token.LB &&
1198
- token.getType() != Token.LC &&
1199
- token.getType() != Token.STRING &&
1200
- token.getType() != Token.REGEXP &&
1201
- token.getType() != Token.SEMI) {
1202
- result.append(' ');
1203
- }
1204
- }
1205
- break;
1206
-
1207
- case Token.CASE:
1208
- case Token.THROW:
1209
- result.append(literals.get(new Integer(token.getType())));
1210
- // White-space needed after 'case' and 'throw' when not followed by a string.
1211
- if (offset < length && getToken(0).getType() != Token.STRING) {
1212
- result.append(' ');
1213
- }
1214
- break;
1215
-
1216
- case Token.BREAK:
1217
- case Token.CONTINUE:
1218
- result.append(literals.get(new Integer(token.getType())));
1219
- if (offset < length && getToken(0).getType() != Token.SEMI) {
1220
- // If 'break' or 'continue' is not followed by a semi-colon, it must
1221
- // be followed by a label, hence the need for a white space.
1222
- result.append(' ');
1223
- }
1224
- break;
1225
-
1226
- case Token.LC:
1227
- result.append('{');
1228
- braceNesting++;
1229
- break;
1230
-
1231
- case Token.RC:
1232
- result.append('}');
1233
- braceNesting--;
1234
- assert braceNesting >= currentScope.getBraceNesting();
1235
- if (braceNesting == currentScope.getBraceNesting()) {
1236
- leaveCurrentScope();
1237
- }
1238
- break;
1239
-
1240
- case Token.SEMI:
1241
- // No need to output a semi-colon if the next character is a right-curly...
1242
- if (preserveAllSemiColons || offset < length && getToken(0).getType() != Token.RC) {
1243
- result.append(';');
1244
- }
1245
-
1246
- if (linebreakpos >= 0 && result.length() - linestartpos > linebreakpos) {
1247
- // Some source control tools don't like it when files containing lines longer
1248
- // than, say 8000 characters, are checked in. The linebreak option is used in
1249
- // that case to split long lines after a specific column.
1250
- result.append('\n');
1251
- linestartpos = result.length();
1252
- }
1253
- break;
1254
-
1255
- default:
1256
- String literal = (String) literals.get(new Integer(token.getType()));
1257
- if (literal != null) {
1258
- result.append(literal);
1259
- } else {
1260
- warn("This symbol cannot be printed: " + symbol, true);
1261
- }
1262
- break;
1263
- }
1264
- }
1265
-
1266
- // Append a semi-colon at the end, even if unnecessary semi-colons are
1267
- // supposed to be removed. This is especially useful when concatenating
1268
- // several minified files (the absence of an ending semi-colon at the
1269
- // end of one file may very likely cause a syntax error)
1270
- if (!preserveAllSemiColons &&
1271
- result.length() > 0) {
1272
- if (result.charAt(result.length() - 1) == '\n') {
1273
- result.setCharAt(result.length() - 1, ';');
1274
- } else {
1275
- result.append(';');
1276
- }
1277
- }
1278
-
1279
- return result;
1280
- }
1281
- }