coffee-script 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/LICENSE +22 -0
- data/README +38 -0
- data/bin/coffee-script +5 -0
- data/coffee-script.gemspec +21 -0
- data/examples/code.cs +173 -0
- data/examples/documents.cs +72 -0
- data/examples/poignant.cs +153 -0
- data/examples/syntax_errors.cs +20 -0
- data/examples/underscore.cs +597 -0
- data/lib/coffee-script.rb +20 -0
- data/lib/coffee_script/CoffeeScript.tmbundle/Preferences/CoffeeScript.tmPreferences +24 -0
- data/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage +329 -0
- data/lib/coffee_script/CoffeeScript.tmbundle/info.plist +10 -0
- data/lib/coffee_script/command_line.rb +183 -0
- data/lib/coffee_script/grammar.y +403 -0
- data/lib/coffee_script/lexer.rb +187 -0
- data/lib/coffee_script/nodes.rb +680 -0
- data/lib/coffee_script/parse_error.rb +22 -0
- data/lib/coffee_script/parser.rb +1987 -0
- data/lib/coffee_script/scope.rb +45 -0
- data/lib/coffee_script/value.rb +42 -0
- metadata +75 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2009 Jeremy Ashkenas
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
=
|
2
|
+
{
|
3
|
+
} } {
|
4
|
+
{ { } }
|
5
|
+
} }{ {
|
6
|
+
{ }{ } } _____ __ __
|
7
|
+
( }{ }{ { ) / ____| / _|/ _|
|
8
|
+
.- { { } { }} -. | | ___ | |_| |_ ___ ___
|
9
|
+
( ( } { } { } } ) | | / _ \| _| _/ _ \/ _ \
|
10
|
+
|`-..________ ..-'| | |___| (_) | | | || __/ __/
|
11
|
+
| | \_____\___/|_| |_| \___|\___|
|
12
|
+
| ;--.
|
13
|
+
| (__ \ _____ _ _
|
14
|
+
| | ) ) / ____| (_) | |
|
15
|
+
| |/ / | (___ ___ _ __ _ _ __ | |_
|
16
|
+
| ( / \___ \ / __| '__| | '_ \| __|
|
17
|
+
| |/ ____) | (__| | | | |_) | |_
|
18
|
+
| | |_____/ \___|_| |_| .__/ \__|
|
19
|
+
`-.._________..-' | |
|
20
|
+
|_|
|
21
|
+
|
22
|
+
|
23
|
+
CoffeeScript is a little language that compiles into JavaScript.
|
24
|
+
|
25
|
+
Install the compiler:
|
26
|
+
gem install coffee-script
|
27
|
+
|
28
|
+
Compile a script:
|
29
|
+
coffee-script /path/to/script.cs
|
30
|
+
|
31
|
+
For documentation, usage, and examples, see:
|
32
|
+
http://jashkenas.github.com/coffee-script/
|
33
|
+
|
34
|
+
To suggest a feature or report a bug:
|
35
|
+
http://github.com/jashkenas/coffee-script/issues/
|
36
|
+
|
37
|
+
The source repository:
|
38
|
+
git://github.com/jashkenas/coffee-script.git
|
data/bin/coffee-script
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'coffee-script'
|
3
|
+
s.version = '0.1.0' # Keep version in sync with coffee-script.rb
|
4
|
+
s.date = '2009-12-24'
|
5
|
+
|
6
|
+
s.homepage = "http://jashkenas.github.com/coffee-script/"
|
7
|
+
s.summary = "The CoffeeScript Compiler"
|
8
|
+
s.description = <<-EOS
|
9
|
+
CoffeeScript is a little language that compiles into JavaScript.
|
10
|
+
EOS
|
11
|
+
|
12
|
+
s.authors = ['Jeremy Ashkenas']
|
13
|
+
s.email = 'jashkenas@gmail.com'
|
14
|
+
s.rubyforge_project = 'coffee-script'
|
15
|
+
s.has_rdoc = false
|
16
|
+
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
s.executables = ['coffee-script']
|
19
|
+
|
20
|
+
s.files = Dir['bin/*', 'examples/*', 'lib/**/*', 'coffee-script.gemspec', 'LICENSE', 'README']
|
21
|
+
end
|
data/examples/code.cs
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
# Functions:
|
2
|
+
square: x => x * x.
|
3
|
+
|
4
|
+
sum: x, y => x + y.
|
5
|
+
|
6
|
+
odd: x => x % 2 is 0.
|
7
|
+
|
8
|
+
even: x => x % 2 aint 0.
|
9
|
+
|
10
|
+
run_loop: =>
|
11
|
+
fire_events( e => e.stopPropagation(). )
|
12
|
+
listen()
|
13
|
+
wait().
|
14
|
+
|
15
|
+
# Objects:
|
16
|
+
dense_object_literal: {one: 1, two: 2, three: 3}
|
17
|
+
|
18
|
+
spaced_out_multiline_object: {
|
19
|
+
pi: 3.14159
|
20
|
+
list: [1, 2, 3, 4]
|
21
|
+
regex: /match[ing](every|thing|\/)/gi
|
22
|
+
three: new Idea()
|
23
|
+
|
24
|
+
inner_obj: {
|
25
|
+
freedom: => _.freedom().
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
# Arrays:
|
30
|
+
stooges : [{moe: 45}, {curly: 43}, {larry: 46}]
|
31
|
+
|
32
|
+
exponents : [x => x., x => x * x., x => x * x * x.]
|
33
|
+
|
34
|
+
empty: []
|
35
|
+
|
36
|
+
multiline: [
|
37
|
+
'line one'
|
38
|
+
'line two'
|
39
|
+
]
|
40
|
+
|
41
|
+
# Conditionals and ternaries.
|
42
|
+
if submarine.shields_up
|
43
|
+
full_speed_ahead()
|
44
|
+
fire_torpedos()
|
45
|
+
else if submarine.sinking
|
46
|
+
abandon_ship()
|
47
|
+
else
|
48
|
+
run_away().
|
49
|
+
|
50
|
+
eldest: if 25 > 21 then liz else marge.
|
51
|
+
|
52
|
+
decoration: medal_of_honor if war_hero
|
53
|
+
|
54
|
+
go_to_sleep() unless coffee
|
55
|
+
|
56
|
+
# Returning early:
|
57
|
+
race: =>
|
58
|
+
run()
|
59
|
+
walk()
|
60
|
+
crawl()
|
61
|
+
if tired then return sleep().
|
62
|
+
race().
|
63
|
+
|
64
|
+
# Conditional assignment:
|
65
|
+
good ||: evil
|
66
|
+
wine &&: cheese
|
67
|
+
|
68
|
+
# Nested property access and calls.
|
69
|
+
((moon.turn(360))).shapes[3].move({x: 45, y: 30}).position['top'].offset('x')
|
70
|
+
|
71
|
+
a: b: c: 5
|
72
|
+
|
73
|
+
# Embedded JavaScript.
|
74
|
+
callback(
|
75
|
+
`function(e) { e.stop(); }`
|
76
|
+
)
|
77
|
+
|
78
|
+
# Try/Catch/Finally/Throw.
|
79
|
+
try
|
80
|
+
all_hell_breaks_loose()
|
81
|
+
dogs_and_cats_living_together()
|
82
|
+
throw "up"
|
83
|
+
catch error
|
84
|
+
print( error )
|
85
|
+
finally
|
86
|
+
clean_up().
|
87
|
+
|
88
|
+
try all_hell_breaks_loose() catch error print(error) finally clean_up().
|
89
|
+
|
90
|
+
# While loops, break and continue.
|
91
|
+
while demand > supply
|
92
|
+
sell()
|
93
|
+
restock().
|
94
|
+
|
95
|
+
while supply > demand then buy().
|
96
|
+
|
97
|
+
while true
|
98
|
+
break if broken
|
99
|
+
continue if continuing.
|
100
|
+
|
101
|
+
# Unary operators.
|
102
|
+
!!true
|
103
|
+
|
104
|
+
# Lexical scoping.
|
105
|
+
a: 5
|
106
|
+
change_a_and_set_b: =>
|
107
|
+
a: 10
|
108
|
+
b: 15.
|
109
|
+
b: 20
|
110
|
+
|
111
|
+
# Array comprehensions.
|
112
|
+
supper: food.capitalize() for food in ['toast', 'cheese', 'wine'].
|
113
|
+
|
114
|
+
drink(bottle) for bottle, i in ['soda', 'wine', 'lemonade'] if even(i).
|
115
|
+
|
116
|
+
# Switch statements ("else" serves as a default).
|
117
|
+
activity: switch day
|
118
|
+
when "Tuesday" then eat_breakfast()
|
119
|
+
when "Sunday" then go_to_church()
|
120
|
+
when "Saturday" then go_to_the_park()
|
121
|
+
when "Wednesday"
|
122
|
+
if day is bingo_day
|
123
|
+
go_to_bingo()
|
124
|
+
else
|
125
|
+
eat_breakfast()
|
126
|
+
go_to_work()
|
127
|
+
eat_dinner().
|
128
|
+
else go_to_work().
|
129
|
+
|
130
|
+
# Semicolons can optionally be used instead of newlines.
|
131
|
+
wednesday: => eat_breakfast(); go_to_work(); eat_dinner(); .
|
132
|
+
|
133
|
+
# Array slice literals.
|
134
|
+
zero_to_nine: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
135
|
+
three_to_six: zero_to_nine[3, 6]
|
136
|
+
|
137
|
+
# Multiline strings with inner quotes.
|
138
|
+
story: "Lorem ipsum dolor \"sit\" amet, consectetuer adipiscing elit,
|
139
|
+
sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna
|
140
|
+
aliquam erat volutpat. Ut wisi enim ad."
|
141
|
+
|
142
|
+
# Inheritance and calling super.
|
143
|
+
Animal: => .
|
144
|
+
Animal.prototype.move: meters =>
|
145
|
+
alert(this.name + " moved " + meters + "m.").
|
146
|
+
|
147
|
+
Snake: name => this.name: name.
|
148
|
+
Snake.prototype: Animal
|
149
|
+
Snake.prototype.move: =>
|
150
|
+
alert('Slithering...')
|
151
|
+
super(5).
|
152
|
+
|
153
|
+
Horse: name => this.name: name.
|
154
|
+
Horse.prototype: Animal
|
155
|
+
Horse.prototype.move: =>
|
156
|
+
alert('Galloping...')
|
157
|
+
super(45).
|
158
|
+
|
159
|
+
sam: new Snake("Sammy the Snake")
|
160
|
+
tom: new Horse("Tommy the Horse")
|
161
|
+
|
162
|
+
sam.move()
|
163
|
+
tom.move()
|
164
|
+
|
165
|
+
# Numbers.
|
166
|
+
a_googol: 1e100
|
167
|
+
hex: 0xff0000
|
168
|
+
negative: -1.0
|
169
|
+
infinity: Infinity
|
170
|
+
nan: NaN
|
171
|
+
|
172
|
+
# Deleting.
|
173
|
+
delete secret.identity
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# Document Model
|
2
|
+
dc.model.Document: dc.Model.extend({
|
3
|
+
|
4
|
+
constructor: attributes => this.base(attributes).
|
5
|
+
|
6
|
+
# For display, show either the highlighted search results, or the summary,
|
7
|
+
# if no highlights are available.
|
8
|
+
# The import process will take care of this in the future, but the inline
|
9
|
+
# version of the summary has all runs of whitespace squeezed out.
|
10
|
+
displaySummary: =>
|
11
|
+
text: this.get('highlight') or this.get('summary') or ''
|
12
|
+
text and text.replace(/\s+/g, ' ').
|
13
|
+
|
14
|
+
# Return a list of the document's metadata. Think about caching this on the
|
15
|
+
# document by binding to Metadata, instead of on-the-fly.
|
16
|
+
metadata: =>
|
17
|
+
docId: this.id
|
18
|
+
_.select(Metadata.models()
|
19
|
+
meta => _.any(meta.get('instances')
|
20
|
+
instance => instance.document_id is docId.).).
|
21
|
+
|
22
|
+
bookmark: pageNumber =>
|
23
|
+
bookmark: new dc.model.Bookmark({title: this.get('title'), page_number: pageNumber, document_id: this.id})
|
24
|
+
Bookmarks.create(bookmark).
|
25
|
+
|
26
|
+
# Inspect.
|
27
|
+
toString: => 'Document ' + this.id + ' "' + this.get('title') + '"'.
|
28
|
+
|
29
|
+
})
|
30
|
+
|
31
|
+
# Document Set
|
32
|
+
dc.model.DocumentSet: dc.model.RESTfulSet.extend({
|
33
|
+
|
34
|
+
resource: 'documents'
|
35
|
+
|
36
|
+
SELECTION_CHANGED: 'documents:selection_changed'
|
37
|
+
|
38
|
+
constructor: options =>
|
39
|
+
this.base(options)
|
40
|
+
_.bindAll(this, 'downloadSelectedViewers', 'downloadSelectedPDF', 'downloadSelectedFullText').
|
41
|
+
|
42
|
+
selected: => _.select(this.models(), m => m.get('selected').).
|
43
|
+
|
44
|
+
selectedIds: => _.pluck(this.selected(), 'id').
|
45
|
+
|
46
|
+
countSelected: => this.selected().length.
|
47
|
+
|
48
|
+
downloadSelectedViewers: =>
|
49
|
+
dc.app.download('/download/' + this.selectedIds().join('/') + '/document_viewer.zip').
|
50
|
+
|
51
|
+
downloadSelectedPDF: =>
|
52
|
+
if this.countSelected() <= 1 then return window.open(this.selected()[0].get('pdf_url')).
|
53
|
+
dc.app.download('/download/' + this.selectedIds().join('/') + '/document_pdfs.zip').
|
54
|
+
|
55
|
+
downloadSelectedFullText: =>
|
56
|
+
if this.countSelected() <= 1 then return window.open(this.selected()[0].get('full_text_url')).
|
57
|
+
dc.app.download('/download/' + this.selectedIds().join('/') + '/document_text.zip').
|
58
|
+
|
59
|
+
# We override "_onModelEvent" to fire selection changed events when documents
|
60
|
+
# change their selected state.
|
61
|
+
_onModelEvent: e, model =>
|
62
|
+
this.base(e, model)
|
63
|
+
fire: e == dc.Model.CHANGED and model.hasChanged('selected')
|
64
|
+
if fire then _.defer(_(this.fire).bind(this, this.SELECTION_CHANGED, this))..
|
65
|
+
|
66
|
+
})
|
67
|
+
|
68
|
+
# The main set of Documents, used by the search tab.
|
69
|
+
window.Documents: new dc.model.DocumentSet()
|
70
|
+
|
71
|
+
# The set of documents that is used to look at a particular label.
|
72
|
+
dc.app.LabeledDocuments: new dc.model.DocumentSet()
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# Examples from the Poignant Guide.
|
2
|
+
|
3
|
+
# ['toast', 'cheese', 'wine'].each { |food| print food.capitalize }
|
4
|
+
|
5
|
+
['toast', 'wine', 'cheese'].each( food => print(food.capitalize()). )
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
# class LotteryTicket
|
10
|
+
# def picks; @picks; end
|
11
|
+
# def picks=(var); @picks = var; end
|
12
|
+
# def purchased; @purchased; end
|
13
|
+
# def purchased=(var); @purchased = var; end
|
14
|
+
# end
|
15
|
+
|
16
|
+
LotteryTicket: {
|
17
|
+
get_picks: => this.picks.
|
18
|
+
set_picks: nums => this.picks: nums.
|
19
|
+
get_purchase: => this.purchase.
|
20
|
+
set_purchase: amount => this.purchase: amount.
|
21
|
+
}
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
# module WishScanner
|
26
|
+
# def scan_for_a_wish
|
27
|
+
# wish = self.read.detect do |thought|
|
28
|
+
# thought.index( 'wish: ' ) == 0
|
29
|
+
# end
|
30
|
+
# wish.gsub( 'wish: ', '' )
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
|
34
|
+
WishScanner: {
|
35
|
+
scan_for_a_wish: =>
|
36
|
+
wish: this.read().detect( thought => thought.index('wish: ') is 0. )
|
37
|
+
wish.replace('wish: ', '').
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
# class Creature
|
43
|
+
#
|
44
|
+
# # This method applies a hit taken during a fight.
|
45
|
+
# def hit( damage )
|
46
|
+
# p_up = rand( charisma )
|
47
|
+
# if p_up % 9 == 7
|
48
|
+
# @life += p_up / 4
|
49
|
+
# puts "[#{ self.class } magick powers up #{ p_up }!]"
|
50
|
+
# end
|
51
|
+
# @life -= damage
|
52
|
+
# puts "[#{ self.class } has died.]" if @life <= 0
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# # This method takes one turn in a fight.
|
56
|
+
# def fight( enemy, weapon )
|
57
|
+
# if life <= 0
|
58
|
+
# puts "[#{ self.class } is too dead to fight!]"
|
59
|
+
# return
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# # Attack the opponent
|
63
|
+
# your_hit = rand( strength + weapon )
|
64
|
+
# puts "[You hit with #{ your_hit } points of damage!]"
|
65
|
+
# enemy.hit( your_hit )
|
66
|
+
#
|
67
|
+
# # Retaliation
|
68
|
+
# p enemy
|
69
|
+
# if enemy.life > 0
|
70
|
+
# enemy_hit = rand( enemy.strength + enemy.weapon )
|
71
|
+
# puts "[Your enemy hit with #{ enemy_hit } points of damage!]"
|
72
|
+
# self.hit( enemy_hit )
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# end
|
77
|
+
|
78
|
+
Creature : {
|
79
|
+
|
80
|
+
# This method applies a hit taken during a fight.
|
81
|
+
hit: damage =>
|
82
|
+
p_up: Math.rand( this.charisma )
|
83
|
+
if p_up % 9 is 7
|
84
|
+
this.life += p_up / 4
|
85
|
+
puts( "[" + this.name + " magick powers up " + p_up + "!]" ).
|
86
|
+
this.life -= damage
|
87
|
+
if this.life <= 0 then puts( "[" + this.name + " has died.]" )..
|
88
|
+
|
89
|
+
# This method takes one turn in a fight.
|
90
|
+
fight: enemy, weapon =>
|
91
|
+
if this.life <= 0 then return puts( "[" + this.name + "is too dead to fight!]" ).
|
92
|
+
|
93
|
+
# Attack the opponent.
|
94
|
+
your_hit: Math.rand( this.strength + weapon )
|
95
|
+
puts( "[You hit with " + your_hit + "points of damage!]" )
|
96
|
+
enemy.hit( your_hit )
|
97
|
+
|
98
|
+
# Retaliation.
|
99
|
+
puts( enemy )
|
100
|
+
if enemy.life > 0
|
101
|
+
enemy_hit: Math.rand( enemy.strength + enemy.weapon )
|
102
|
+
puts( "[Your enemy hit with " + enemy_hit + "points of damage!]" )
|
103
|
+
this.hit( enemy_hit )..
|
104
|
+
|
105
|
+
}
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
# # Get evil idea and swap in code words
|
110
|
+
# print "Enter your new idea: "
|
111
|
+
# idea = gets
|
112
|
+
# code_words.each do |real, code|
|
113
|
+
# idea.gsub!( real, code )
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# # Save the jibberish to a new file
|
117
|
+
# print "File encoded. Please enter a name for this idea: "
|
118
|
+
# idea_name = gets.strip
|
119
|
+
# File::open( "idea-" + idea_name + ".txt", "w" ) do |f|
|
120
|
+
# f << idea
|
121
|
+
# end
|
122
|
+
|
123
|
+
# Get evil idea and swap in code words
|
124
|
+
print("Enter your new idea: ")
|
125
|
+
idea: gets()
|
126
|
+
code_words.each( real, code => idea.replace(real, code). )
|
127
|
+
|
128
|
+
# Save the jibberish to a new file
|
129
|
+
print("File encoded. Please enter a name for this idea: ")
|
130
|
+
idea_name: gets().strip()
|
131
|
+
File.open("idea-" + idea_name + '.txt', 'w', file => file.write(idea). )
|
132
|
+
|
133
|
+
|
134
|
+
|
135
|
+
# def wipe_mutterings_from( sentence )
|
136
|
+
# unless sentence.respond_to? :include?
|
137
|
+
# raise ArgumentError,
|
138
|
+
# "cannot wipe mutterings from a #{ sentence.class }"
|
139
|
+
# end
|
140
|
+
# while sentence.include? '('
|
141
|
+
# open = sentence.index( '(' )
|
142
|
+
# close = sentence.index( ')', open )
|
143
|
+
# sentence[open..close] = '' if close
|
144
|
+
# end
|
145
|
+
# end
|
146
|
+
|
147
|
+
wipe_mutterings_from: sentence =>
|
148
|
+
throw new Error("cannot wipe mutterings") unless sentence.indexOf
|
149
|
+
while sentence.indexOf('(') >= 0
|
150
|
+
open: sentence.indexOf('(') - 1
|
151
|
+
close: sentence.indexOf(')') + 1
|
152
|
+
sentence: sentence[0, open] + sentence[close, sentence.length].
|
153
|
+
sentence.
|