sweetjs 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ execjs_runtimes = {
6
+ "RubyRacer" => "therubyracer",
7
+ "RubyRhino" => "therubyrhino",
8
+ "Mustang" => "mustang"
9
+ }
10
+
11
+ if ENV["EXECJS_RUNTIME"] && execjs_runtimes[ENV["EXECJS_RUNTIME"]]
12
+ gem execjs_runtimes[ENV["EXECJS_RUNTIME"]], :group => :development
13
+ end
14
+
15
+ # Engine
16
+ gem ENV["MULTI_JSON_ENGINE"], :group => :development if ENV["MULTI_JSON_ENGINE"]
17
+
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Garry Hill
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,39 @@
1
+ # Sweet Javascript Macros from Ruby
2
+
3
+ This is a Ruby wrapper around the [Sweet.js macro processor](http://sweetjs.org).
4
+
5
+ Go to [sweetjs.org](http://sweetjs.org) for more information.
6
+
7
+ ## Installation
8
+
9
+ gem install sweetjs
10
+
11
+ Ensure that your environment has a JavaScript interpreter supported by
12
+ [ExecJS](https://github.com/sstephenson/execjs). Using the
13
+ [therubyracer](https://github.com/cowboyd/therubyracer) gem is a good option.
14
+
15
+ In your `Gemfile`:
16
+
17
+ gem "sweetjs"
18
+ gem "therubyracer"
19
+
20
+
21
+ ## Usage
22
+
23
+ require 'sweetjs'
24
+
25
+ SweetJS.new.compile(File.read("source.sjs"))
26
+ # => processed JavaScript source
27
+
28
+ # Or alternatively:
29
+ SweetJS.compile(File.read("source.sjs"))
30
+
31
+ ## Acknowledgements
32
+
33
+ Thanks to [Ville Lautanala](https://github.com/lautis) who unwittingly wrote
34
+ most of the code and the README.
35
+
36
+ ## Copyright
37
+
38
+ © Garry Hill, [Magnetised Ltd](https://magnetised.net/). Released under MIT license, see [LICENSE.txt](https://github.com/magnetised/sweetjs/blob/master/LICENSE.txt) for more details.
39
+
@@ -0,0 +1,125 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+
12
+ require 'rake'
13
+ require 'date'
14
+
15
+ require 'rspec/core'
16
+ require 'rspec/core/rake_task'
17
+
18
+ RSpec::Core::RakeTask.new(:spec) do |spec|
19
+ spec.pattern = FileList['spec/**/*_spec.rb']
20
+ end
21
+
22
+ task :default => :spec
23
+
24
+ #############################################################################
25
+ #
26
+ # Helper functions
27
+ #
28
+ #############################################################################
29
+
30
+ def name
31
+ @name ||= Dir['*.gemspec'].first.split('.').first
32
+ end
33
+
34
+ def version
35
+ line = File.read("lib/sweetjs.rb")[/^\s*VERSION\s*=\s*.*/]
36
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
37
+ end
38
+
39
+ def date
40
+ Date.today.to_s
41
+ end
42
+
43
+ def rubyforge_project
44
+ name
45
+ end
46
+
47
+ def gemspec_file
48
+ "#{name}.gemspec"
49
+ end
50
+
51
+ def gem_file
52
+ "#{name}-#{version}.gem"
53
+ end
54
+
55
+ def replace_header(head, header_name)
56
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
57
+ end
58
+
59
+ #############################################################################
60
+ #
61
+ # Packaging tasks
62
+ #
63
+ #############################################################################
64
+
65
+ desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
66
+ task :release => :build do
67
+ unless `git branch` =~ /^\* master$/
68
+ puts "You must be on the master branch to release!"
69
+ exit!
70
+ end
71
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
72
+ sh "git tag v#{version}"
73
+ sh "git push origin master"
74
+ sh "git push origin v#{version}"
75
+ sh "gem push pkg/#{name}-#{version}.gem"
76
+ end
77
+
78
+ desc "Build #{gem_file} into the pkg directory"
79
+ task :build => :gemspec do
80
+ sh "mkdir -p pkg"
81
+ sh "gem build #{gemspec_file}"
82
+ sh "mv #{gem_file} pkg"
83
+ end
84
+
85
+ desc "Generate #{gemspec_file}"
86
+ task :gemspec => :validate do
87
+ # read spec file and split out manifest section
88
+ spec = File.read(gemspec_file)
89
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
90
+
91
+ # replace name version and date
92
+ replace_header(head, :name)
93
+ replace_header(head, :version)
94
+ replace_header(head, :date)
95
+ #comment this out if your rubyforge_project has a different name
96
+ replace_header(head, :rubyforge_project)
97
+
98
+ # determine file list from git ls-files
99
+ files = `git ls-files`.
100
+ split("\n").
101
+ sort.
102
+ reject { |file| file =~ /^\./ }.
103
+ reject { |file| file =~ /^(rdoc|pkg)/ }.
104
+ map { |file| " #{file}" }.
105
+ join("\n")
106
+
107
+ # piece file back together and write
108
+ manifest = " s.files = %w[\n#{files}\n ]\n"
109
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
110
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
111
+ puts "Updated #{gemspec_file}"
112
+ end
113
+
114
+ desc "Validate #{gemspec_file}"
115
+ task :validate do
116
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
117
+ unless libfiles.empty?
118
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
119
+ exit!
120
+ end
121
+ unless Dir['VERSION*'].empty?
122
+ puts "A `VERSION` file at root level violates Gem best practices."
123
+ exit!
124
+ end
125
+ end
@@ -0,0 +1,78 @@
1
+ # encoding: UTF-8
2
+
3
+ require "execjs"
4
+ require "multi_json"
5
+
6
+ class SweetJS
7
+ VERSION = "0.1.0"
8
+ REQUIRES = %w(underscore escodegen sweet)
9
+
10
+ Error = ExecJS::Error
11
+
12
+ def self.compile(source)
13
+ self.new.compile(source)
14
+ end
15
+
16
+ def context
17
+ @context ||= build_context
18
+ end
19
+
20
+ def build_context
21
+ source = (<<-JS)
22
+ var require = (function() {
23
+ var modules = {};
24
+ var require = function(module) {
25
+ return modules[module];
26
+ };
27
+ JS
28
+
29
+ REQUIRES.each do |file|
30
+ source << (<<-JS)
31
+
32
+ ////////////////////////////////////////////////////////////
33
+ // #{ file }.js START
34
+
35
+ modules["#{file}"] = function() {
36
+ var exports = {}, module = {};
37
+ module.exports = exports;
38
+
39
+ #{ read_source_file(file) }
40
+
41
+ return exports;
42
+ }.call({});
43
+
44
+ // #{ file }.js END
45
+ JS
46
+ end
47
+ source << (<<-JS)
48
+ return require;
49
+ }.call(this));
50
+ JS
51
+ ExecJS.compile(source)
52
+ end
53
+
54
+ def read_source_file(name)
55
+ File.open(File.expand_path("../sweetjs/#{name}.js", __FILE__), "r:UTF-8").read
56
+ end
57
+
58
+ def compile(source)
59
+ source = source.respond_to?(:read) ? source.read : source.to_s
60
+ js = []
61
+ js << "var sweet = require('sweet');"
62
+ js << "var escodegen = require('escodegen');"
63
+ js << "var source = #{json_encode(source)};"
64
+ js << "var result = escodegen.generate(sweet.parse(source));"
65
+ js << "return result;"
66
+ context.exec js.join("\n")
67
+ end
68
+
69
+ if MultiJson.respond_to? :dump
70
+ def json_encode(obj)
71
+ MultiJson.dump(obj)
72
+ end
73
+ else
74
+ def json_encode(obj)
75
+ MultiJson.encode(obj)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,1963 @@
1
+ /*
2
+ Copyright (C) 2012 Michael Ficarra <escodegen.copyright@michael.ficarra.me>
3
+ Copyright (C) 2012 Robert Gust-Bardon <donate@robert.gust-bardon.org>
4
+ Copyright (C) 2012 John Freeman <jfreeman08@gmail.com>
5
+ Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
6
+ Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
7
+ Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
8
+ Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
9
+ Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
10
+ Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
11
+ Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
12
+
13
+ Redistribution and use in source and binary forms, with or without
14
+ modification, are permitted provided that the following conditions are met:
15
+
16
+ * Redistributions of source code must retain the above copyright
17
+ notice, this list of conditions and the following disclaimer.
18
+ * Redistributions in binary form must reproduce the above copyright
19
+ notice, this list of conditions and the following disclaimer in the
20
+ documentation and/or other materials provided with the distribution.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
26
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+ */
33
+
34
+ /*jslint bitwise:true */
35
+ /*global escodegen:true, exports:true, generateStatement: true*/
36
+
37
+ (function (factory, global) {
38
+ 'use strict';
39
+
40
+ // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
41
+ // and plain browser loading,
42
+ if (typeof define === 'function' && define.amd) {
43
+ define(['exports'], function(exports) {
44
+ factory(exports, global);
45
+ });
46
+ } else if (typeof exports !== 'undefined') {
47
+ factory(exports, global);
48
+ } else {
49
+ factory((global.escodegen = {}), global);
50
+ }
51
+ }(function (exports, global) {
52
+ 'use strict';
53
+
54
+ var Syntax,
55
+ Precedence,
56
+ BinaryPrecedence,
57
+ Regex,
58
+ VisitorKeys,
59
+ VisitorOption,
60
+ SourceNode,
61
+ isArray,
62
+ base,
63
+ indent,
64
+ json,
65
+ renumber,
66
+ hexadecimal,
67
+ quotes,
68
+ escapeless,
69
+ newline,
70
+ space,
71
+ parentheses,
72
+ semicolons,
73
+ safeConcatenation,
74
+ extra,
75
+ parse,
76
+ sourceMap;
77
+
78
+ Syntax = {
79
+ AssignmentExpression: 'AssignmentExpression',
80
+ ArrayExpression: 'ArrayExpression',
81
+ BlockStatement: 'BlockStatement',
82
+ BinaryExpression: 'BinaryExpression',
83
+ BreakStatement: 'BreakStatement',
84
+ CallExpression: 'CallExpression',
85
+ CatchClause: 'CatchClause',
86
+ ConditionalExpression: 'ConditionalExpression',
87
+ ContinueStatement: 'ContinueStatement',
88
+ DoWhileStatement: 'DoWhileStatement',
89
+ DebuggerStatement: 'DebuggerStatement',
90
+ EmptyStatement: 'EmptyStatement',
91
+ ExpressionStatement: 'ExpressionStatement',
92
+ ForStatement: 'ForStatement',
93
+ ForInStatement: 'ForInStatement',
94
+ FunctionDeclaration: 'FunctionDeclaration',
95
+ FunctionExpression: 'FunctionExpression',
96
+ Identifier: 'Identifier',
97
+ IfStatement: 'IfStatement',
98
+ Literal: 'Literal',
99
+ LabeledStatement: 'LabeledStatement',
100
+ LogicalExpression: 'LogicalExpression',
101
+ MemberExpression: 'MemberExpression',
102
+ NewExpression: 'NewExpression',
103
+ ObjectExpression: 'ObjectExpression',
104
+ Program: 'Program',
105
+ Property: 'Property',
106
+ ReturnStatement: 'ReturnStatement',
107
+ SequenceExpression: 'SequenceExpression',
108
+ SwitchStatement: 'SwitchStatement',
109
+ SwitchCase: 'SwitchCase',
110
+ ThisExpression: 'ThisExpression',
111
+ ThrowStatement: 'ThrowStatement',
112
+ TryStatement: 'TryStatement',
113
+ UnaryExpression: 'UnaryExpression',
114
+ UpdateExpression: 'UpdateExpression',
115
+ VariableDeclaration: 'VariableDeclaration',
116
+ VariableDeclarator: 'VariableDeclarator',
117
+ WhileStatement: 'WhileStatement',
118
+ WithStatement: 'WithStatement'
119
+ };
120
+
121
+ Precedence = {
122
+ Sequence: 0,
123
+ Assignment: 1,
124
+ Conditional: 2,
125
+ LogicalOR: 3,
126
+ LogicalAND: 4,
127
+ BitwiseOR: 5,
128
+ BitwiseXOR: 6,
129
+ BitwiseAND: 7,
130
+ Equality: 8,
131
+ Relational: 9,
132
+ BitwiseSHIFT: 10,
133
+ Additive: 11,
134
+ Multiplicative: 12,
135
+ Unary: 13,
136
+ Postfix: 14,
137
+ Call: 15,
138
+ New: 16,
139
+ Member: 17,
140
+ Primary: 18
141
+ };
142
+
143
+ BinaryPrecedence = {
144
+ '||': Precedence.LogicalOR,
145
+ '&&': Precedence.LogicalAND,
146
+ '|': Precedence.BitwiseOR,
147
+ '^': Precedence.BitwiseXOR,
148
+ '&': Precedence.BitwiseAND,
149
+ '==': Precedence.Equality,
150
+ '!=': Precedence.Equality,
151
+ '===': Precedence.Equality,
152
+ '!==': Precedence.Equality,
153
+ '<': Precedence.Relational,
154
+ '>': Precedence.Relational,
155
+ '<=': Precedence.Relational,
156
+ '>=': Precedence.Relational,
157
+ 'in': Precedence.Relational,
158
+ 'instanceof': Precedence.Relational,
159
+ '<<': Precedence.BitwiseSHIFT,
160
+ '>>': Precedence.BitwiseSHIFT,
161
+ '>>>': Precedence.BitwiseSHIFT,
162
+ '+': Precedence.Additive,
163
+ '-': Precedence.Additive,
164
+ '*': Precedence.Multiplicative,
165
+ '%': Precedence.Multiplicative,
166
+ '/': Precedence.Multiplicative
167
+ };
168
+
169
+ Regex = {
170
+ NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]')
171
+ };
172
+
173
+ function getDefaultOptions() {
174
+ // default options
175
+ return {
176
+ indent: null,
177
+ base: null,
178
+ parse: null,
179
+ comment: false,
180
+ format: {
181
+ indent: {
182
+ style: ' ',
183
+ base: 0,
184
+ adjustMultilineComment: false
185
+ },
186
+ json: false,
187
+ renumber: false,
188
+ hexadecimal: false,
189
+ quotes: 'single',
190
+ escapeless: false,
191
+ compact: false,
192
+ parentheses: true,
193
+ semicolons: true,
194
+ safeConcatenation: false
195
+ },
196
+ sourceMap: null,
197
+ sourceMapWithCode: false
198
+ };
199
+ }
200
+
201
+ function stringToArray(str) {
202
+ var length = str.length,
203
+ result = [],
204
+ i;
205
+ for (i = 0; i < length; i += 1) {
206
+ result[i] = str.charAt(i);
207
+ }
208
+ return result;
209
+ }
210
+
211
+ function stringRepeat(str, num) {
212
+ var result = '';
213
+
214
+ for (num |= 0; num > 0; num >>>= 1, str += str) {
215
+ if (num & 1) {
216
+ result += str;
217
+ }
218
+ }
219
+
220
+ return result;
221
+ }
222
+
223
+ isArray = Array.isArray;
224
+ if (!isArray) {
225
+ isArray = function isArray(array) {
226
+ return Object.prototype.toString.call(array) === '[object Array]';
227
+ };
228
+ }
229
+
230
+ // Fallback for the non SourceMap environment
231
+ function SourceNodeMock(line, column, filename, chunk) {
232
+ var result = [];
233
+
234
+ function flatten(input) {
235
+ var i, iz;
236
+ if (isArray(input)) {
237
+ for (i = 0, iz = input.length; i < iz; ++i) {
238
+ flatten(input[i]);
239
+ }
240
+ } else if (input instanceof SourceNodeMock) {
241
+ result.push(input);
242
+ } else if (typeof input === 'string' && input) {
243
+ result.push(input);
244
+ }
245
+ }
246
+
247
+ flatten(chunk);
248
+ this.children = result;
249
+ }
250
+
251
+ SourceNodeMock.prototype.toString = function toString() {
252
+ var res = '', i, iz, node;
253
+ for (i = 0, iz = this.children.length; i < iz; ++i) {
254
+ node = this.children[i];
255
+ if (node instanceof SourceNodeMock) {
256
+ res += node.toString();
257
+ } else {
258
+ res += node;
259
+ }
260
+ }
261
+ return res;
262
+ };
263
+
264
+ SourceNodeMock.prototype.replaceRight = function replaceRight(pattern, replacement) {
265
+ var last = this.children[this.children.length - 1];
266
+ if (last instanceof SourceNodeMock) {
267
+ last.replaceRight(pattern, replacement);
268
+ } else if (typeof last === 'string') {
269
+ this.children[this.children.length - 1] = last.replace(pattern, replacement);
270
+ } else {
271
+ this.children.push(''.replace(pattern, replacement));
272
+ }
273
+ return this;
274
+ };
275
+
276
+ SourceNodeMock.prototype.join = function join(sep) {
277
+ var i, iz, result;
278
+ result = [];
279
+ iz = this.children.length;
280
+ if (iz > 0) {
281
+ for (i = 0, iz -= 1; i < iz; ++i) {
282
+ result.push(this.children[i], sep);
283
+ }
284
+ result.push(this.children[iz]);
285
+ this.children = result;
286
+ }
287
+ return this;
288
+ };
289
+
290
+ function endsWithLineTerminator(str) {
291
+ var ch = str.charAt(str.length - 1);
292
+ return ch === '\r' || ch === '\n';
293
+ }
294
+
295
+ function shallowCopy(obj) {
296
+ var ret = {}, key;
297
+ for (key in obj) {
298
+ if (obj.hasOwnProperty(key)) {
299
+ ret[key] = obj[key];
300
+ }
301
+ }
302
+ return ret;
303
+ }
304
+
305
+ function deepCopy(obj) {
306
+ var ret = {}, key, val;
307
+ for (key in obj) {
308
+ if (obj.hasOwnProperty(key)) {
309
+ val = obj[key];
310
+ if (typeof val === 'object' && val !== null) {
311
+ ret[key] = deepCopy(val);
312
+ } else {
313
+ ret[key] = val;
314
+ }
315
+ }
316
+ }
317
+ return ret;
318
+ }
319
+
320
+ function updateDeeply(target, override) {
321
+ var key, val;
322
+
323
+ function isHashObject(target) {
324
+ return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp);
325
+ }
326
+
327
+ for (key in override) {
328
+ if (override.hasOwnProperty(key)) {
329
+ val = override[key];
330
+ if (isHashObject(val)) {
331
+ if (isHashObject(target[key])) {
332
+ updateDeeply(target[key], val);
333
+ } else {
334
+ target[key] = updateDeeply({}, val);
335
+ }
336
+ } else {
337
+ target[key] = val;
338
+ }
339
+ }
340
+ }
341
+ return target;
342
+ }
343
+
344
+ function generateNumber(value) {
345
+ var result, point, temp, exponent, pos;
346
+
347
+ if (value !== value) {
348
+ throw new Error('Numeric literal whose value is NaN');
349
+ }
350
+ if (value < 0 || (value === 0 && 1 / value < 0)) {
351
+ throw new Error('Numeric literal whose value is negative');
352
+ }
353
+
354
+ if (value === 1 / 0) {
355
+ return json ? 'null' : renumber ? '1e400' : '1e+400';
356
+ }
357
+
358
+ result = '' + value;
359
+ if (!renumber || result.length < 3) {
360
+ return result;
361
+ }
362
+
363
+ point = result.indexOf('.');
364
+ if (!json && result.charAt(0) === '0' && point === 1) {
365
+ point = 0;
366
+ result = result.slice(1);
367
+ }
368
+ temp = result;
369
+ result = result.replace('e+', 'e');
370
+ exponent = 0;
371
+ if ((pos = temp.indexOf('e')) > 0) {
372
+ exponent = +temp.slice(pos + 1);
373
+ temp = temp.slice(0, pos);
374
+ }
375
+ if (point >= 0) {
376
+ exponent -= temp.length - point - 1;
377
+ temp = +(temp.slice(0, point) + temp.slice(point + 1)) + '';
378
+ }
379
+ pos = 0;
380
+ while (temp.charAt(temp.length + pos - 1) === '0') {
381
+ pos -= 1;
382
+ }
383
+ if (pos !== 0) {
384
+ exponent -= pos;
385
+ temp = temp.slice(0, pos);
386
+ }
387
+ if (exponent !== 0) {
388
+ temp += 'e' + exponent;
389
+ }
390
+ if ((temp.length < result.length ||
391
+ (hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length)) &&
392
+ +temp === value) {
393
+ result = temp;
394
+ }
395
+
396
+ return result;
397
+ }
398
+
399
+ function escapeAllowedCharacter(ch, next) {
400
+ var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\';
401
+
402
+ switch (ch) {
403
+ case '\b':
404
+ result += 'b';
405
+ break;
406
+ case '\f':
407
+ result += 'f';
408
+ break;
409
+ case '\t':
410
+ result += 't';
411
+ break;
412
+ default:
413
+ if (json || code > 0xff) {
414
+ result += 'u' + '0000'.slice(hex.length) + hex;
415
+ } else if (ch === '\u0000' && '0123456789'.indexOf(next) < 0) {
416
+ result += '0';
417
+ } else if (ch === '\v') {
418
+ result += 'v';
419
+ } else {
420
+ result += 'x' + '00'.slice(hex.length) + hex;
421
+ }
422
+ break;
423
+ }
424
+
425
+ return result;
426
+ }
427
+
428
+ function escapeDisallowedCharacter(ch) {
429
+ var result = '\\';
430
+ switch (ch) {
431
+ case '\\':
432
+ result += '\\';
433
+ break;
434
+ case '\n':
435
+ result += 'n';
436
+ break;
437
+ case '\r':
438
+ result += 'r';
439
+ break;
440
+ case '\u2028':
441
+ result += 'u2028';
442
+ break;
443
+ case '\u2029':
444
+ result += 'u2029';
445
+ break;
446
+ default:
447
+ throw new Error('Incorrectly classified character');
448
+ }
449
+
450
+ return result;
451
+ }
452
+
453
+ function escapeString(str) {
454
+ var result = '', i, len, ch, next, singleQuotes = 0, doubleQuotes = 0, single;
455
+
456
+ if (typeof str[0] === 'undefined') {
457
+ str = stringToArray(str);
458
+ }
459
+
460
+ for (i = 0, len = str.length; i < len; i += 1) {
461
+ ch = str[i];
462
+ if (ch === '\'') {
463
+ singleQuotes += 1;
464
+ } else if (ch === '"') {
465
+ doubleQuotes += 1;
466
+ } else if (ch === '/' && json) {
467
+ result += '\\';
468
+ } else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) {
469
+ result += escapeDisallowedCharacter(ch);
470
+ continue;
471
+ } else if ((json && ch < ' ') || !(json || escapeless || (ch >= ' ' && ch <= '~'))) {
472
+ result += escapeAllowedCharacter(ch, str[i + 1]);
473
+ continue;
474
+ }
475
+ result += ch;
476
+ }
477
+
478
+ single = !(quotes === 'double' || (quotes === 'auto' && doubleQuotes < singleQuotes));
479
+ str = result;
480
+ result = single ? '\'' : '"';
481
+
482
+ if (typeof str[0] === 'undefined') {
483
+ str = stringToArray(str);
484
+ }
485
+
486
+ for (i = 0, len = str.length; i < len; i += 1) {
487
+ ch = str[i];
488
+ if ((ch === '\'' && single) || (ch === '"' && !single)) {
489
+ result += '\\';
490
+ }
491
+ result += ch;
492
+ }
493
+
494
+ return result + (single ? '\'' : '"');
495
+ }
496
+
497
+ function isWhiteSpace(ch) {
498
+ return '\t\v\f \xa0'.indexOf(ch) >= 0 || (ch.charCodeAt(0) >= 0x1680 && '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff'.indexOf(ch) >= 0);
499
+ }
500
+
501
+ function isLineTerminator(ch) {
502
+ return '\n\r\u2028\u2029'.indexOf(ch) >= 0;
503
+ }
504
+
505
+ function isIdentifierPart(ch) {
506
+ return (ch === '$') || (ch === '_') || (ch === '\\') ||
507
+ (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
508
+ ((ch >= '0') && (ch <= '9')) ||
509
+ ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch));
510
+ }
511
+
512
+ function join(left, right) {
513
+ var leftSource = toSourceNode(left).toString(),
514
+ rightSource = toSourceNode(right).toString(),
515
+ leftChar = leftSource.charAt(leftSource.length - 1),
516
+ rightChar = rightSource.charAt(0);
517
+
518
+ if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) {
519
+ return [left, ' ', right];
520
+ } else if (isWhiteSpace(leftChar) || isLineTerminator(leftChar) || isWhiteSpace(rightChar) || isLineTerminator(rightChar)) {
521
+ return [left, right];
522
+ }
523
+ return [left, space, right];
524
+ }
525
+
526
+ function addIndent(stmt) {
527
+ return [base, stmt];
528
+ }
529
+
530
+ function withIndent(fn) {
531
+ var previousBase;
532
+ previousBase = base;
533
+ base += indent;
534
+ var result = fn.call(this, base);
535
+ base = previousBase;
536
+ return result;
537
+ }
538
+
539
+ function calculateSpaces(str) {
540
+ var i;
541
+ for (i = str.length - 1; i >= 0; i -= 1) {
542
+ if (isLineTerminator(str.charAt(i))) {
543
+ break;
544
+ }
545
+ }
546
+ return (str.length - 1) - i;
547
+ }
548
+
549
+ function toSourceNode(generated, node) {
550
+ if (node == null) {
551
+ if (generated instanceof SourceNode) {
552
+ return generated;
553
+ } else {
554
+ node = {};
555
+ }
556
+ }
557
+ if (node.loc == null) {
558
+ return new SourceNode(null, null, sourceMap, generated);
559
+ }
560
+ return new SourceNode(node.loc.start.line, node.loc.start.column, sourceMap, generated);
561
+ }
562
+
563
+ function adjustMultilineComment(value, specialBase) {
564
+ var array, i, len, line, j, ch, spaces, previousBase;
565
+
566
+ array = value.split(/\r\n|[\r\n]/);
567
+ spaces = Number.MAX_VALUE;
568
+
569
+ // first line doesn't have indentation
570
+ for (i = 1, len = array.length; i < len; i += 1) {
571
+ line = array[i];
572
+ j = 0;
573
+ while (j < line.length && isWhiteSpace(line[j])) {
574
+ j += 1;
575
+ }
576
+ if (spaces > j) {
577
+ spaces = j;
578
+ }
579
+ }
580
+
581
+ if (typeof specialBase !== 'undefined') {
582
+ // pattern like
583
+ // {
584
+ // var t = 20; /*
585
+ // * this is comment
586
+ // */
587
+ // }
588
+ previousBase = base;
589
+ if (array[1][spaces] === '*') {
590
+ specialBase += ' ';
591
+ }
592
+ base = specialBase;
593
+ } else {
594
+ if (spaces & 1) {
595
+ // /*
596
+ // *
597
+ // */
598
+ // If spaces are odd number, above pattern is considered.
599
+ // We waste 1 space.
600
+ spaces -= 1;
601
+ }
602
+ previousBase = base;
603
+ }
604
+
605
+ for (i = 1, len = array.length; i < len; i += 1) {
606
+ array[i] = toSourceNode(addIndent(array[i].slice(spaces))).join('');
607
+ }
608
+
609
+ base = previousBase;
610
+
611
+ return array.join('\n');
612
+ }
613
+
614
+ function generateComment(comment, specialBase) {
615
+ if (comment.type === 'Line') {
616
+ if (endsWithLineTerminator(comment.value)) {
617
+ return '//' + comment.value;
618
+ } else {
619
+ // Always use LineTerminator
620
+ return '//' + comment.value + '\n';
621
+ }
622
+ }
623
+ if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) {
624
+ return adjustMultilineComment('/*' + comment.value + '*/', specialBase);
625
+ }
626
+ return '/*' + comment.value + '*/';
627
+ }
628
+
629
+ function addCommentsToStatement(stmt, result) {
630
+ var i, len, comment, save, node, tailingToStatement, specialBase, fragment;
631
+
632
+ if (stmt.leadingComments && stmt.leadingComments.length > 0) {
633
+ save = result;
634
+
635
+ comment = stmt.leadingComments[0];
636
+ result = [];
637
+ if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) {
638
+ result.push('\n');
639
+ }
640
+ result.push(generateComment(comment));
641
+ if (!endsWithLineTerminator(toSourceNode(result).toString())) {
642
+ result.push('\n');
643
+ }
644
+
645
+ for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) {
646
+ comment = stmt.leadingComments[i];
647
+ fragment = [generateComment(comment)];
648
+ if (!endsWithLineTerminator(toSourceNode(fragment).toString())) {
649
+ fragment.push('\n');
650
+ }
651
+ result.push(addIndent(fragment));
652
+ }
653
+
654
+ result.push(addIndent(save));
655
+ }
656
+
657
+ if (stmt.trailingComments) {
658
+ tailingToStatement = !endsWithLineTerminator(toSourceNode(result).toString());
659
+ specialBase = stringRepeat(' ', calculateSpaces(toSourceNode([base, result, indent]).toString()));
660
+ for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) {
661
+ comment = stmt.trailingComments[i];
662
+ if (tailingToStatement) {
663
+ // We assume target like following script
664
+ //
665
+ // var t = 20; /**
666
+ // * This is comment of t
667
+ // */
668
+ if (i === 0) {
669
+ // first case
670
+ result.push(indent);
671
+ } else {
672
+ result.push(specialBase);
673
+ }
674
+ result.push(generateComment(comment, specialBase));
675
+ } else {
676
+ result.push(addIndent(generateComment(comment)));
677
+ }
678
+ if (i !== len - 1 && !endsWithLineTerminator(toSourceNode(result).toString())) {
679
+ result.push('\n');
680
+ }
681
+ }
682
+ }
683
+
684
+ return result;
685
+ }
686
+
687
+ function parenthesize(text, current, should) {
688
+ if (current < should) {
689
+ return ['(', text, ')'];
690
+ }
691
+ return text;
692
+ }
693
+
694
+ function maybeBlock(stmt, semicolonOptional) {
695
+ var result, noLeadingComment;
696
+
697
+ noLeadingComment = !extra.comment || !stmt.leadingComments;
698
+
699
+ if (stmt.type === Syntax.BlockStatement && noLeadingComment) {
700
+ return [space, generateStatement(stmt)];
701
+ }
702
+
703
+ if (stmt.type === Syntax.EmptyStatement && noLeadingComment) {
704
+ return ';';
705
+ }
706
+
707
+ withIndent(function () {
708
+ result = [newline, addIndent(generateStatement(stmt, { semicolonOptional: semicolonOptional }))];
709
+ });
710
+
711
+ return result;
712
+ }
713
+
714
+ function maybeBlockSuffix(stmt, result) {
715
+ var ends = endsWithLineTerminator(toSourceNode(result).toString());
716
+ if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !ends) {
717
+ return [result, space];
718
+ }
719
+ if (ends) {
720
+ return [result, base];
721
+ }
722
+ return [result, newline, base];
723
+ }
724
+
725
+ function generateFunctionBody(node) {
726
+ var result, i, len;
727
+ result = ['('];
728
+ for (i = 0, len = node.params.length; i < len; i += 1) {
729
+ result.push(node.params[i].name);
730
+ if (i + 1 < len) {
731
+ result.push(',' + space);
732
+ }
733
+ }
734
+ result.push(')', maybeBlock(node.body));
735
+ return result;
736
+ }
737
+
738
+ function generateExpression(expr, option) {
739
+ var result, precedence, currentPrecedence, i, len, raw, fragment, multiline, leftChar, leftSource, rightChar, rightSource, allowIn, allowCall, allowUnparenthesizedNew;
740
+
741
+ precedence = option.precedence;
742
+ allowIn = option.allowIn;
743
+ allowCall = option.allowCall;
744
+
745
+ switch (expr.type) {
746
+ case Syntax.SequenceExpression:
747
+ result = [];
748
+ allowIn |= (Precedence.Sequence < precedence);
749
+ for (i = 0, len = expr.expressions.length; i < len; i += 1) {
750
+ result.push(generateExpression(expr.expressions[i], {
751
+ precedence: Precedence.Assignment,
752
+ allowIn: allowIn,
753
+ allowCall: true
754
+ }));
755
+ if (i + 1 < len) {
756
+ result.push(',' + space);
757
+ }
758
+ }
759
+ result = parenthesize(result, Precedence.Sequence, precedence);
760
+ break;
761
+
762
+ case Syntax.AssignmentExpression:
763
+ allowIn |= (Precedence.Assignment < precedence);
764
+ result = parenthesize(
765
+ [
766
+ generateExpression(expr.left, {
767
+ precedence: Precedence.Call,
768
+ allowIn: allowIn,
769
+ allowCall: true
770
+ }),
771
+ space + expr.operator + space,
772
+ generateExpression(expr.right, {
773
+ precedence: Precedence.Assignment,
774
+ allowIn: allowIn,
775
+ allowCall: true
776
+ })
777
+ ],
778
+ Precedence.Assignment,
779
+ precedence
780
+ );
781
+ break;
782
+
783
+ case Syntax.ConditionalExpression:
784
+ allowIn |= (Precedence.Conditional < precedence);
785
+ result = parenthesize(
786
+ [
787
+ generateExpression(expr.test, {
788
+ precedence: Precedence.LogicalOR,
789
+ allowIn: allowIn,
790
+ allowCall: true
791
+ }),
792
+ space + '?' + space,
793
+ generateExpression(expr.consequent, {
794
+ precedence: Precedence.Assignment,
795
+ allowIn: allowIn,
796
+ allowCall: true
797
+ }),
798
+ space + ':' + space,
799
+ generateExpression(expr.alternate, {
800
+ precedence: Precedence.Assignment,
801
+ allowIn: allowIn,
802
+ allowCall: true
803
+ })
804
+ ],
805
+ Precedence.Conditional,
806
+ precedence
807
+ );
808
+ break;
809
+
810
+ case Syntax.LogicalExpression:
811
+ case Syntax.BinaryExpression:
812
+ currentPrecedence = BinaryPrecedence[expr.operator];
813
+
814
+ allowIn |= (currentPrecedence < precedence);
815
+
816
+ result = join(
817
+ generateExpression(expr.left, {
818
+ precedence: currentPrecedence,
819
+ allowIn: allowIn,
820
+ allowCall: true
821
+ }),
822
+ expr.operator
823
+ );
824
+
825
+ fragment = generateExpression(expr.right, {
826
+ precedence: currentPrecedence + 1,
827
+ allowIn: allowIn,
828
+ allowCall: true
829
+ });
830
+
831
+ if (expr.operator === '/' && fragment.toString().charAt(0) === '/') {
832
+ // If '/' concats with '/', it is interpreted as comment start
833
+ result.push(' ', fragment);
834
+ } else {
835
+ result = join(result, fragment);
836
+ }
837
+
838
+ if (expr.operator === 'in' && !allowIn) {
839
+ result = ['(', result, ')'];
840
+ } else {
841
+ result = parenthesize(result, currentPrecedence, precedence);
842
+ }
843
+
844
+ break;
845
+
846
+ case Syntax.CallExpression:
847
+ result = [generateExpression(expr.callee, {
848
+ precedence: Precedence.Call,
849
+ allowIn: true,
850
+ allowCall: true,
851
+ allowUnparenthesizedNew: false
852
+ })];
853
+
854
+ result.push('(');
855
+ for (i = 0, len = expr['arguments'].length; i < len; i += 1) {
856
+ result.push(generateExpression(expr['arguments'][i], {
857
+ precedence: Precedence.Assignment,
858
+ allowIn: true,
859
+ allowCall: true
860
+ }));
861
+ if (i + 1 < len) {
862
+ result.push(',' + space);
863
+ }
864
+ }
865
+ result.push(')');
866
+
867
+ if (!allowCall) {
868
+ result = ['(', result, ')'];
869
+ } else {
870
+ result = parenthesize(result, Precedence.Call, precedence);
871
+ }
872
+ break;
873
+
874
+ case Syntax.NewExpression:
875
+ len = expr['arguments'].length;
876
+ allowUnparenthesizedNew = option.allowUnparenthesizedNew === undefined || option.allowUnparenthesizedNew;
877
+
878
+ result = join(
879
+ 'new',
880
+ generateExpression(expr.callee, {
881
+ precedence: Precedence.New,
882
+ allowIn: true,
883
+ allowCall: false,
884
+ allowUnparenthesizedNew: allowUnparenthesizedNew && !parentheses && len === 0
885
+ })
886
+ );
887
+
888
+ if (!allowUnparenthesizedNew || parentheses || len > 0) {
889
+ result.push('(');
890
+ for (i = 0; i < len; i += 1) {
891
+ result.push(generateExpression(expr['arguments'][i], {
892
+ precedence: Precedence.Assignment,
893
+ allowIn: true,
894
+ allowCall: true
895
+ }));
896
+ if (i + 1 < len) {
897
+ result.push(',' + space);
898
+ }
899
+ }
900
+ result.push(')');
901
+ }
902
+
903
+ result = parenthesize(result, Precedence.New, precedence);
904
+ break;
905
+
906
+ case Syntax.MemberExpression:
907
+ result = [generateExpression(expr.object, {
908
+ precedence: Precedence.Call,
909
+ allowIn: true,
910
+ allowCall: allowCall,
911
+ allowUnparenthesizedNew: false
912
+ })];
913
+
914
+ if (expr.computed) {
915
+ result.push('[', generateExpression(expr.property, {
916
+ precedence: Precedence.Sequence,
917
+ allowIn: true,
918
+ allowCall: allowCall
919
+ }), ']');
920
+ } else {
921
+ if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
922
+ if (result.indexOf('.') < 0) {
923
+ if (!/[eExX]/.test(result) && !(result.length >= 2 && result[0] === '0')) {
924
+ result.push('.');
925
+ }
926
+ }
927
+ }
928
+ result.push('.' + expr.property.name);
929
+ }
930
+
931
+ result = parenthesize(result, Precedence.Member, precedence);
932
+ break;
933
+
934
+ case Syntax.UnaryExpression:
935
+ fragment = generateExpression(expr.argument, {
936
+ precedence: Precedence.Unary,
937
+ allowIn: true,
938
+ allowCall: true
939
+ });
940
+
941
+ if (space === '') {
942
+ result = join(expr.operator, fragment);
943
+ } else {
944
+ result = [expr.operator];
945
+ if (expr.operator.length > 2) {
946
+ // delete, void, typeof
947
+ // get `typeof []`, not `typeof[]`
948
+ result = join(result, fragment);
949
+ } else {
950
+ // Prevent inserting spaces between operator and argument if it is unnecessary
951
+ // like, `!cond`
952
+ leftSource = toSourceNode(result).toString();
953
+ leftChar = leftSource.charAt(leftSource.length - 1);
954
+ rightChar = fragment.toString().charAt(0);
955
+
956
+ if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) {
957
+ result.push(' ', fragment);
958
+ } else {
959
+ result.push(fragment);
960
+ }
961
+ }
962
+ }
963
+ result = parenthesize(result, Precedence.Unary, precedence);
964
+ break;
965
+
966
+ case Syntax.UpdateExpression:
967
+ if (expr.prefix) {
968
+ result = parenthesize(
969
+ [
970
+ expr.operator,
971
+ generateExpression(expr.argument, {
972
+ precedence: Precedence.Unary,
973
+ allowIn: true,
974
+ allowCall: true
975
+ })
976
+ ],
977
+ Precedence.Unary,
978
+ precedence
979
+ );
980
+ } else {
981
+ result = parenthesize(
982
+ [
983
+ generateExpression(expr.argument, {
984
+ precedence: Precedence.Postfix,
985
+ allowIn: true,
986
+ allowCall: true
987
+ }),
988
+ expr.operator
989
+ ],
990
+ Precedence.Postfix,
991
+ precedence
992
+ );
993
+ }
994
+ break;
995
+
996
+ case Syntax.FunctionExpression:
997
+ result = 'function';
998
+ if (expr.id) {
999
+ result += ' ' + expr.id.name;
1000
+ } else {
1001
+ result += space;
1002
+ }
1003
+ result = [result, generateFunctionBody(expr)];
1004
+ break;
1005
+
1006
+ case Syntax.ArrayExpression:
1007
+ if (!expr.elements.length) {
1008
+ result = '[]';
1009
+ break;
1010
+ }
1011
+ multiline = expr.elements.length > 1;
1012
+ result = ['[', multiline ? newline : ''];
1013
+ withIndent(function (indent) {
1014
+ for (i = 0, len = expr.elements.length; i < len; i += 1) {
1015
+ if (!expr.elements[i]) {
1016
+ if(multiline) {
1017
+ result.push(indent);
1018
+ }
1019
+ if (i + 1 === len) {
1020
+ result.push(',');
1021
+ }
1022
+ } else {
1023
+ result.push(multiline ? indent: '', generateExpression(expr.elements[i], {
1024
+ precedence: Precedence.Assignment,
1025
+ allowIn: true,
1026
+ allowCall: true
1027
+ }));
1028
+ }
1029
+ if (i + 1 < len) {
1030
+ result.push(',' + (multiline ? newline : space));
1031
+ }
1032
+ }
1033
+ });
1034
+ if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) {
1035
+ result.push(newline);
1036
+ }
1037
+ result.push(multiline ? base : '', ']');
1038
+ break;
1039
+
1040
+ case Syntax.Property:
1041
+ if (expr.kind === 'get' || expr.kind === 'set') {
1042
+ result = [
1043
+ expr.kind + ' ',
1044
+ generateExpression(expr.key, {
1045
+ precedence: Precedence.Sequence,
1046
+ allowIn: true,
1047
+ allowCall: true
1048
+ }),
1049
+ generateFunctionBody(expr.value)
1050
+ ];
1051
+ } else {
1052
+ result = [
1053
+ generateExpression(expr.key, {
1054
+ precedence: Precedence.Sequence,
1055
+ allowIn: true,
1056
+ allowCall: true
1057
+ }),
1058
+ ':' + space,
1059
+ generateExpression(expr.value, {
1060
+ precedence: Precedence.Assignment,
1061
+ allowIn: true,
1062
+ allowCall: true
1063
+ })
1064
+ ];
1065
+ }
1066
+ break;
1067
+
1068
+ case Syntax.ObjectExpression:
1069
+ if (!expr.properties.length) {
1070
+ result = '{}';
1071
+ break;
1072
+ }
1073
+ multiline = expr.properties.length > 1;
1074
+ result = ['{', multiline ? newline : ''];
1075
+
1076
+ withIndent(function (indent) {
1077
+ for (i = 0, len = expr.properties.length; i < len; i += 1) {
1078
+ result.push(multiline ? indent : '', generateExpression(expr.properties[i], {
1079
+ precedence: Precedence.Sequence,
1080
+ allowIn: true,
1081
+ allowCall: true
1082
+ }));
1083
+ if (i + 1 < len) {
1084
+ result.push(',' + (multiline ? newline : space));
1085
+ }
1086
+ }
1087
+ });
1088
+
1089
+ if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) {
1090
+ result.push(newline);
1091
+ }
1092
+ result.push(multiline ? base : '', '}');
1093
+ break;
1094
+
1095
+ case Syntax.ThisExpression:
1096
+ result = 'this';
1097
+ break;
1098
+
1099
+ case Syntax.Identifier:
1100
+ result = expr.name;
1101
+ break;
1102
+
1103
+ case Syntax.Literal:
1104
+ if (expr.hasOwnProperty('raw') && parse) {
1105
+ try {
1106
+ raw = parse(expr.raw).body[0].expression;
1107
+ if (raw.type === Syntax.Literal) {
1108
+ if (raw.value === expr.value) {
1109
+ result = expr.raw;
1110
+ break;
1111
+ }
1112
+ }
1113
+ } catch (e) {
1114
+ // not use raw property
1115
+ }
1116
+ }
1117
+
1118
+ if (expr.value === null) {
1119
+ result = 'null';
1120
+ break;
1121
+ }
1122
+
1123
+ if (typeof expr.value === 'string') {
1124
+ result = escapeString(expr.value);
1125
+ break;
1126
+ }
1127
+
1128
+ if (typeof expr.value === 'number') {
1129
+ result = generateNumber(expr.value);
1130
+ break;
1131
+ }
1132
+
1133
+ result = expr.value.toString();
1134
+ break;
1135
+
1136
+ default:
1137
+ throw new Error('Unknown expression type: ' + expr.type);
1138
+ }
1139
+
1140
+ return toSourceNode(result, expr);
1141
+ }
1142
+
1143
+ function generateStatement(stmt, option) {
1144
+ var i, len, result, node, allowIn, fragment, semicolon;
1145
+
1146
+ allowIn = true;
1147
+ semicolon = ';';
1148
+ if (option) {
1149
+ allowIn = option.allowIn === undefined || option.allowIn;
1150
+ if (!semicolons && option.semicolonOptional === true) {
1151
+ semicolon = '';
1152
+ }
1153
+ }
1154
+
1155
+ switch (stmt.type) {
1156
+ case Syntax.BlockStatement:
1157
+ result = ['{', newline];
1158
+
1159
+ withIndent(function () {
1160
+ for (i = 0, len = stmt.body.length; i < len; i += 1) {
1161
+ fragment = addIndent(generateStatement(stmt.body[i], {semicolonOptional: i === len - 1}));
1162
+ result.push(fragment);
1163
+ if (!endsWithLineTerminator(toSourceNode(fragment).toString())) {
1164
+ result.push(newline);
1165
+ }
1166
+ }
1167
+ });
1168
+
1169
+ result.push(addIndent('}'));
1170
+ break;
1171
+
1172
+ case Syntax.BreakStatement:
1173
+ if (stmt.label) {
1174
+ result = 'break ' + stmt.label.name + semicolon;
1175
+ } else {
1176
+ result = 'break' + semicolon;
1177
+ }
1178
+ break;
1179
+
1180
+ case Syntax.ContinueStatement:
1181
+ if (stmt.label) {
1182
+ result = 'continue ' + stmt.label.name + semicolon;
1183
+ } else {
1184
+ result = 'continue' + semicolon;
1185
+ }
1186
+ break;
1187
+
1188
+ case Syntax.DoWhileStatement:
1189
+ // Because `do 42 while (cond)` is Syntax Error. We need semicolon.
1190
+ result = join('do', maybeBlock(stmt.body));
1191
+ result = maybeBlockSuffix(stmt.body, result);
1192
+ result = join(result, [
1193
+ 'while' + space + '(',
1194
+ generateExpression(stmt.test, {
1195
+ precedence: Precedence.Sequence,
1196
+ allowIn: true,
1197
+ allowCall: true
1198
+ }),
1199
+ ')' + semicolon
1200
+ ]);
1201
+ break;
1202
+
1203
+ case Syntax.CatchClause:
1204
+ withIndent(function () {
1205
+ result = [
1206
+ 'catch' + space + '(',
1207
+ generateExpression(stmt.param, {
1208
+ precedence: Precedence.Sequence,
1209
+ allowIn: true,
1210
+ allowCall: true
1211
+ }),
1212
+ ')'
1213
+ ];
1214
+ });
1215
+ result.push(maybeBlock(stmt.body));
1216
+ break;
1217
+
1218
+ case Syntax.DebuggerStatement:
1219
+ result = 'debugger' + semicolon;
1220
+ break;
1221
+
1222
+ case Syntax.EmptyStatement:
1223
+ result = ';';
1224
+ break;
1225
+
1226
+ case Syntax.ExpressionStatement:
1227
+ result = [generateExpression(stmt.expression, {
1228
+ precedence: Precedence.Sequence,
1229
+ allowIn: true,
1230
+ allowCall: true
1231
+ })];
1232
+ // 12.4 '{', 'function' is not allowed in this position.
1233
+ // wrap expression with parentheses
1234
+ if (result.toString().charAt(0) === '{' || (result.toString().slice(0, 8) === 'function' && " (".indexOf(result.toString().charAt(8)) >= 0)) {
1235
+ result = ['(', result, ')' + semicolon];
1236
+ } else {
1237
+ result.push(semicolon);
1238
+ }
1239
+ break;
1240
+
1241
+ case Syntax.VariableDeclarator:
1242
+ if (stmt.init) {
1243
+ result = [
1244
+ stmt.id.name + space + '=' + space,
1245
+ generateExpression(stmt.init, {
1246
+ precedence: Precedence.Assignment,
1247
+ allowIn: allowIn,
1248
+ allowCall: true
1249
+ })
1250
+ ];
1251
+ } else {
1252
+ result = stmt.id.name;
1253
+ }
1254
+ break;
1255
+
1256
+ case Syntax.VariableDeclaration:
1257
+ result = [stmt.kind];
1258
+ // special path for
1259
+ // var x = function () {
1260
+ // };
1261
+ if (stmt.declarations.length === 1 && stmt.declarations[0].init &&
1262
+ stmt.declarations[0].init.type === Syntax.FunctionExpression) {
1263
+ result.push(' ', generateStatement(stmt.declarations[0], {
1264
+ allowIn: allowIn
1265
+ }));
1266
+ } else {
1267
+ // VariableDeclarator is typed as Statement,
1268
+ // but joined with comma (not LineTerminator).
1269
+ // So if comment is attached to target node, we should specialize.
1270
+ withIndent(function () {
1271
+ node = stmt.declarations[0];
1272
+ if (extra.comment && node.leadingComments) {
1273
+ result.push('\n', addIndent(generateStatement(node, {
1274
+ allowIn: allowIn
1275
+ })));
1276
+ } else {
1277
+ result.push(' ', generateStatement(node, {
1278
+ allowIn: allowIn
1279
+ }));
1280
+ }
1281
+
1282
+ for (i = 1, len = stmt.declarations.length; i < len; i += 1) {
1283
+ node = stmt.declarations[i];
1284
+ if (extra.comment && node.leadingComments) {
1285
+ result.push(',' + newline, addIndent(generateStatement(node, {
1286
+ allowIn: allowIn
1287
+ })));
1288
+ } else {
1289
+ result.push(',' + space, generateStatement(node, {
1290
+ allowIn: allowIn
1291
+ }));
1292
+ }
1293
+ }
1294
+ });
1295
+ }
1296
+ result.push(semicolon);
1297
+ break;
1298
+
1299
+ case Syntax.ThrowStatement:
1300
+ result = [join(
1301
+ 'throw',
1302
+ generateExpression(stmt.argument, {
1303
+ precedence: Precedence.Sequence,
1304
+ allowIn: true,
1305
+ allowCall: true
1306
+ })
1307
+ ), semicolon];
1308
+ break;
1309
+
1310
+ case Syntax.TryStatement:
1311
+ result = ['try', maybeBlock(stmt.block)];
1312
+ result = maybeBlockSuffix(stmt.block, result);
1313
+ for (i = 0, len = stmt.handlers.length; i < len; i += 1) {
1314
+ result = join(result, generateStatement(stmt.handlers[i]));
1315
+ if (stmt.finalizer || i + 1 !== len) {
1316
+ result = maybeBlockSuffix(stmt.handlers[i].body, result);
1317
+ }
1318
+ }
1319
+ if (stmt.finalizer) {
1320
+ result = join(result, ['finally', maybeBlock(stmt.finalizer)]);
1321
+ }
1322
+ break;
1323
+
1324
+ case Syntax.SwitchStatement:
1325
+ withIndent(function () {
1326
+ result = [
1327
+ 'switch' + space + '(',
1328
+ generateExpression(stmt.discriminant, {
1329
+ precedence: Precedence.Sequence,
1330
+ allowIn: true,
1331
+ allowCall: true
1332
+ }),
1333
+ ')' + space + '{' + newline
1334
+ ];
1335
+ });
1336
+ if (stmt.cases) {
1337
+ for (i = 0, len = stmt.cases.length; i < len; i += 1) {
1338
+ fragment = addIndent(generateStatement(stmt.cases[i], {semicolonOptional: i === len - 1}));
1339
+ result.push(fragment);
1340
+ if (!endsWithLineTerminator(toSourceNode(fragment).toString())) {
1341
+ result.push(newline);
1342
+ }
1343
+ }
1344
+ }
1345
+ result.push(addIndent('}'));
1346
+ break;
1347
+
1348
+ case Syntax.SwitchCase:
1349
+ withIndent(function () {
1350
+ if (stmt.test) {
1351
+ result = [
1352
+ join('case', generateExpression(stmt.test, {
1353
+ precedence: Precedence.Sequence,
1354
+ allowIn: true,
1355
+ allowCall: true
1356
+ })),
1357
+ ':'
1358
+ ];
1359
+ } else {
1360
+ result = ['default:'];
1361
+ }
1362
+
1363
+ i = 0;
1364
+ len = stmt.consequent.length;
1365
+ if (len && stmt.consequent[0].type === Syntax.BlockStatement) {
1366
+ fragment = maybeBlock(stmt.consequent[0]);
1367
+ result.push(fragment);
1368
+ i = 1;
1369
+ }
1370
+
1371
+ if (i !== len && !endsWithLineTerminator(toSourceNode(result).toString())) {
1372
+ result.push(newline);
1373
+ }
1374
+
1375
+ for (; i < len; i += 1) {
1376
+ fragment = addIndent(generateStatement(stmt.consequent[i], {semicolonOptional: i === len - 1 && semicolon === ''}));
1377
+ result.push(fragment);
1378
+ if (i + 1 !== len && !endsWithLineTerminator(toSourceNode(fragment).toString())) {
1379
+ result.push(newline);
1380
+ }
1381
+ }
1382
+ });
1383
+ break;
1384
+
1385
+ case Syntax.IfStatement:
1386
+ withIndent(function () {
1387
+ result = [
1388
+ 'if'+ space + '(',
1389
+ generateExpression(stmt.test, {
1390
+ precedence: Precedence.Sequence,
1391
+ allowIn: true,
1392
+ allowCall: true
1393
+ }),
1394
+ ')'
1395
+ ];
1396
+ });
1397
+ if (stmt.alternate) {
1398
+ result.push(maybeBlock(stmt.consequent));
1399
+ result = maybeBlockSuffix(stmt.consequent, result);
1400
+ if (stmt.alternate.type === Syntax.IfStatement) {
1401
+ result = join(result, ['else ', generateStatement(stmt.alternate, {semicolonOptional: semicolon === ''})]);
1402
+ } else {
1403
+ result = join(result, join('else', maybeBlock(stmt.alternate, semicolon === '')));
1404
+ }
1405
+ } else {
1406
+ result.push(maybeBlock(stmt.consequent, semicolon === ''));
1407
+ }
1408
+ break;
1409
+
1410
+ case Syntax.ForStatement:
1411
+ withIndent(function () {
1412
+ result = ['for' + space + '('];
1413
+ if (stmt.init) {
1414
+ if (stmt.init.type === Syntax.VariableDeclaration) {
1415
+ result.push(generateStatement(stmt.init, {allowIn: false}));
1416
+ } else {
1417
+ result.push(generateExpression(stmt.init, {
1418
+ precedence: Precedence.Sequence,
1419
+ allowIn: false,
1420
+ allowCall: true
1421
+ }), ';');
1422
+ }
1423
+ } else {
1424
+ result.push(';');
1425
+ }
1426
+
1427
+ if (stmt.test) {
1428
+ result.push(space, generateExpression(stmt.test, {
1429
+ precedence: Precedence.Sequence,
1430
+ allowIn: true,
1431
+ allowCall: true
1432
+ }), ';');
1433
+ } else {
1434
+ result.push(';');
1435
+ }
1436
+
1437
+ if (stmt.update) {
1438
+ result.push(space, generateExpression(stmt.update, {
1439
+ precedence: Precedence.Sequence,
1440
+ allowIn: true,
1441
+ allowCall: true
1442
+ }), ')');
1443
+ } else {
1444
+ result.push(')');
1445
+ }
1446
+ });
1447
+
1448
+ result.push(maybeBlock(stmt.body, semicolon === ''));
1449
+ break;
1450
+
1451
+ case Syntax.ForInStatement:
1452
+ result = ['for' + space + '('];
1453
+ withIndent(function () {
1454
+ if (stmt.left.type === Syntax.VariableDeclaration) {
1455
+ withIndent(function () {
1456
+ result.push(stmt.left.kind + ' ', generateStatement(stmt.left.declarations[0], {
1457
+ allowIn: false
1458
+ }));
1459
+ });
1460
+ } else {
1461
+ result.push(generateExpression(stmt.left, {
1462
+ precedence: Precedence.Call,
1463
+ allowIn: true,
1464
+ allowCall: true
1465
+ }));
1466
+ }
1467
+
1468
+ result = join(result, 'in');
1469
+ result = [join(
1470
+ result,
1471
+ generateExpression(stmt.right, {
1472
+ precedence: Precedence.Sequence,
1473
+ allowIn: true,
1474
+ allowCall: true
1475
+ })
1476
+ ), ')'];
1477
+ });
1478
+ result.push(maybeBlock(stmt.body, semicolon === ''));
1479
+ break;
1480
+
1481
+ case Syntax.LabeledStatement:
1482
+ result = [stmt.label.name + ':', maybeBlock(stmt.body, semicolon === '')];
1483
+ break;
1484
+
1485
+ case Syntax.Program:
1486
+ len = stmt.body.length;
1487
+ result = [safeConcatenation && len > 0 ? '\n' : ''];
1488
+ for (i = 0; i < len; i += 1) {
1489
+ fragment = addIndent(generateStatement(stmt.body[i], {semicolonOptional: !safeConcatenation && i === len - 1}));
1490
+ result.push(fragment);
1491
+ if (i + 1 < len && !endsWithLineTerminator(toSourceNode(fragment).toString())) {
1492
+ result.push(newline);
1493
+ }
1494
+ }
1495
+ break;
1496
+
1497
+ case Syntax.FunctionDeclaration:
1498
+ result = ['function ' + stmt.id.name, generateFunctionBody(stmt)];
1499
+ break;
1500
+
1501
+ case Syntax.ReturnStatement:
1502
+ if (stmt.argument) {
1503
+ result = [join(
1504
+ 'return',
1505
+ generateExpression(stmt.argument, {
1506
+ precedence: Precedence.Sequence,
1507
+ allowIn: true,
1508
+ allowCall: true
1509
+ })
1510
+ ), semicolon];
1511
+ } else {
1512
+ result = ['return' + semicolon];
1513
+ }
1514
+ break;
1515
+
1516
+ case Syntax.WhileStatement:
1517
+ withIndent(function () {
1518
+ result = [
1519
+ 'while' + space + '(',
1520
+ generateExpression(stmt.test, {
1521
+ precedence: Precedence.Sequence,
1522
+ allowIn: true,
1523
+ allowCall: true
1524
+ }),
1525
+ ')'
1526
+ ];
1527
+ });
1528
+ result.push(maybeBlock(stmt.body, semicolon === ''));
1529
+ break;
1530
+
1531
+ case Syntax.WithStatement:
1532
+ withIndent(function () {
1533
+ result = [
1534
+ 'with' + space + '(',
1535
+ generateExpression(stmt.object, {
1536
+ precedence: Precedence.Sequence,
1537
+ allowIn: true,
1538
+ allowCall: true
1539
+ }),
1540
+ ')'
1541
+ ];
1542
+ });
1543
+ result.push(maybeBlock(stmt.body, semicolon === ''));
1544
+ break;
1545
+
1546
+ default:
1547
+ throw new Error('Unknown statement type: ' + stmt.type);
1548
+ }
1549
+
1550
+ // Attach comments
1551
+
1552
+ if (extra.comment) {
1553
+ result = addCommentsToStatement(stmt, result);
1554
+ }
1555
+
1556
+ var fragment = toSourceNode(result).toString();
1557
+ if (stmt.type === Syntax.Program && !safeConcatenation && newline === '' && fragment.charAt(fragment.length - 1) === '\n') {
1558
+ result = toSourceNode(result).replaceRight(/\s+$/, '');
1559
+ }
1560
+
1561
+ return toSourceNode(result, stmt);
1562
+ }
1563
+
1564
+ function generate(node, options) {
1565
+ var defaultOptions = getDefaultOptions(), result, pair;
1566
+
1567
+ if (options != null) {
1568
+ // Obsolete options
1569
+ //
1570
+ // `options.indent`
1571
+ // `options.base`
1572
+ //
1573
+ // Instead of them, we can use `option.format.indent`.
1574
+ if (typeof options.indent === 'string') {
1575
+ defaultOptions.format.indent.style = options.indent;
1576
+ }
1577
+ if (typeof options.base === 'number') {
1578
+ defaultOptions.format.indent.base = options.base;
1579
+ }
1580
+ options = updateDeeply(defaultOptions, options);
1581
+ indent = options.format.indent.style;
1582
+ if (typeof options.base === 'string') {
1583
+ base = options.base;
1584
+ } else {
1585
+ base = stringRepeat(indent, options.format.indent.base);
1586
+ }
1587
+ } else {
1588
+ options = defaultOptions;
1589
+ indent = options.format.indent.style;
1590
+ base = stringRepeat(indent, options.format.indent.base);
1591
+ }
1592
+ json = options.format.json;
1593
+ renumber = options.format.renumber;
1594
+ hexadecimal = json ? false : options.format.hexadecimal;
1595
+ quotes = json ? 'double' : options.format.quotes;
1596
+ escapeless = options.format.escapeless;
1597
+ if (options.format.compact) {
1598
+ newline = space = indent = base = '';
1599
+ } else {
1600
+ newline = '\n';
1601
+ space = ' ';
1602
+ }
1603
+ parentheses = options.format.parentheses;
1604
+ semicolons = options.format.semicolons;
1605
+ safeConcatenation = options.format.safeConcatenation;
1606
+ parse = json ? null : options.parse;
1607
+ sourceMap = options.sourceMap;
1608
+ extra = options;
1609
+
1610
+ if (sourceMap) {
1611
+ if (typeof process !== 'undefined') {
1612
+ // We assume environment is node.js
1613
+ SourceNode = require('source-map').SourceNode;
1614
+ } else {
1615
+ SourceNode = global.sourceMap.SourceNode;
1616
+ }
1617
+ } else {
1618
+ SourceNode = SourceNodeMock;
1619
+ }
1620
+
1621
+ switch (node.type) {
1622
+ case Syntax.BlockStatement:
1623
+ case Syntax.BreakStatement:
1624
+ case Syntax.CatchClause:
1625
+ case Syntax.ContinueStatement:
1626
+ case Syntax.DoWhileStatement:
1627
+ case Syntax.DebuggerStatement:
1628
+ case Syntax.EmptyStatement:
1629
+ case Syntax.ExpressionStatement:
1630
+ case Syntax.ForStatement:
1631
+ case Syntax.ForInStatement:
1632
+ case Syntax.FunctionDeclaration:
1633
+ case Syntax.IfStatement:
1634
+ case Syntax.LabeledStatement:
1635
+ case Syntax.Program:
1636
+ case Syntax.ReturnStatement:
1637
+ case Syntax.SwitchStatement:
1638
+ case Syntax.SwitchCase:
1639
+ case Syntax.ThrowStatement:
1640
+ case Syntax.TryStatement:
1641
+ case Syntax.VariableDeclaration:
1642
+ case Syntax.VariableDeclarator:
1643
+ case Syntax.WhileStatement:
1644
+ case Syntax.WithStatement:
1645
+ result = generateStatement(node);
1646
+ break;
1647
+
1648
+ case Syntax.AssignmentExpression:
1649
+ case Syntax.ArrayExpression:
1650
+ case Syntax.BinaryExpression:
1651
+ case Syntax.CallExpression:
1652
+ case Syntax.ConditionalExpression:
1653
+ case Syntax.FunctionExpression:
1654
+ case Syntax.Identifier:
1655
+ case Syntax.Literal:
1656
+ case Syntax.LogicalExpression:
1657
+ case Syntax.MemberExpression:
1658
+ case Syntax.NewExpression:
1659
+ case Syntax.ObjectExpression:
1660
+ case Syntax.Property:
1661
+ case Syntax.SequenceExpression:
1662
+ case Syntax.ThisExpression:
1663
+ case Syntax.UnaryExpression:
1664
+ case Syntax.UpdateExpression:
1665
+ result = generateExpression(node, {
1666
+ precedence: Precedence.Sequence,
1667
+ allowIn: true,
1668
+ allowCall: true
1669
+ });
1670
+ break;
1671
+
1672
+ default:
1673
+ throw new Error('Unknown node type: ' + node.type);
1674
+ }
1675
+
1676
+ if (!sourceMap) {
1677
+ return result.toString();
1678
+ }
1679
+
1680
+ pair = result.toStringWithSourceMap({file: options.sourceMap});
1681
+
1682
+ if (options.sourceMapWithCode) {
1683
+ return pair;
1684
+ }
1685
+ return pair.map.toString();
1686
+ }
1687
+
1688
+ // simple visitor implementation
1689
+
1690
+ VisitorKeys = {
1691
+ AssignmentExpression: ['left', 'right'],
1692
+ ArrayExpression: ['elements'],
1693
+ BlockStatement: ['body'],
1694
+ BinaryExpression: ['left', 'right'],
1695
+ BreakStatement: ['label'],
1696
+ CallExpression: ['callee', 'arguments'],
1697
+ CatchClause: ['param', 'body'],
1698
+ ConditionalExpression: ['test', 'consequent', 'alternate'],
1699
+ ContinueStatement: ['label'],
1700
+ DoWhileStatement: ['body', 'test'],
1701
+ DebuggerStatement: [],
1702
+ EmptyStatement: [],
1703
+ ExpressionStatement: ['expression'],
1704
+ ForStatement: ['init', 'test', 'update', 'body'],
1705
+ ForInStatement: ['left', 'right', 'body'],
1706
+ FunctionDeclaration: ['id', 'params', 'body'],
1707
+ FunctionExpression: ['id', 'params', 'body'],
1708
+ Identifier: [],
1709
+ IfStatement: ['test', 'consequent', 'alternate'],
1710
+ Literal: [],
1711
+ LabeledStatement: ['label', 'body'],
1712
+ LogicalExpression: ['left', 'right'],
1713
+ MemberExpression: ['object', 'property'],
1714
+ NewExpression: ['callee', 'arguments'],
1715
+ ObjectExpression: ['properties'],
1716
+ Program: ['body'],
1717
+ Property: ['key', 'value'],
1718
+ ReturnStatement: ['argument'],
1719
+ SequenceExpression: ['expressions'],
1720
+ SwitchStatement: ['discriminant', 'cases'],
1721
+ SwitchCase: ['test', 'consequent'],
1722
+ ThisExpression: [],
1723
+ ThrowStatement: ['argument'],
1724
+ TryStatement: ['block', 'handlers', 'finalizer'],
1725
+ UnaryExpression: ['argument'],
1726
+ UpdateExpression: ['argument'],
1727
+ VariableDeclaration: ['declarations'],
1728
+ VariableDeclarator: ['id', 'init'],
1729
+ WhileStatement: ['test', 'body'],
1730
+ WithStatement: ['object', 'body']
1731
+ };
1732
+
1733
+ VisitorOption = {
1734
+ Break: 1,
1735
+ Skip: 2
1736
+ };
1737
+
1738
+ function traverse(top, visitor) {
1739
+ var worklist, leavelist, node, ret, current, current2, candidates, candidate, marker = {};
1740
+
1741
+ worklist = [ top ];
1742
+ leavelist = [ null ];
1743
+
1744
+ while (worklist.length) {
1745
+ node = worklist.pop();
1746
+
1747
+ if (node === marker) {
1748
+ node = leavelist.pop();
1749
+ if (visitor.leave) {
1750
+ ret = visitor.leave(node, leavelist[leavelist.length - 1]);
1751
+ } else {
1752
+ ret = undefined;
1753
+ }
1754
+ if (ret === VisitorOption.Break) {
1755
+ return;
1756
+ }
1757
+ } else if (node) {
1758
+ if (visitor.enter) {
1759
+ ret = visitor.enter(node, leavelist[leavelist.length - 1]);
1760
+ } else {
1761
+ ret = undefined;
1762
+ }
1763
+
1764
+ if (ret === VisitorOption.Break) {
1765
+ return;
1766
+ }
1767
+
1768
+ worklist.push(marker);
1769
+ leavelist.push(node);
1770
+
1771
+ if (ret !== VisitorOption.Skip) {
1772
+ candidates = VisitorKeys[node.type];
1773
+ current = candidates.length;
1774
+ while ((current -= 1) >= 0) {
1775
+ candidate = node[candidates[current]];
1776
+ if (candidate) {
1777
+ if (isArray(candidate)) {
1778
+ current2 = candidate.length;
1779
+ while ((current2 -= 1) >= 0) {
1780
+ if (candidate[current2]) {
1781
+ worklist.push(candidate[current2]);
1782
+ }
1783
+ }
1784
+ } else {
1785
+ worklist.push(candidate);
1786
+ }
1787
+ }
1788
+ }
1789
+ }
1790
+ }
1791
+ }
1792
+ }
1793
+
1794
+ // based on LLVM libc++ upper_bound / lower_bound
1795
+ // MIT License
1796
+
1797
+ function upperBound(array, func) {
1798
+ var diff, len, i, current;
1799
+
1800
+ len = array.length;
1801
+ i = 0;
1802
+
1803
+ while (len) {
1804
+ diff = len >>> 1;
1805
+ current = i + diff;
1806
+ if (func(array[current])) {
1807
+ len = diff;
1808
+ } else {
1809
+ i = current + 1;
1810
+ len -= diff + 1;
1811
+ }
1812
+ }
1813
+ return i;
1814
+ }
1815
+
1816
+ function lowerBound(array, func) {
1817
+ var diff, len, i, current;
1818
+
1819
+ len = array.length;
1820
+ i = 0;
1821
+
1822
+ while (len) {
1823
+ diff = len >>> 1;
1824
+ current = i + diff;
1825
+ if (func(array[current])) {
1826
+ i = current + 1;
1827
+ len -= diff + 1;
1828
+ } else {
1829
+ len = diff;
1830
+ }
1831
+ }
1832
+ return i;
1833
+ }
1834
+
1835
+ function extendCommentRange(comment, tokens) {
1836
+ var target, token;
1837
+
1838
+ target = upperBound(tokens, function search(token) {
1839
+ return token.range[0] > comment.range[0];
1840
+ });
1841
+
1842
+ comment.extendedRange = [comment.range[0], comment.range[1]];
1843
+
1844
+ if (target !== tokens.length) {
1845
+ comment.extendedRange[1] = tokens[target].range[0];
1846
+ }
1847
+
1848
+ target -= 1;
1849
+ if (target >= 0) {
1850
+ if (target < tokens.length) {
1851
+ comment.extendedRange[0] = tokens[target].range[1];
1852
+ } else if (token.length) {
1853
+ comment.extendedRange[1] = tokens[tokens.length - 1].range[0];
1854
+ }
1855
+ }
1856
+
1857
+ return comment;
1858
+ }
1859
+
1860
+ function attachComments(tree, providedComments, tokens) {
1861
+ // At first, we should calculate extended comment ranges.
1862
+ var comments = [], comment, len, i;
1863
+
1864
+ if (!tree.range) {
1865
+ throw new Error('attachComments needs range information');
1866
+ }
1867
+
1868
+ // tokens array is empty, we attach comments to tree as 'leadingComments'
1869
+ if (!tokens.length) {
1870
+ if (providedComments.length) {
1871
+ for (i = 0, len = providedComments.length; i < len; i += 1) {
1872
+ comment = deepCopy(providedComments[i]);
1873
+ comment.extendedRange = [0, tree.range[0]];
1874
+ comments.push(comment);
1875
+ }
1876
+ tree.leadingComments = comments;
1877
+ }
1878
+ return tree;
1879
+ }
1880
+
1881
+ for (i = 0, len = providedComments.length; i < len; i += 1) {
1882
+ comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens));
1883
+ }
1884
+
1885
+ // This is based on John Freeman's implementation.
1886
+ traverse(tree, {
1887
+ cursor: 0,
1888
+ enter: function (node) {
1889
+ var comment;
1890
+
1891
+ while (this.cursor < comments.length) {
1892
+ comment = comments[this.cursor];
1893
+ if (comment.extendedRange[1] > node.range[0]) {
1894
+ break;
1895
+ }
1896
+
1897
+ if (comment.extendedRange[1] === node.range[0]) {
1898
+ if (!node.leadingComments) {
1899
+ node.leadingComments = [];
1900
+ }
1901
+ node.leadingComments.push(comment);
1902
+ comments.splice(this.cursor, 1);
1903
+ } else {
1904
+ this.cursor += 1;
1905
+ }
1906
+ }
1907
+
1908
+ // already out of owned node
1909
+ if (this.cursor === comments.length) {
1910
+ return VisitorOption.Break;
1911
+ }
1912
+
1913
+ if (comments[this.cursor].extendedRange[0] > node.range[1]) {
1914
+ return VisitorOption.Skip;
1915
+ }
1916
+ }
1917
+ });
1918
+
1919
+ traverse(tree, {
1920
+ cursor: 0,
1921
+ leave: function (node) {
1922
+ var comment;
1923
+
1924
+ while (this.cursor < comments.length) {
1925
+ comment = comments[this.cursor];
1926
+ if (node.range[1] < comment.extendedRange[0]) {
1927
+ break;
1928
+ }
1929
+
1930
+ if (node.range[1] === comment.extendedRange[0]) {
1931
+ if (!node.trailingComments) {
1932
+ node.trailingComments = [];
1933
+ }
1934
+ node.trailingComments.push(comment);
1935
+ comments.splice(this.cursor, 1);
1936
+ } else {
1937
+ this.cursor += 1;
1938
+ }
1939
+ }
1940
+
1941
+ // already out of owned node
1942
+ if (this.cursor === comments.length) {
1943
+ return VisitorOption.Break;
1944
+ }
1945
+
1946
+ if (comments[this.cursor].extendedRange[0] > node.range[1]) {
1947
+ return VisitorOption.Skip;
1948
+ }
1949
+ }
1950
+ });
1951
+
1952
+ return tree;
1953
+ }
1954
+
1955
+ // Sync with package.json.
1956
+ exports.version = '0.0.10-dev';
1957
+
1958
+ exports.generate = generate;
1959
+ exports.traverse = traverse;
1960
+ exports.attachComments = attachComments;
1961
+
1962
+ }, this));
1963
+ /* vim: set sw=4 ts=4 et tw=80 : */