golf 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
- }