assets_booster 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in assets_booster.gemspec
4
+ gemspec
data/README ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "assets_booster/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "assets_booster"
7
+ s.version = AssetsBooster::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Corin Langosch"]
10
+ s.email = ["info@netskin.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Assets (javascripts, css) compression for rails applications}
13
+ s.description = %q{Instead of sending down a dozen JavaScript and CSS files full of formatting and comments, this gem makes it simple to merge and compress these into one or more files, increasing speed and saving bandwidth.}
14
+
15
+ s.rubyforge_project = "assets_booster"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,7 @@
1
+ require 'assets_booster/railtie' if defined?(Rails)
2
+
3
+ module AssetsBooster
4
+ def self.log(message)
5
+ puts message
6
+ end
7
+ end
@@ -0,0 +1,36 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ module AssetsBooster
5
+ module Compiler
6
+ class Closure
7
+ def self.name
8
+ "Google Closure Compiler"
9
+ end
10
+
11
+ def self.compile(code)
12
+ post_data = {
13
+ 'js_code'=> code,
14
+ 'compilation_level' => 'SIMPLE_OPTIMIZATIONS',
15
+ 'output_format' => 'text',
16
+ 'output_info' => 'compiled_code'
17
+ }
18
+ uri = URI.parse('http://closure-compiler.appspot.com/compile')
19
+ res = Net::HTTP.post_form(uri, post_data)
20
+ case res
21
+ when Net::HTTPSuccess
22
+ data = res.body.strip
23
+ if code.size > 0 && data.size < 1
24
+ post_data['output_info'] = 'errors'
25
+ res = Net::HTTP.post_form(uri, post_data)
26
+ raise CompileError.new("Google's Closure Compiler failed: "+res.body)
27
+ end
28
+ data
29
+ else
30
+ raise CompileError.new("HTTP request TO Google's Closure Compiler failed: "+res.to_s)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,17 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ module AssetsBooster
5
+ module Compiler
6
+ class Dummy
7
+ def self.name
8
+ "Dummy Compiler"
9
+ end
10
+
11
+ def self.compile(code)
12
+ code
13
+ end
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,234 @@
1
+ # jsmin.rb 2007-07-20
2
+ # Author: Uladzislau Latynski
3
+ # This work is a translation from C to Ruby of jsmin.c published by
4
+ # Douglas Crockford. Permission is hereby granted to use the Ruby
5
+ # version under the same conditions as the jsmin.c on which it is
6
+ # based.
7
+ #
8
+ # /* jsmin.c
9
+ # 2003-04-21
10
+ #
11
+ # Copyright (c) 2002 Douglas Crockford (www.crockford.com)
12
+ #
13
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
14
+ # this software and associated documentation files (the "Software"), to deal in
15
+ # the Software without restriction, including without limitation the rights to
16
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
17
+ # of the Software, and to permit persons to whom the Software is furnished to do
18
+ # so, subject to the following conditions:
19
+ #
20
+ # The above copyright notice and this permission notice shall be included in all
21
+ # copies or substantial portions of the Software.
22
+ #
23
+ # The Software shall be used for Good, not Evil.
24
+ #
25
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
+ # SOFTWARE.
32
+
33
+ require 'stringio'
34
+
35
+ module AssetsBooster
36
+ module Compiler
37
+ class JSMin
38
+
39
+ # class variables
40
+ @@EOF = -1
41
+ @@theA = ""
42
+ @@theB = ""
43
+ @@input = ""
44
+ @@output = ""
45
+
46
+ # singleton methods
47
+ class << self
48
+
49
+ def name
50
+ "Douglas Crockford's JSMin"
51
+ end
52
+
53
+ def compile(incoming)
54
+ @@output = StringIO.new("","w")
55
+ if incoming.is_a? String
56
+ @@input = StringIO.new(incoming,"r")
57
+ elsif incoming.kind_of? IO
58
+ @@input = incoming
59
+ else
60
+ raise CompileError.new("JSMin can only compress strings or files.")
61
+ end
62
+ jsmin
63
+ @@output.string
64
+ end
65
+
66
+
67
+ protected
68
+ # isAlphanum -- return true if the character is a letter, digit, underscore,
69
+ # dollar sign, or non-ASCII character
70
+ def isAlphanum(c)
71
+ return false if !c || c == @@EOF
72
+ return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
73
+ (c >= 'A' && c <= 'Z') || c == '_' || c == '$' ||
74
+ c == '\\' || c[0].ord > 126)
75
+ end
76
+
77
+ # get -- return the next character from stdin. Watch out for lookahead. If
78
+ # the character is a control character, translate it to a space or linefeed.
79
+ def get()
80
+ c = @@input.getc
81
+ return @@EOF if(!c)
82
+ c = c.chr
83
+ return c if (c >= " " || c == "\n" || c.unpack("c") == @@EOF)
84
+ return "\n" if (c == "\r")
85
+ return " "
86
+ end
87
+
88
+ # Get the next character without getting it.
89
+ def peek()
90
+ lookaheadChar = @@input.getc
91
+ @@input.ungetc(lookaheadChar)
92
+ return lookaheadChar.chr
93
+ end
94
+
95
+ # mynext -- get the next character, excluding comments.
96
+ # peek() is used to see if a '/' is followed by a '/' or '*'.
97
+ def mynext()
98
+ c = get
99
+ if (c == "/")
100
+ if(peek == "/")
101
+ while(true)
102
+ c = get
103
+ if (c <= "\n")
104
+ return c
105
+ end
106
+ end
107
+ end
108
+ if(peek == "*")
109
+ get
110
+ while(true)
111
+ case get
112
+ when "*"
113
+ if (peek == "/")
114
+ get
115
+ return " "
116
+ end
117
+ when @@EOF
118
+ raise "Unterminated comment"
119
+ end
120
+ end
121
+ end
122
+ end
123
+ return c
124
+ end
125
+
126
+
127
+ # action -- do something! What you do is determined by the argument: 1
128
+ # Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
129
+ # (Delete A). 3 Get the next B. (Delete B). action treats a string as a
130
+ # single character. Wow! action recognizes a regular expression if it is
131
+ # preceded by ( or , or =.
132
+ def action(a)
133
+ if(a==1)
134
+ @@output.write $theA
135
+ end
136
+ if(a==1 || a==2)
137
+ $theA = $theB
138
+ if ($theA == "\'" || $theA == "\"")
139
+ while (true)
140
+ @@output.write $theA
141
+ $theA = get
142
+ break if ($theA == $theB)
143
+ raise "Unterminated string literal" if ($theA <= "\n")
144
+ if ($theA == "\\")
145
+ @@output.write $theA
146
+ $theA = get
147
+ end
148
+ end
149
+ end
150
+ end
151
+ if(a==1 || a==2 || a==3)
152
+ $theB = mynext
153
+ if ($theB == "/" && ($theA == "(" || $theA == "," || $theA == "=" ||
154
+ $theA == ":" || $theA == "[" || $theA == "!" ||
155
+ $theA == "&" || $theA == "|" || $theA == "?" ||
156
+ $theA == "{" || $theA == "}" || $theA == ";" ||
157
+ $theA == "\n"))
158
+ @@output.write $theA
159
+ @@output.write $theB
160
+ while (true)
161
+ $theA = get
162
+ if ($theA == "/")
163
+ break
164
+ elsif ($theA == "\\")
165
+ @@output.write $theA
166
+ $theA = get
167
+ elsif ($theA <= "\n")
168
+ raise "Unterminated RegExp Literal"
169
+ end
170
+ @@output.write $theA
171
+ end
172
+ $theB = mynext
173
+ end
174
+ end
175
+ end
176
+
177
+ # jsmin -- Copy the input to the output, deleting the characters which are
178
+ # insignificant to JavaScript. Comments will be removed. Tabs will be
179
+ # replaced with spaces. Carriage returns will be replaced with linefeeds.
180
+ # Most spaces and linefeeds will be removed.
181
+ def jsmin
182
+ $theA = "\n"
183
+ action(3)
184
+ while ($theA != @@EOF)
185
+ case $theA
186
+ when " "
187
+ if (isAlphanum($theB))
188
+ action(1)
189
+ else
190
+ action(2)
191
+ end
192
+ when "\n"
193
+ case ($theB)
194
+ when "{","[","(","+","-"
195
+ action(1)
196
+ when " "
197
+ action(3)
198
+ else
199
+ if (isAlphanum($theB))
200
+ action(1)
201
+ else
202
+ action(2)
203
+ end
204
+ end
205
+ else
206
+ case ($theB)
207
+ when " "
208
+ if (isAlphanum($theA))
209
+ action(1)
210
+ else
211
+ action(3)
212
+ end
213
+ when "\n"
214
+ case ($theA)
215
+ when "}","]",")","+","-","\"","\\", "'", '"'
216
+ action(1)
217
+ else
218
+ if (isAlphanum($theA))
219
+ action(1)
220
+ else
221
+ action(3)
222
+ end
223
+ end
224
+ else
225
+ action(1)
226
+ end
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end
234
+
@@ -0,0 +1,1254 @@
1
+ /***********************************************************************
2
+
3
+ A JavaScript tokenizer / parser / beautifier / compressor.
4
+
5
+ This version is suitable for Node.js. With minimal changes (the
6
+ exports stuff) it should work on any JS platform.
7
+
8
+ This file contains the tokenizer/parser. It is a port to JavaScript
9
+ of parse-js [1], a JavaScript parser library written in Common Lisp
10
+ by Marijn Haverbeke. Thank you Marijn!
11
+
12
+ [1] http://marijn.haverbeke.nl/parse-js/
13
+
14
+ Exported functions:
15
+
16
+ - tokenizer(code) -- returns a function. Call the returned
17
+ function to fetch the next token.
18
+
19
+ - parse(code) -- returns an AST of the given JavaScript code.
20
+
21
+ -------------------------------- (C) ---------------------------------
22
+
23
+ Author: Mihai Bazon
24
+ <mihai.bazon@gmail.com>
25
+ http://mihai.bazon.net/blog
26
+
27
+ Distributed under the BSD license:
28
+
29
+ Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com>
30
+ Based on parse-js (http://marijn.haverbeke.nl/parse-js/).
31
+
32
+ Redistribution and use in source and binary forms, with or without
33
+ modification, are permitted provided that the following conditions
34
+ are met:
35
+
36
+ * Redistributions of source code must retain the above
37
+ copyright notice, this list of conditions and the following
38
+ disclaimer.
39
+
40
+ * Redistributions in binary form must reproduce the above
41
+ copyright notice, this list of conditions and the following
42
+ disclaimer in the documentation and/or other materials
43
+ provided with the distribution.
44
+
45
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
46
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
49
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
50
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
52
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
53
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
54
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
55
+ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56
+ SUCH DAMAGE.
57
+
58
+ ***********************************************************************/
59
+
60
+ /* -----[ Tokenizer (constants) ]----- */
61
+
62
+ var KEYWORDS = array_to_hash([
63
+ "break",
64
+ "case",
65
+ "catch",
66
+ "const",
67
+ "continue",
68
+ "default",
69
+ "delete",
70
+ "do",
71
+ "else",
72
+ "finally",
73
+ "for",
74
+ "function",
75
+ "if",
76
+ "in",
77
+ "instanceof",
78
+ "new",
79
+ "return",
80
+ "switch",
81
+ "throw",
82
+ "try",
83
+ "typeof",
84
+ "var",
85
+ "void",
86
+ "while",
87
+ "with"
88
+ ]);
89
+
90
+ var RESERVED_WORDS = array_to_hash([
91
+ "abstract",
92
+ "boolean",
93
+ "byte",
94
+ "char",
95
+ "class",
96
+ "debugger",
97
+ "double",
98
+ "enum",
99
+ "export",
100
+ "extends",
101
+ "final",
102
+ "float",
103
+ "goto",
104
+ "implements",
105
+ "import",
106
+ "int",
107
+ "interface",
108
+ "long",
109
+ "native",
110
+ "package",
111
+ "private",
112
+ "protected",
113
+ "public",
114
+ "short",
115
+ "static",
116
+ "super",
117
+ "synchronized",
118
+ "throws",
119
+ "transient",
120
+ "volatile"
121
+ ]);
122
+
123
+ var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([
124
+ "return",
125
+ "new",
126
+ "delete",
127
+ "throw",
128
+ "else",
129
+ "case"
130
+ ]);
131
+
132
+ var KEYWORDS_ATOM = array_to_hash([
133
+ "false",
134
+ "null",
135
+ "true",
136
+ "undefined"
137
+ ]);
138
+
139
+ var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^"));
140
+
141
+ var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
142
+ var RE_OCT_NUMBER = /^0[0-7]+$/;
143
+ var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
144
+
145
+ var OPERATORS = array_to_hash([
146
+ "in",
147
+ "instanceof",
148
+ "typeof",
149
+ "new",
150
+ "void",
151
+ "delete",
152
+ "++",
153
+ "--",
154
+ "+",
155
+ "-",
156
+ "!",
157
+ "~",
158
+ "&",
159
+ "|",
160
+ "^",
161
+ "*",
162
+ "/",
163
+ "%",
164
+ ">>",
165
+ "<<",
166
+ ">>>",
167
+ "<",
168
+ ">",
169
+ "<=",
170
+ ">=",
171
+ "==",
172
+ "===",
173
+ "!=",
174
+ "!==",
175
+ "?",
176
+ "=",
177
+ "+=",
178
+ "-=",
179
+ "/=",
180
+ "*=",
181
+ "%=",
182
+ ">>=",
183
+ "<<=",
184
+ ">>>=",
185
+ "%=",
186
+ "|=",
187
+ "^=",
188
+ "&=",
189
+ "&&",
190
+ "||"
191
+ ]);
192
+
193
+ var WHITESPACE_CHARS = array_to_hash(characters(" \n\r\t"));
194
+
195
+ var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:"));
196
+
197
+ var PUNC_CHARS = array_to_hash(characters("[]{}(),;:"));
198
+
199
+ var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy"));
200
+
201
+ /* -----[ Tokenizer ]----- */
202
+
203
+ function is_alphanumeric_char(ch) {
204
+ ch = ch.charCodeAt(0);
205
+ return (ch >= 48 && ch <= 57) ||
206
+ (ch >= 65 && ch <= 90) ||
207
+ (ch >= 97 && ch <= 122);
208
+ };
209
+
210
+ function is_identifier_char(ch) {
211
+ return is_alphanumeric_char(ch) || ch == "$" || ch == "_";
212
+ };
213
+
214
+ function is_digit(ch) {
215
+ ch = ch.charCodeAt(0);
216
+ return ch >= 48 && ch <= 57;
217
+ };
218
+
219
+ function parse_js_number(num) {
220
+ if (RE_HEX_NUMBER.test(num)) {
221
+ return parseInt(num.substr(2), 16);
222
+ } else if (RE_OCT_NUMBER.test(num)) {
223
+ return parseInt(num.substr(1), 8);
224
+ } else if (RE_DEC_NUMBER.test(num)) {
225
+ return parseFloat(num);
226
+ }
227
+ };
228
+
229
+ function JS_Parse_Error(message, line, col, pos) {
230
+ this.message = message;
231
+ this.line = line;
232
+ this.col = col;
233
+ this.pos = pos;
234
+ try {
235
+ ({})();
236
+ } catch(ex) {
237
+ this.stack = ex.stack;
238
+ };
239
+ };
240
+
241
+ JS_Parse_Error.prototype.toString = function() {
242
+ return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack;
243
+ };
244
+
245
+ function js_error(message, line, col, pos) {
246
+ throw new JS_Parse_Error(message, line, col, pos);
247
+ };
248
+
249
+ function is_token(token, type, val) {
250
+ return token.type == type && (val == null || token.value == val);
251
+ };
252
+
253
+ var EX_EOF = {};
254
+
255
+ function tokenizer($TEXT) {
256
+
257
+ var S = {
258
+ text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''),
259
+ pos : 0,
260
+ tokpos : 0,
261
+ line : 0,
262
+ tokline : 0,
263
+ col : 0,
264
+ tokcol : 0,
265
+ newline_before : false,
266
+ regex_allowed : false,
267
+ comments_before : []
268
+ };
269
+
270
+ function peek() { return S.text.charAt(S.pos); };
271
+
272
+ function next(signal_eof) {
273
+ var ch = S.text.charAt(S.pos++);
274
+ if (signal_eof && !ch)
275
+ throw EX_EOF;
276
+ if (ch == "\n") {
277
+ S.newline_before = true;
278
+ ++S.line;
279
+ S.col = 0;
280
+ } else {
281
+ ++S.col;
282
+ }
283
+ return ch;
284
+ };
285
+
286
+ function eof() {
287
+ return !S.peek();
288
+ };
289
+
290
+ function find(what, signal_eof) {
291
+ var pos = S.text.indexOf(what, S.pos);
292
+ if (signal_eof && pos == -1) throw EX_EOF;
293
+ return pos;
294
+ };
295
+
296
+ function start_token() {
297
+ S.tokline = S.line;
298
+ S.tokcol = S.col;
299
+ S.tokpos = S.pos;
300
+ };
301
+
302
+ function token(type, value, is_comment) {
303
+ S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) ||
304
+ (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) ||
305
+ (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value)));
306
+ var ret = {
307
+ type : type,
308
+ value : value,
309
+ line : S.tokline,
310
+ col : S.tokcol,
311
+ pos : S.tokpos,
312
+ nlb : S.newline_before
313
+ };
314
+ if (!is_comment) {
315
+ ret.comments_before = S.comments_before;
316
+ S.comments_before = [];
317
+ }
318
+ S.newline_before = false;
319
+ return ret;
320
+ };
321
+
322
+ function skip_whitespace() {
323
+ while (HOP(WHITESPACE_CHARS, peek()))
324
+ next();
325
+ };
326
+
327
+ function read_while(pred) {
328
+ var ret = "", ch = peek(), i = 0;
329
+ while (ch && pred(ch, i++)) {
330
+ ret += next();
331
+ ch = peek();
332
+ }
333
+ return ret;
334
+ };
335
+
336
+ function parse_error(err) {
337
+ js_error(err, S.tokline, S.tokcol, S.tokpos);
338
+ };
339
+
340
+ function read_num(prefix) {
341
+ var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".";
342
+ var num = read_while(function(ch, i){
343
+ if (ch == "x" || ch == "X") {
344
+ if (has_x) return false;
345
+ return has_x = true;
346
+ }
347
+ if (!has_x && (ch == "E" || ch == "e")) {
348
+ if (has_e) return false;
349
+ return has_e = after_e = true;
350
+ }
351
+ if (ch == "-") {
352
+ if (after_e || (i == 0 && !prefix)) return true;
353
+ return false;
354
+ }
355
+ if (ch == "+") return after_e;
356
+ after_e = false;
357
+ if (ch == ".") {
358
+ if (!has_dot)
359
+ return has_dot = true;
360
+ return false;
361
+ }
362
+ return is_alphanumeric_char(ch);
363
+ });
364
+ if (prefix)
365
+ num = prefix + num;
366
+ var valid = parse_js_number(num);
367
+ if (!isNaN(valid)) {
368
+ return token("num", valid);
369
+ } else {
370
+ parse_error("Invalid syntax: " + num);
371
+ }
372
+ };
373
+
374
+ function read_escaped_char() {
375
+ var ch = next(true);
376
+ switch (ch) {
377
+ case "n" : return "\n";
378
+ case "r" : return "\r";
379
+ case "t" : return "\t";
380
+ case "b" : return "\b";
381
+ case "v" : return "\v";
382
+ case "f" : return "\f";
383
+ case "0" : return "\0";
384
+ case "x" : return String.fromCharCode(hex_bytes(2));
385
+ case "u" : return String.fromCharCode(hex_bytes(4));
386
+ default : return ch;
387
+ }
388
+ };
389
+
390
+ function hex_bytes(n) {
391
+ var num = 0;
392
+ for (; n > 0; --n) {
393
+ var digit = parseInt(next(true), 16);
394
+ if (isNaN(digit))
395
+ parse_error("Invalid hex-character pattern in string");
396
+ num = (num << 4) | digit;
397
+ }
398
+ return num;
399
+ };
400
+
401
+ function read_string() {
402
+ return with_eof_error("Unterminated string constant", function(){
403
+ var quote = next(), ret = "";
404
+ for (;;) {
405
+ var ch = next(true);
406
+ if (ch == "\\") ch = read_escaped_char();
407
+ else if (ch == quote) break;
408
+ ret += ch;
409
+ }
410
+ return token("string", ret);
411
+ });
412
+ };
413
+
414
+ function read_line_comment() {
415
+ next();
416
+ var i = find("\n"), ret;
417
+ if (i == -1) {
418
+ ret = S.text.substr(S.pos);
419
+ S.pos = S.text.length;
420
+ } else {
421
+ ret = S.text.substring(S.pos, i);
422
+ S.pos = i;
423
+ }
424
+ return token("comment1", ret, true);
425
+ };
426
+
427
+ function read_multiline_comment() {
428
+ next();
429
+ return with_eof_error("Unterminated multiline comment", function(){
430
+ var i = find("*/", true),
431
+ text = S.text.substring(S.pos, i),
432
+ tok = token("comment2", text, true);
433
+ S.pos = i + 2;
434
+ S.line += text.split("\n").length - 1;
435
+ S.newline_before = text.indexOf("\n") >= 0;
436
+ return tok;
437
+ });
438
+ };
439
+
440
+ function read_regexp() {
441
+ return with_eof_error("Unterminated regular expression", function(){
442
+ var prev_backslash = false, regexp = "", ch, in_class = false;
443
+ while ((ch = next(true))) if (prev_backslash) {
444
+ regexp += "\\" + ch;
445
+ prev_backslash = false;
446
+ } else if (ch == "[") {
447
+ in_class = true;
448
+ regexp += ch;
449
+ } else if (ch == "]" && in_class) {
450
+ in_class = false;
451
+ regexp += ch;
452
+ } else if (ch == "/" && !in_class) {
453
+ break;
454
+ } else if (ch == "\\") {
455
+ prev_backslash = true;
456
+ } else {
457
+ regexp += ch;
458
+ }
459
+ var mods = read_while(function(ch){
460
+ return HOP(REGEXP_MODIFIERS, ch);
461
+ });
462
+ return token("regexp", [ regexp, mods ]);
463
+ });
464
+ };
465
+
466
+ function read_operator(prefix) {
467
+ function grow(op) {
468
+ if (!peek()) return op;
469
+ var bigger = op + peek();
470
+ if (HOP(OPERATORS, bigger)) {
471
+ next();
472
+ return grow(bigger);
473
+ } else {
474
+ return op;
475
+ }
476
+ };
477
+ return token("operator", grow(prefix || next()));
478
+ };
479
+
480
+ function handle_slash() {
481
+ next();
482
+ var regex_allowed = S.regex_allowed;
483
+ switch (peek()) {
484
+ case "/":
485
+ S.comments_before.push(read_line_comment());
486
+ S.regex_allowed = regex_allowed;
487
+ return next_token();
488
+ case "*":
489
+ S.comments_before.push(read_multiline_comment());
490
+ S.regex_allowed = regex_allowed;
491
+ return next_token();
492
+ }
493
+ return S.regex_allowed ? read_regexp() : read_operator("/");
494
+ };
495
+
496
+ function handle_dot() {
497
+ next();
498
+ return is_digit(peek())
499
+ ? read_num(".")
500
+ : token("punc", ".");
501
+ };
502
+
503
+ function read_word() {
504
+ var word = read_while(is_identifier_char);
505
+ return !HOP(KEYWORDS, word)
506
+ ? token("name", word)
507
+ : HOP(OPERATORS, word)
508
+ ? token("operator", word)
509
+ : HOP(KEYWORDS_ATOM, word)
510
+ ? token("atom", word)
511
+ : token("keyword", word);
512
+ };
513
+
514
+ function with_eof_error(eof_error, cont) {
515
+ try {
516
+ return cont();
517
+ } catch(ex) {
518
+ if (ex === EX_EOF) parse_error(eof_error);
519
+ else throw ex;
520
+ }
521
+ };
522
+
523
+ function next_token(force_regexp) {
524
+ if (force_regexp)
525
+ return read_regexp();
526
+ skip_whitespace();
527
+ start_token();
528
+ var ch = peek();
529
+ if (!ch) return token("eof");
530
+ if (is_digit(ch)) return read_num();
531
+ if (ch == '"' || ch == "'") return read_string();
532
+ if (HOP(PUNC_CHARS, ch)) return token("punc", next());
533
+ if (ch == ".") return handle_dot();
534
+ if (ch == "/") return handle_slash();
535
+ if (HOP(OPERATOR_CHARS, ch)) return read_operator();
536
+ if (is_identifier_char(ch)) return read_word();
537
+ parse_error("Unexpected character '" + ch + "'");
538
+ };
539
+
540
+ next_token.context = function(nc) {
541
+ if (nc) S = nc;
542
+ return S;
543
+ };
544
+
545
+ return next_token;
546
+
547
+ };
548
+
549
+ /* -----[ Parser (constants) ]----- */
550
+
551
+ var UNARY_PREFIX = array_to_hash([
552
+ "typeof",
553
+ "void",
554
+ "delete",
555
+ "--",
556
+ "++",
557
+ "!",
558
+ "~",
559
+ "-",
560
+ "+"
561
+ ]);
562
+
563
+ var UNARY_POSTFIX = array_to_hash([ "--", "++" ]);
564
+
565
+ var ASSIGNMENT = (function(a, ret, i){
566
+ while (i < a.length) {
567
+ ret[a[i]] = a[i].substr(0, a[i].length - 1);
568
+ i++;
569
+ }
570
+ return ret;
571
+ })(
572
+ ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&="],
573
+ { "=": true },
574
+ 0
575
+ );
576
+
577
+ var PRECEDENCE = (function(a, ret){
578
+ for (var i = 0, n = 1; i < a.length; ++i, ++n) {
579
+ var b = a[i];
580
+ for (var j = 0; j < b.length; ++j) {
581
+ ret[b[j]] = n;
582
+ }
583
+ }
584
+ return ret;
585
+ })(
586
+ [
587
+ ["||"],
588
+ ["&&"],
589
+ ["|"],
590
+ ["^"],
591
+ ["&"],
592
+ ["==", "===", "!=", "!=="],
593
+ ["<", ">", "<=", ">=", "in", "instanceof"],
594
+ [">>", "<<", ">>>"],
595
+ ["+", "-"],
596
+ ["*", "/", "%"]
597
+ ],
598
+ {}
599
+ );
600
+
601
+ var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]);
602
+
603
+ var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]);
604
+
605
+ /* -----[ Parser ]----- */
606
+
607
+ function NodeWithToken(str, start, end) {
608
+ this.name = str;
609
+ this.start = start;
610
+ this.end = end;
611
+ };
612
+
613
+ NodeWithToken.prototype.toString = function() { return this.name; };
614
+
615
+ function parse($TEXT, strict_mode, embed_tokens) {
616
+
617
+ var S = {
618
+ input : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT,
619
+ token : null,
620
+ prev : null,
621
+ peeked : null,
622
+ in_function : 0,
623
+ in_loop : 0,
624
+ labels : []
625
+ };
626
+
627
+ S.token = next();
628
+
629
+ function is(type, value) {
630
+ return is_token(S.token, type, value);
631
+ };
632
+
633
+ function peek() { return S.peeked || (S.peeked = S.input()); };
634
+
635
+ function next() {
636
+ S.prev = S.token;
637
+ if (S.peeked) {
638
+ S.token = S.peeked;
639
+ S.peeked = null;
640
+ } else {
641
+ S.token = S.input();
642
+ }
643
+ return S.token;
644
+ };
645
+
646
+ function prev() {
647
+ return S.prev;
648
+ };
649
+
650
+ function croak(msg, line, col, pos) {
651
+ var ctx = S.input.context();
652
+ js_error(msg,
653
+ line != null ? line : ctx.tokline,
654
+ col != null ? col : ctx.tokcol,
655
+ pos != null ? pos : ctx.tokpos);
656
+ };
657
+
658
+ function token_error(token, msg) {
659
+ croak(msg, token.line, token.col);
660
+ };
661
+
662
+ function unexpected(token) {
663
+ if (token == null)
664
+ token = S.token;
665
+ token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
666
+ };
667
+
668
+ function expect_token(type, val) {
669
+ if (is(type, val)) {
670
+ return next();
671
+ }
672
+ token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type);
673
+ };
674
+
675
+ function expect(punc) { return expect_token("punc", punc); };
676
+
677
+ function can_insert_semicolon() {
678
+ return !strict_mode && (
679
+ S.token.nlb || is("eof") || is("punc", "}")
680
+ );
681
+ };
682
+
683
+ function semicolon() {
684
+ if (is("punc", ";")) next();
685
+ else if (!can_insert_semicolon()) unexpected();
686
+ };
687
+
688
+ function as() {
689
+ return slice(arguments);
690
+ };
691
+
692
+ function parenthesised() {
693
+ expect("(");
694
+ var ex = expression();
695
+ expect(")");
696
+ return ex;
697
+ };
698
+
699
+ function add_tokens(str, start, end) {
700
+ return str instanceof NodeWithToken ? str : new NodeWithToken(str, start, end);
701
+ };
702
+
703
+ var statement = embed_tokens ? function() {
704
+ var start = S.token;
705
+ var ast = $statement.apply(this, arguments);
706
+ ast[0] = add_tokens(ast[0], start, prev());
707
+ return ast;
708
+ } : $statement;
709
+
710
+ function $statement() {
711
+ if (is("operator", "/")) {
712
+ S.peeked = null;
713
+ S.token = S.input(true); // force regexp
714
+ }
715
+ switch (S.token.type) {
716
+ case "num":
717
+ case "string":
718
+ case "regexp":
719
+ case "operator":
720
+ case "atom":
721
+ return simple_statement();
722
+
723
+ case "name":
724
+ return is_token(peek(), "punc", ":")
725
+ ? labeled_statement(prog1(S.token.value, next, next))
726
+ : simple_statement();
727
+
728
+ case "punc":
729
+ switch (S.token.value) {
730
+ case "{":
731
+ return as("block", block_());
732
+ case "[":
733
+ case "(":
734
+ return simple_statement();
735
+ case ";":
736
+ next();
737
+ return as("block");
738
+ default:
739
+ unexpected();
740
+ }
741
+
742
+ case "keyword":
743
+ switch (prog1(S.token.value, next)) {
744
+ case "break":
745
+ return break_cont("break");
746
+
747
+ case "continue":
748
+ return break_cont("continue");
749
+
750
+ case "debugger":
751
+ semicolon();
752
+ return as("debugger");
753
+
754
+ case "do":
755
+ return (function(body){
756
+ expect_token("keyword", "while");
757
+ return as("do", prog1(parenthesised, semicolon), body);
758
+ })(in_loop(statement));
759
+
760
+ case "for":
761
+ return for_();
762
+
763
+ case "function":
764
+ return function_(true);
765
+
766
+ case "if":
767
+ return if_();
768
+
769
+ case "return":
770
+ if (S.in_function == 0)
771
+ croak("'return' outside of function");
772
+ return as("return",
773
+ is("punc", ";")
774
+ ? (next(), null)
775
+ : can_insert_semicolon()
776
+ ? null
777
+ : prog1(expression, semicolon));
778
+
779
+ case "switch":
780
+ return as("switch", parenthesised(), switch_block_());
781
+
782
+ case "throw":
783
+ return as("throw", prog1(expression, semicolon));
784
+
785
+ case "try":
786
+ return try_();
787
+
788
+ case "var":
789
+ return prog1(var_, semicolon);
790
+
791
+ case "const":
792
+ return prog1(const_, semicolon);
793
+
794
+ case "while":
795
+ return as("while", parenthesised(), in_loop(statement));
796
+
797
+ case "with":
798
+ return as("with", parenthesised(), statement());
799
+
800
+ default:
801
+ unexpected();
802
+ }
803
+ }
804
+ };
805
+
806
+ function labeled_statement(label) {
807
+ S.labels.push(label);
808
+ var start = S.token, stat = statement();
809
+ if (strict_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0]))
810
+ unexpected(start);
811
+ S.labels.pop();
812
+ return as("label", label, stat);
813
+ };
814
+
815
+ function simple_statement() {
816
+ return as("stat", prog1(expression, semicolon));
817
+ };
818
+
819
+ function break_cont(type) {
820
+ var name = is("name") ? S.token.value : null;
821
+ if (name != null) {
822
+ next();
823
+ if (!member(name, S.labels))
824
+ croak("Label " + name + " without matching loop or statement");
825
+ }
826
+ else if (S.in_loop == 0)
827
+ croak(type + " not inside a loop or switch");
828
+ semicolon();
829
+ return as(type, name);
830
+ };
831
+
832
+ function for_() {
833
+ expect("(");
834
+ var has_var = is("keyword", "var");
835
+ if (has_var)
836
+ next();
837
+ if (is("name") && is_token(peek(), "operator", "in")) {
838
+ // for (i in foo)
839
+ var name = S.token.value;
840
+ next(); next();
841
+ var obj = expression();
842
+ expect(")");
843
+ return as("for-in", has_var, name, obj, in_loop(statement));
844
+ } else {
845
+ // classic for
846
+ var init = is("punc", ";") ? null : has_var ? var_() : expression();
847
+ expect(";");
848
+ var test = is("punc", ";") ? null : expression();
849
+ expect(";");
850
+ var step = is("punc", ")") ? null : expression();
851
+ expect(")");
852
+ return as("for", init, test, step, in_loop(statement));
853
+ }
854
+ };
855
+
856
+ var function_ = embed_tokens ? function() {
857
+ var start = prev();
858
+ var ast = $function_.apply(this, arguments);
859
+ ast[0] = add_tokens(ast[0], start, prev());
860
+ return ast;
861
+ } : $function_;
862
+
863
+ function $function_(in_statement) {
864
+ var name = is("name") ? prog1(S.token.value, next) : null;
865
+ if (in_statement && !name)
866
+ unexpected();
867
+ expect("(");
868
+ return as(in_statement ? "defun" : "function",
869
+ name,
870
+ // arguments
871
+ (function(first, a){
872
+ while (!is("punc", ")")) {
873
+ if (first) first = false; else expect(",");
874
+ if (!is("name")) unexpected();
875
+ a.push(S.token.value);
876
+ next();
877
+ }
878
+ next();
879
+ return a;
880
+ })(true, []),
881
+ // body
882
+ (function(){
883
+ ++S.in_function;
884
+ var loop = S.in_loop;
885
+ S.in_loop = 0;
886
+ var a = block_();
887
+ --S.in_function;
888
+ S.in_loop = loop;
889
+ return a;
890
+ })());
891
+ };
892
+
893
+ function if_() {
894
+ var cond = parenthesised(), body = statement(), belse;
895
+ if (is("keyword", "else")) {
896
+ next();
897
+ belse = statement();
898
+ }
899
+ return as("if", cond, body, belse);
900
+ };
901
+
902
+ function block_() {
903
+ expect("{");
904
+ var a = [];
905
+ while (!is("punc", "}")) {
906
+ if (is("eof")) unexpected();
907
+ a.push(statement());
908
+ }
909
+ next();
910
+ return a;
911
+ };
912
+
913
+ var switch_block_ = curry(in_loop, function(){
914
+ expect("{");
915
+ var a = [], cur = null;
916
+ while (!is("punc", "}")) {
917
+ if (is("eof")) unexpected();
918
+ if (is("keyword", "case")) {
919
+ next();
920
+ cur = [];
921
+ a.push([ expression(), cur ]);
922
+ expect(":");
923
+ }
924
+ else if (is("keyword", "default")) {
925
+ next();
926
+ expect(":");
927
+ cur = [];
928
+ a.push([ null, cur ]);
929
+ }
930
+ else {
931
+ if (!cur) unexpected();
932
+ cur.push(statement());
933
+ }
934
+ }
935
+ next();
936
+ return a;
937
+ });
938
+
939
+ function try_() {
940
+ var body = block_(), bcatch, bfinally;
941
+ if (is("keyword", "catch")) {
942
+ next();
943
+ expect("(");
944
+ if (!is("name"))
945
+ croak("Name expected");
946
+ var name = S.token.value;
947
+ next();
948
+ expect(")");
949
+ bcatch = [ name, block_() ];
950
+ }
951
+ if (is("keyword", "finally")) {
952
+ next();
953
+ bfinally = block_();
954
+ }
955
+ if (!bcatch && !bfinally)
956
+ croak("Missing catch/finally blocks");
957
+ return as("try", body, bcatch, bfinally);
958
+ };
959
+
960
+ function vardefs() {
961
+ var a = [];
962
+ for (;;) {
963
+ if (!is("name"))
964
+ unexpected();
965
+ var name = S.token.value;
966
+ next();
967
+ if (is("operator", "=")) {
968
+ next();
969
+ a.push([ name, expression(false) ]);
970
+ } else {
971
+ a.push([ name ]);
972
+ }
973
+ if (!is("punc", ","))
974
+ break;
975
+ next();
976
+ }
977
+ return a;
978
+ };
979
+
980
+ function var_() {
981
+ return as("var", vardefs());
982
+ };
983
+
984
+ function const_() {
985
+ return as("const", vardefs());
986
+ };
987
+
988
+ function new_() {
989
+ var newexp = expr_atom(false), args;
990
+ if (is("punc", "(")) {
991
+ next();
992
+ args = expr_list(")");
993
+ } else {
994
+ args = [];
995
+ }
996
+ return subscripts(as("new", newexp, args), true);
997
+ };
998
+
999
+ function expr_atom(allow_calls) {
1000
+ if (is("operator", "new")) {
1001
+ next();
1002
+ return new_();
1003
+ }
1004
+ if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) {
1005
+ return make_unary("unary-prefix",
1006
+ prog1(S.token.value, next),
1007
+ expr_atom(allow_calls));
1008
+ }
1009
+ if (is("punc")) {
1010
+ switch (S.token.value) {
1011
+ case "(":
1012
+ next();
1013
+ return subscripts(prog1(expression, curry(expect, ")")), allow_calls);
1014
+ case "[":
1015
+ next();
1016
+ return subscripts(array_(), allow_calls);
1017
+ case "{":
1018
+ next();
1019
+ return subscripts(object_(), allow_calls);
1020
+ }
1021
+ unexpected();
1022
+ }
1023
+ if (is("keyword", "function")) {
1024
+ next();
1025
+ return subscripts(function_(false), allow_calls);
1026
+ }
1027
+ if (HOP(ATOMIC_START_TOKEN, S.token.type)) {
1028
+ var atom = S.token.type == "regexp"
1029
+ ? as("regexp", S.token.value[0], S.token.value[1])
1030
+ : as(S.token.type, S.token.value);
1031
+ return subscripts(prog1(atom, next), allow_calls);
1032
+ }
1033
+ unexpected();
1034
+ };
1035
+
1036
+ function expr_list(closing, allow_trailing_comma, allow_empty) {
1037
+ var first = true, a = [];
1038
+ while (!is("punc", closing)) {
1039
+ if (first) first = false; else expect(",");
1040
+ if (allow_trailing_comma && is("punc", closing)) break;
1041
+ if (is("punc", ",") && allow_empty) {
1042
+ a.push([ "atom", "undefined" ]);
1043
+ } else {
1044
+ a.push(expression(false));
1045
+ }
1046
+ }
1047
+ next();
1048
+ return a;
1049
+ };
1050
+
1051
+ function array_() {
1052
+ return as("array", expr_list("]", !strict_mode, true));
1053
+ };
1054
+
1055
+ function object_() {
1056
+ var first = true, a = [];
1057
+ while (!is("punc", "}")) {
1058
+ if (first) first = false; else expect(",");
1059
+ if (!strict_mode && is("punc", "}"))
1060
+ // allow trailing comma
1061
+ break;
1062
+ var type = S.token.type;
1063
+ var name = as_property_name();
1064
+ if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) {
1065
+ a.push([ as_name(), function_(false), name ]);
1066
+ } else {
1067
+ expect(":");
1068
+ a.push([ name, expression(false) ]);
1069
+ }
1070
+ }
1071
+ next();
1072
+ return as("object", a);
1073
+ };
1074
+
1075
+ function as_property_name() {
1076
+ switch (S.token.type) {
1077
+ case "num":
1078
+ case "string":
1079
+ return prog1(S.token.value, next);
1080
+ }
1081
+ return as_name();
1082
+ };
1083
+
1084
+ function as_name() {
1085
+ switch (S.token.type) {
1086
+ case "name":
1087
+ case "operator":
1088
+ case "keyword":
1089
+ case "atom":
1090
+ return prog1(S.token.value, next);
1091
+ default:
1092
+ unexpected();
1093
+ }
1094
+ };
1095
+
1096
+ function subscripts(expr, allow_calls) {
1097
+ if (is("punc", ".")) {
1098
+ next();
1099
+ return subscripts(as("dot", expr, as_name()), allow_calls);
1100
+ }
1101
+ if (is("punc", "[")) {
1102
+ next();
1103
+ return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls);
1104
+ }
1105
+ if (allow_calls && is("punc", "(")) {
1106
+ next();
1107
+ return subscripts(as("call", expr, expr_list(")")), true);
1108
+ }
1109
+ if (allow_calls && is("operator") && HOP(UNARY_POSTFIX, S.token.value)) {
1110
+ return prog1(curry(make_unary, "unary-postfix", S.token.value, expr),
1111
+ next);
1112
+ }
1113
+ return expr;
1114
+ };
1115
+
1116
+ function make_unary(tag, op, expr) {
1117
+ if ((op == "++" || op == "--") && !is_assignable(expr))
1118
+ croak("Invalid use of " + op + " operator");
1119
+ return as(tag, op, expr);
1120
+ };
1121
+
1122
+ function expr_op(left, min_prec) {
1123
+ var op = is("operator") ? S.token.value : null;
1124
+ var prec = op != null ? PRECEDENCE[op] : null;
1125
+ if (prec != null && prec > min_prec) {
1126
+ next();
1127
+ var right = expr_op(expr_atom(true), prec);
1128
+ return expr_op(as("binary", op, left, right), min_prec);
1129
+ }
1130
+ return left;
1131
+ };
1132
+
1133
+ function expr_ops() {
1134
+ return expr_op(expr_atom(true), 0);
1135
+ };
1136
+
1137
+ function maybe_conditional() {
1138
+ var expr = expr_ops();
1139
+ if (is("operator", "?")) {
1140
+ next();
1141
+ var yes = expression(false);
1142
+ expect(":");
1143
+ return as("conditional", expr, yes, expression(false));
1144
+ }
1145
+ return expr;
1146
+ };
1147
+
1148
+ function is_assignable(expr) {
1149
+ switch (expr[0]) {
1150
+ case "dot":
1151
+ case "sub":
1152
+ return true;
1153
+ case "name":
1154
+ return expr[1] != "this";
1155
+ }
1156
+ };
1157
+
1158
+ function maybe_assign() {
1159
+ var left = maybe_conditional(), val = S.token.value;
1160
+ if (is("operator") && HOP(ASSIGNMENT, val)) {
1161
+ if (is_assignable(left)) {
1162
+ next();
1163
+ return as("assign", ASSIGNMENT[val], left, maybe_assign());
1164
+ }
1165
+ croak("Invalid assignment");
1166
+ }
1167
+ return left;
1168
+ };
1169
+
1170
+ function expression(commas) {
1171
+ if (arguments.length == 0)
1172
+ commas = true;
1173
+ var expr = maybe_assign();
1174
+ if (commas && is("punc", ",")) {
1175
+ next();
1176
+ return as("seq", expr, expression());
1177
+ }
1178
+ return expr;
1179
+ };
1180
+
1181
+ function in_loop(cont) {
1182
+ try {
1183
+ ++S.in_loop;
1184
+ return cont();
1185
+ } finally {
1186
+ --S.in_loop;
1187
+ }
1188
+ };
1189
+
1190
+ return as("toplevel", (function(a){
1191
+ while (!is("eof"))
1192
+ a.push(statement());
1193
+ return a;
1194
+ })([]));
1195
+
1196
+ };
1197
+
1198
+ /* -----[ Utilities ]----- */
1199
+
1200
+ function curry(f) {
1201
+ var args = slice(arguments, 1);
1202
+ return function() { return f.apply(this, args.concat(slice(arguments))); };
1203
+ };
1204
+
1205
+ function prog1(ret) {
1206
+ if (ret instanceof Function)
1207
+ ret = ret();
1208
+ for (var i = 1, n = arguments.length; --n > 0; ++i)
1209
+ arguments[i]();
1210
+ return ret;
1211
+ };
1212
+
1213
+ function array_to_hash(a) {
1214
+ var ret = {};
1215
+ for (var i = 0; i < a.length; ++i)
1216
+ ret[a[i]] = true;
1217
+ return ret;
1218
+ };
1219
+
1220
+ function slice(a, start) {
1221
+ return Array.prototype.slice.call(a, start == null ? 0 : start);
1222
+ };
1223
+
1224
+ function characters(str) {
1225
+ return str.split("");
1226
+ };
1227
+
1228
+ function member(name, array) {
1229
+ for (var i = array.length; --i >= 0;)
1230
+ if (array[i] === name)
1231
+ return true;
1232
+ return false;
1233
+ };
1234
+
1235
+ function HOP(obj, prop) {
1236
+ return Object.prototype.hasOwnProperty.call(obj, prop);
1237
+ };
1238
+
1239
+ /* -----[ Exports ]----- */
1240
+
1241
+ exports.tokenizer = tokenizer;
1242
+ exports.parse = parse;
1243
+ exports.slice = slice;
1244
+ exports.curry = curry;
1245
+ exports.member = member;
1246
+ exports.array_to_hash = array_to_hash;
1247
+ exports.PRECEDENCE = PRECEDENCE;
1248
+ exports.KEYWORDS_ATOM = KEYWORDS_ATOM;
1249
+ exports.RESERVED_WORDS = RESERVED_WORDS;
1250
+ exports.KEYWORDS = KEYWORDS;
1251
+ exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN;
1252
+ exports.OPERATORS = OPERATORS;
1253
+ exports.is_alphanumeric_char = is_alphanumeric_char;
1254
+ exports.is_identifier_char = is_identifier_char;