sweetjs 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 : */