coffee-script 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ require "coffee_script/lexer"
3
+ require "coffee_script/parser"
4
+ require "coffee_script/nodes"
5
+ require "coffee_script/value"
6
+ require "coffee_script/scope"
7
+ require "coffee_script/parse_error"
8
+
9
+ # Namespace for all CoffeeScript internal classes.
10
+ module CoffeeScript
11
+
12
+ VERSION = '0.1.0' # Keep in sync with the gemspec.
13
+
14
+ # Compile a script (String or IO) to JavaScript.
15
+ def self.compile(script)
16
+ script = script.read if script.respond_to?(:read)
17
+ Parser.new.parse(script).compile
18
+ end
19
+
20
+ end
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>name</key>
6
+ <string>comments</string>
7
+ <key>scope</key>
8
+ <string>source.cs</string>
9
+ <key>settings</key>
10
+ <dict>
11
+ <key>shellVariables</key>
12
+ <array>
13
+ <dict>
14
+ <key>name</key>
15
+ <string>TM_COMMENT_START</string>
16
+ <key>value</key>
17
+ <string># </string>
18
+ </dict>
19
+ </array>
20
+ </dict>
21
+ <key>uuid</key>
22
+ <string>0A92C6F6-4D73-4859-B38C-4CC19CBC191F</string>
23
+ </dict>
24
+ </plist>
@@ -0,0 +1,329 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>comment</key>
6
+ <string>CoffeeScript Syntax: version 1</string>
7
+ <key>fileTypes</key>
8
+ <array>
9
+ <string>cs</string>
10
+ <string>coffeescript</string>
11
+ </array>
12
+ <key>name</key>
13
+ <string>CoffeeScript</string>
14
+ <key>patterns</key>
15
+ <array>
16
+ <dict>
17
+ <key>captures</key>
18
+ <dict>
19
+ <key>1</key>
20
+ <dict>
21
+ <key>name</key>
22
+ <string>entity.name.function.cs</string>
23
+ </dict>
24
+ <key>2</key>
25
+ <dict>
26
+ <key>name</key>
27
+ <string>keyword.operator.cs</string>
28
+ </dict>
29
+ <key>3</key>
30
+ <dict>
31
+ <key>name</key>
32
+ <string>variable.parameter.function.cs</string>
33
+ </dict>
34
+ <key>4</key>
35
+ <dict>
36
+ <key>name</key>
37
+ <string>storage.type.function.cs</string>
38
+ </dict>
39
+ </dict>
40
+ <key>comment</key>
41
+ <string>match stuff like: funcName: =&gt; … </string>
42
+ <key>match</key>
43
+ <string>([a-zA-Z_?.$]*)\s*(=|:)\s*([\w,\s]*?)\s*(=&gt;)</string>
44
+ <key>name</key>
45
+ <string>meta.function.cs</string>
46
+ </dict>
47
+ <dict>
48
+ <key>captures</key>
49
+ <dict>
50
+ <key>1</key>
51
+ <dict>
52
+ <key>name</key>
53
+ <string>variable.parameter.function.cs</string>
54
+ </dict>
55
+ <key>2</key>
56
+ <dict>
57
+ <key>name</key>
58
+ <string>storage.type.function.cs</string>
59
+ </dict>
60
+ </dict>
61
+ <key>comment</key>
62
+ <string>match stuff like: a =&gt; … </string>
63
+ <key>match</key>
64
+ <string>([a-zA-Z_?., $]*)\s*(=&gt;)</string>
65
+ <key>name</key>
66
+ <string>meta.inline.function.cs</string>
67
+ </dict>
68
+ <dict>
69
+ <key>captures</key>
70
+ <dict>
71
+ <key>1</key>
72
+ <dict>
73
+ <key>name</key>
74
+ <string>keyword.operator.new.cs</string>
75
+ </dict>
76
+ <key>2</key>
77
+ <dict>
78
+ <key>name</key>
79
+ <string>entity.name.type.instance.cs</string>
80
+ </dict>
81
+ </dict>
82
+ <key>match</key>
83
+ <string>(new)\s+(\w+(?:\.\w*)?)</string>
84
+ <key>name</key>
85
+ <string>meta.class.instance.constructor</string>
86
+ </dict>
87
+ <dict>
88
+ <key>match</key>
89
+ <string>\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\.[0-9]+)?(e[+\-]?[0-9]+)?))\b</string>
90
+ <key>name</key>
91
+ <string>constant.numeric.cs</string>
92
+ </dict>
93
+ <dict>
94
+ <key>begin</key>
95
+ <string>'</string>
96
+ <key>beginCaptures</key>
97
+ <dict>
98
+ <key>0</key>
99
+ <dict>
100
+ <key>name</key>
101
+ <string>punctuation.definition.string.begin.cs</string>
102
+ </dict>
103
+ </dict>
104
+ <key>end</key>
105
+ <string>'</string>
106
+ <key>endCaptures</key>
107
+ <dict>
108
+ <key>0</key>
109
+ <dict>
110
+ <key>name</key>
111
+ <string>punctuation.definition.string.end.cs</string>
112
+ </dict>
113
+ </dict>
114
+ <key>name</key>
115
+ <string>string.quoted.single.cs</string>
116
+ <key>patterns</key>
117
+ <array>
118
+ <dict>
119
+ <key>match</key>
120
+ <string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)</string>
121
+ <key>name</key>
122
+ <string>constant.character.escape.cs</string>
123
+ </dict>
124
+ </array>
125
+ </dict>
126
+ <dict>
127
+ <key>begin</key>
128
+ <string>"</string>
129
+ <key>beginCaptures</key>
130
+ <dict>
131
+ <key>0</key>
132
+ <dict>
133
+ <key>name</key>
134
+ <string>punctuation.definition.string.begin.cs</string>
135
+ </dict>
136
+ </dict>
137
+ <key>end</key>
138
+ <string>"</string>
139
+ <key>endCaptures</key>
140
+ <dict>
141
+ <key>0</key>
142
+ <dict>
143
+ <key>name</key>
144
+ <string>punctuation.definition.string.end.cs</string>
145
+ </dict>
146
+ </dict>
147
+ <key>name</key>
148
+ <string>string.quoted.double.cs</string>
149
+ <key>patterns</key>
150
+ <array>
151
+ <dict>
152
+ <key>match</key>
153
+ <string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)</string>
154
+ <key>name</key>
155
+ <string>constant.character.escape.cs</string>
156
+ </dict>
157
+ </array>
158
+ </dict>
159
+ <dict>
160
+ <key>begin</key>
161
+ <string>`</string>
162
+ <key>beginCaptures</key>
163
+ <dict>
164
+ <key>0</key>
165
+ <dict>
166
+ <key>name</key>
167
+ <string>punctuation.definition.string.begin.cs</string>
168
+ </dict>
169
+ </dict>
170
+ <key>end</key>
171
+ <string>`</string>
172
+ <key>endCaptures</key>
173
+ <dict>
174
+ <key>0</key>
175
+ <dict>
176
+ <key>name</key>
177
+ <string>punctuation.definition.string.end.cs</string>
178
+ </dict>
179
+ </dict>
180
+ <key>name</key>
181
+ <string>string.quoted.script.cs</string>
182
+ <key>patterns</key>
183
+ <array>
184
+ <dict>
185
+ <key>match</key>
186
+ <string>\\(x\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)</string>
187
+ <key>name</key>
188
+ <string>constant.character.escape.cs</string>
189
+ </dict>
190
+ </array>
191
+ </dict>
192
+ <dict>
193
+ <key>captures</key>
194
+ <dict>
195
+ <key>1</key>
196
+ <dict>
197
+ <key>name</key>
198
+ <string>punctuation.definition.comment.cs</string>
199
+ </dict>
200
+ </dict>
201
+ <key>match</key>
202
+ <string>(#).*$\n?</string>
203
+ <key>name</key>
204
+ <string>comment.line.cs</string>
205
+ </dict>
206
+ <dict>
207
+ <key>match</key>
208
+ <string>\b(break|when|catch|continue|else|finally|for|if|return|switch|then|throw|try|unless|while)\b</string>
209
+ <key>name</key>
210
+ <string>keyword.control.cs</string>
211
+ </dict>
212
+ <dict>
213
+ <key>match</key>
214
+ <string>\b(true|on|yes)\b</string>
215
+ <key>name</key>
216
+ <string>constant.language.boolean.true.cs</string>
217
+ </dict>
218
+ <dict>
219
+ <key>match</key>
220
+ <string>\b(false|off|no)\b</string>
221
+ <key>name</key>
222
+ <string>constant.language.boolean.false.cs</string>
223
+ </dict>
224
+ <dict>
225
+ <key>match</key>
226
+ <string>\bnull\b</string>
227
+ <key>name</key>
228
+ <string>constant.language.null.cs</string>
229
+ </dict>
230
+ <dict>
231
+ <key>match</key>
232
+ <string>\b(super|this)\b</string>
233
+ <key>name</key>
234
+ <string>variable.language.cs</string>
235
+ </dict>
236
+ <dict>
237
+ <key>match</key>
238
+ <string>\b(debugger)\b</string>
239
+ <key>name</key>
240
+ <string>keyword.other.cs</string>
241
+ </dict>
242
+ <dict>
243
+ <key>match</key>
244
+ <string>!|\$|%|&amp;|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|&lt;=|&gt;=|&lt;&lt;=|&gt;&gt;=|&gt;&gt;&gt;=|&lt;&gt;|&lt;|&gt;|!|&amp;&amp;|\?|\|\||\:|\*=|(?&lt;!\()/=|%=|\+=|\-=|&amp;=|\^=|\b(in|instanceof|new|delete|typeof|and|or|is|aint|not)\b</string>
245
+ <key>name</key>
246
+ <string>keyword.operator.cs</string>
247
+ </dict>
248
+ <dict>
249
+ <key>match</key>
250
+ <string>\b(Infinity|NaN|undefined)\b</string>
251
+ <key>name</key>
252
+ <string>constant.language.cs</string>
253
+ </dict>
254
+ <dict>
255
+ <key>begin</key>
256
+ <string>(?&lt;=[=(:]|^|return)\s*(/)(?![/*+{}?])</string>
257
+ <key>beginCaptures</key>
258
+ <dict>
259
+ <key>1</key>
260
+ <dict>
261
+ <key>name</key>
262
+ <string>punctuation.definition.string.begin.cs</string>
263
+ </dict>
264
+ </dict>
265
+ <key>end</key>
266
+ <string>(/)[igm]*</string>
267
+ <key>endCaptures</key>
268
+ <dict>
269
+ <key>1</key>
270
+ <dict>
271
+ <key>name</key>
272
+ <string>punctuation.definition.string.end.cs</string>
273
+ </dict>
274
+ </dict>
275
+ <key>name</key>
276
+ <string>string.regexp.cs</string>
277
+ <key>patterns</key>
278
+ <array>
279
+ <dict>
280
+ <key>match</key>
281
+ <string>\\.</string>
282
+ <key>name</key>
283
+ <string>constant.character.escape.cs</string>
284
+ </dict>
285
+ </array>
286
+ </dict>
287
+ <dict>
288
+ <key>match</key>
289
+ <string>\;</string>
290
+ <key>name</key>
291
+ <string>punctuation.terminator.statement.cs</string>
292
+ </dict>
293
+ <dict>
294
+ <key>match</key>
295
+ <string>,[ |\t]*</string>
296
+ <key>name</key>
297
+ <string>meta.delimiter.object.comma.cs</string>
298
+ </dict>
299
+ <dict>
300
+ <key>match</key>
301
+ <string>\.</string>
302
+ <key>name</key>
303
+ <string>meta.delimiter.method.period.cs</string>
304
+ </dict>
305
+ <dict>
306
+ <key>match</key>
307
+ <string>\{|\}</string>
308
+ <key>name</key>
309
+ <string>meta.brace.curly.cs</string>
310
+ </dict>
311
+ <dict>
312
+ <key>match</key>
313
+ <string>\(|\)</string>
314
+ <key>name</key>
315
+ <string>meta.brace.round.cs</string>
316
+ </dict>
317
+ <dict>
318
+ <key>match</key>
319
+ <string>\[|\]</string>
320
+ <key>name</key>
321
+ <string>meta.brace.square.cs</string>
322
+ </dict>
323
+ </array>
324
+ <key>scopeName</key>
325
+ <string>source.cs</string>
326
+ <key>uuid</key>
327
+ <string>5B520980-A7D5-4E10-8582-1A4C889A8DE5</string>
328
+ </dict>
329
+ </plist>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>name</key>
6
+ <string>CoffeeScript</string>
7
+ <key>uuid</key>
8
+ <string>A46E4382-F1AC-405B-8F22-65FF470F34D7</string>
9
+ </dict>
10
+ </plist>
@@ -0,0 +1,183 @@
1
+ require 'optparse'
2
+ require 'fileutils'
3
+ require 'open3'
4
+ require File.expand_path(File.dirname(__FILE__) + '/../coffee-script')
5
+
6
+ module CoffeeScript
7
+
8
+ # The CommandLine handles all of the functionality of the `coffee-script`
9
+ # utility.
10
+ class CommandLine
11
+
12
+ BANNER = <<-EOS
13
+ coffee-script compiles CoffeeScript source files into JavaScript.
14
+
15
+ Usage:
16
+ coffee-script path/to/script.cs
17
+ EOS
18
+
19
+ # Seconds to pause between checks for changed source files.
20
+ WATCH_INTERVAL = 0.5
21
+
22
+ # Run the CommandLine off the contents of ARGV.
23
+ def initialize
24
+ @mtimes = {}
25
+ parse_options
26
+ return eval_scriptlet if @options[:eval]
27
+ check_sources
28
+ @sources.each {|source| compile_javascript(source) }
29
+ watch_coffee_scripts if @options[:watch]
30
+ end
31
+
32
+ # The "--help" usage message.
33
+ def usage
34
+ puts "\n#{@option_parser}\n"
35
+ exit
36
+ end
37
+
38
+
39
+ private
40
+
41
+ # Compiles (or partially compiles) the source CoffeeScript file, returning
42
+ # the desired JS, tokens, or lint results.
43
+ def compile_javascript(source)
44
+ script = File.read(source)
45
+ return tokens(script) if @options[:tokens]
46
+ js = compile(script, source)
47
+ return unless js
48
+ return puts(js) if @options[:print]
49
+ return lint(js) if @options[:lint]
50
+ File.open(path_for(source), 'w+') {|f| f.write(js) }
51
+ end
52
+
53
+ # Spins up a watcher thread to keep track of the modification times of the
54
+ # source files, recompiling them whenever they're saved.
55
+ def watch_coffee_scripts
56
+ watch_thread = Thread.start do
57
+ loop do
58
+ @sources.each do |source|
59
+ mtime = File.stat(source).mtime
60
+ @mtimes[source] ||= mtime
61
+ if mtime > @mtimes[source]
62
+ @mtimes[source] = mtime
63
+ compile_javascript(source)
64
+ end
65
+ end
66
+ sleep WATCH_INTERVAL
67
+ end
68
+ end
69
+ Signal.trap("INT") { watch_thread.kill }
70
+ watch_thread.join
71
+ end
72
+
73
+ # Ensure that all of the source files exist.
74
+ def check_sources
75
+ usage if @sources.empty?
76
+ missing = @sources.detect {|s| !File.exists?(s) }
77
+ if missing
78
+ STDERR.puts("File not found: '#{missing}'")
79
+ exit(1)
80
+ end
81
+ end
82
+
83
+ # Pipe compiled JS through JSLint (requires a working 'jsl' command).
84
+ def lint(js)
85
+ stdin, stdout, stderr = Open3.popen3('jsl -nologo -stdin')
86
+ stdin.write(js)
87
+ stdin.close
88
+ puts stdout.read.tr("\n", '')
89
+ errs = stderr.read.chomp
90
+ puts errs unless errs.empty?
91
+ stdout.close and stderr.close
92
+ end
93
+
94
+ # Eval a little piece of CoffeeScript directly from the command line.
95
+ def eval_scriptlet
96
+ script = STDIN.tty? ? @sources.join(' ') : STDIN.read
97
+ return tokens(script) if @options[:tokens]
98
+ js = compile(script)
99
+ return lint(js) if @options[:lint]
100
+ puts js
101
+ end
102
+
103
+ # Print the tokens that the lexer generates from a source script.
104
+ def tokens(script)
105
+ puts Lexer.new.tokenize(script).inspect
106
+ end
107
+
108
+ # Compile a single source file to JavaScript.
109
+ def compile(script, source='')
110
+ begin
111
+ CoffeeScript.compile(script)
112
+ rescue CoffeeScript::ParseError => e
113
+ STDERR.puts e.message(source)
114
+ exit(1) unless @options[:watch]
115
+ nil
116
+ end
117
+ end
118
+
119
+ # Write out JavaScript alongside CoffeeScript unless an output directory
120
+ # is specified.
121
+ def path_for(source)
122
+ filename = File.basename(source, File.extname(source)) + '.js'
123
+ dir = @options[:output] || File.dirname(source)
124
+ File.join(dir, filename)
125
+ end
126
+
127
+ # Install the CoffeeScript TextMate bundle to ~/Library.
128
+ def install_bundle
129
+ bundle_dir = File.expand_path('~/Library/Application Support/TextMate/Bundles/')
130
+ FileUtils.cp_r(File.dirname(__FILE__) + '/CoffeeScript.tmbundle', bundle_dir)
131
+ end
132
+
133
+ # Use OptionParser for all the options.
134
+ def parse_options
135
+ @options = {}
136
+ @option_parser = OptionParser.new do |opts|
137
+ opts.on('-o', '--output [DIR]', 'set the directory for compiled JavaScript') do |d|
138
+ @options[:output] = d
139
+ FileUtils.mkdir_p(d) unless File.exists?(d)
140
+ end
141
+ opts.on('-w', '--watch', 'watch scripts for changes, and recompile') do |w|
142
+ @options[:watch] = true
143
+ end
144
+ opts.on('-p', '--print', 'print the compiled JavaScript to stdout') do |d|
145
+ @options[:print] = true
146
+ end
147
+ opts.on('-l', '--lint', 'pipe the compiled JavaScript through JSLint') do |l|
148
+ @options[:lint] = true
149
+ end
150
+ opts.on('-e', '--eval', 'eval a little scriptlet directly from the cli') do |e|
151
+ @options[:eval] = true
152
+ end
153
+ opts.on('-t', '--tokens', 'print the tokens that the lexer produces') do |t|
154
+ @options[:tokens] = true
155
+ end
156
+ opts.on('-v', '--verbose', 'print at every step of code generation') do |v|
157
+ ENV['VERBOSE'] = 'true'
158
+ end
159
+ opts.on_tail('--install-bundle', 'install the CoffeeScript TextMate bundle') do |i|
160
+ install_bundle
161
+ exit
162
+ end
163
+ opts.on_tail('--version', 'display coffee-script version') do
164
+ puts "coffee-script version #{CoffeeScript::VERSION}"
165
+ exit
166
+ end
167
+ opts.on_tail('-h', '--help', 'display this help message') do
168
+ usage
169
+ end
170
+ end
171
+ @option_parser.banner = BANNER
172
+ begin
173
+ @option_parser.parse!(ARGV)
174
+ rescue OptionParser::InvalidOption => e
175
+ puts e.message
176
+ exit(1)
177
+ end
178
+ @sources = ARGV
179
+ end
180
+
181
+ end
182
+
183
+ end