mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
first draft of array comprehensions, but they stink.
This commit is contained in:
parent
443d710be9
commit
d68a4fca19
5 changed files with 865 additions and 700 deletions
23
code.jaa
23
code.jaa
|
@ -1,5 +1,8 @@
|
|||
# TODO: switch/case statements
|
||||
# Flow: For loops, while loops, etc.
|
||||
# Flow: For loops, etc.
|
||||
# ++ and -- (prefix and postfix)
|
||||
# postfix ifs and unlesses
|
||||
# Fix array comprehensions -- they're mad busted.
|
||||
|
||||
# Functions:
|
||||
square: x => x * x.
|
||||
|
@ -66,4 +69,20 @@ catch error
|
|||
finally
|
||||
clean_up().
|
||||
|
||||
try all_hell_breaks_loose() catch error print(error) finally clean_up().
|
||||
try all_hell_breaks_loose() catch error print(error) finally clean_up().
|
||||
|
||||
# While loops.
|
||||
while demand > supply
|
||||
sell()
|
||||
restock().
|
||||
|
||||
while supply > demand then buy().
|
||||
|
||||
# Unary operators.
|
||||
!!true
|
||||
|
||||
# For loops.
|
||||
foods: ['toast', 'wine', 'cheese']
|
||||
print(item.capitalize()) for item in foods.
|
||||
|
||||
drink(item) for item in foods if item is 'wine'.
|
||||
|
|
52
grammar.y
52
grammar.y
|
@ -8,6 +8,7 @@ token IDENTIFIER PROPERTY_ACCESS
|
|||
token CODE PARAM NEW RETURN
|
||||
token TRY CATCH FINALLY THROW
|
||||
token BREAK CONTINUE
|
||||
token FOR IN WHILE
|
||||
token NEWLINE
|
||||
|
||||
prechigh
|
||||
|
@ -59,6 +60,8 @@ rule
|
|||
| Try
|
||||
| Throw
|
||||
| Return
|
||||
| While
|
||||
| For
|
||||
;
|
||||
|
||||
# All tokens that can terminate an expression
|
||||
|
@ -67,6 +70,12 @@ rule
|
|||
| ";"
|
||||
;
|
||||
|
||||
# All tokens that can serve to begin the second block
|
||||
Then:
|
||||
THEN
|
||||
| Terminator
|
||||
;
|
||||
|
||||
# All hard-coded values
|
||||
Literal:
|
||||
NUMBER { result = LiteralNode.new(val[0]) }
|
||||
|
@ -164,11 +173,18 @@ rule
|
|||
;
|
||||
|
||||
Object:
|
||||
"{" "}" { result = ObjectNode.new([]) }
|
||||
| "{" Terminator "}" { result = ObjectNode.new([]) }
|
||||
| "{" AssignList "}" { result = ObjectNode.new(val[1]) }
|
||||
| "{" Terminator AssignList
|
||||
Terminator "}" { result = ObjectNode.new(val[2]) }
|
||||
ObjectStart ObjectEnd { result = ObjectNode.new([]) }
|
||||
| ObjectStart AssignList ObjectEnd { result = ObjectNode.new(val[1]) }
|
||||
;
|
||||
|
||||
ObjectStart:
|
||||
"{" { result = nil }
|
||||
| "{" "\n" { result = nil }
|
||||
;
|
||||
|
||||
ObjectEnd:
|
||||
"}" { result = nil }
|
||||
| "\n" "}" { result = nil }
|
||||
;
|
||||
|
||||
AssignList:
|
||||
|
@ -185,7 +201,7 @@ rule
|
|||
;
|
||||
|
||||
Invocation:
|
||||
Value "(" ArgList ")" { result = CallNode.new(val[0], val[2]) }
|
||||
Value "(" ArgList ")" { result = CallNode.new(val[0], val[2]) }
|
||||
;
|
||||
|
||||
# An Array.
|
||||
|
@ -203,15 +219,10 @@ rule
|
|||
|
||||
If:
|
||||
IF Expression
|
||||
THEN Expression "." { result = IfNode.new(val[1], val[3]) }
|
||||
| IF Expression Terminator
|
||||
Expressions "." { result = IfNode.new(val[1], val[3]) }
|
||||
Then Expressions "." { result = IfNode.new(val[1], val[3]) }
|
||||
| IF Expression
|
||||
THEN Expression
|
||||
ELSE Expression "." { result = IfNode.new(val[1], val[3], val[5]) }
|
||||
| IF Expression Terminator
|
||||
Expressions Terminator
|
||||
ELSE Expressions "." { result = IfNode.new(val[1], val[3], val[6]) }
|
||||
Then Expressions
|
||||
ELSE Expressions "." { result = IfNode.new(val[1], val[3], val[5]) }
|
||||
;
|
||||
|
||||
Try:
|
||||
|
@ -232,6 +243,19 @@ rule
|
|||
"(" Expressions ")" { result = ParentheticalNode.new(val[1]) }
|
||||
;
|
||||
|
||||
While:
|
||||
WHILE Expression Then
|
||||
Expressions "." { result = WhileNode.new(val[1], val[3]) }
|
||||
;
|
||||
|
||||
For:
|
||||
Expression FOR IDENTIFIER
|
||||
IN Expression "." { result = ForNode.new(val[0], val[2], val[4]) }
|
||||
| Expression FOR IDENTIFIER
|
||||
IN Expression
|
||||
IF Expression "." { result = ForNode.new(IfNode.new(val[6], Nodes.new([val[0]])), val[2], val[4]) }
|
||||
;
|
||||
|
||||
end
|
||||
|
||||
---- header
|
||||
|
|
3
lexer.rb
3
lexer.rb
|
@ -5,7 +5,8 @@ class Lexer
|
|||
"and", "or", "is", "aint", "not",
|
||||
"new", "return",
|
||||
"try", "catch", "finally", "throw",
|
||||
"break", "continue"]
|
||||
"break", "continue",
|
||||
"for", "in", "while"]
|
||||
|
||||
IDENTIFIER = /\A([a-zA-Z$_]\w*)/
|
||||
NUMBER = /\A([0-9]+(\.[0-9]+)?)/
|
||||
|
|
71
nodes.rb
71
nodes.rb
|
@ -17,6 +17,11 @@ end
|
|||
# Collection of nodes each one representing an expression.
|
||||
class Nodes < Node
|
||||
attr_reader :nodes
|
||||
|
||||
def self.wrap(node)
|
||||
node.is_a?(Nodes) ? node : Nodes.new([node])
|
||||
end
|
||||
|
||||
def initialize(nodes)
|
||||
@nodes = nodes
|
||||
end
|
||||
|
@ -26,10 +31,12 @@ class Nodes < Node
|
|||
self
|
||||
end
|
||||
|
||||
# line = node.compile(indent + TAB, {:last => last})
|
||||
# line = "return #{line}" if last
|
||||
# indent + TAB + line + node.line_ending
|
||||
def flatten
|
||||
@nodes.length == 1 ? @nodes.first : self
|
||||
end
|
||||
|
||||
# Fancy to handle pushing down returns recursively to the final lines of
|
||||
# inner statements (to make expressions out of them).
|
||||
def compile(indent='', opts={})
|
||||
@nodes.map { |n|
|
||||
if opts[:return] && n == @nodes.last
|
||||
|
@ -63,7 +70,7 @@ class ReturnNode < Node
|
|||
end
|
||||
|
||||
def compile(indent, opts={})
|
||||
"#{indent}return #{@expression.compile(indent)};"
|
||||
"return #{@expression.compile(indent)}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -170,6 +177,7 @@ class OpNode < Node
|
|||
|
||||
def compile(indent, opts={})
|
||||
return compile_conditional(indent) if CONDITIONALS.include?(@operator)
|
||||
return compile_unary(indent) if unary?
|
||||
op = "#{@first.compile(indent)} #{@operator} #{@second.compile(indent)}"
|
||||
opts[:no_paren] ? op : "(#{op})"
|
||||
end
|
||||
|
@ -179,6 +187,10 @@ class OpNode < Node
|
|||
sym = @operator[0..1]
|
||||
"(#{first} = #{first} #{sym} #{second})"
|
||||
end
|
||||
|
||||
def compile_unary(indent)
|
||||
"#{@operator}#{@first.compile(indent)}"
|
||||
end
|
||||
end
|
||||
|
||||
# Method definition.
|
||||
|
@ -229,7 +241,9 @@ class IfNode < Node
|
|||
FORCE_STATEMENT = [Nodes, ReturnNode]
|
||||
|
||||
def initialize(condition, body, else_body=nil)
|
||||
@condition, @body, @else_body = condition, body, else_body
|
||||
@condition = condition
|
||||
@body = body && body.flatten
|
||||
@else_body = else_body && else_body.flatten
|
||||
end
|
||||
|
||||
def statement?
|
||||
|
@ -245,8 +259,8 @@ class IfNode < Node
|
|||
end
|
||||
|
||||
def compile_statement(indent, opts)
|
||||
if_part = "if (#{@condition.compile(indent, :no_paren => true)}) {\n#{@body.compile(indent + TAB, opts)}\n#{indent}}"
|
||||
else_part = @else_body ? " else {\n#{@else_body.compile(indent + TAB, opts)}\n#{indent}}" : ''
|
||||
if_part = "if (#{@condition.compile(indent, :no_paren => true)}) {\n#{Nodes.wrap(@body).compile(indent + TAB, opts)}\n#{indent}}"
|
||||
else_part = @else_body ? " else {\n#{Nodes.wrap(@else_body).compile(indent + TAB, opts)}\n#{indent}}" : ''
|
||||
if_part + else_part
|
||||
end
|
||||
|
||||
|
@ -257,6 +271,49 @@ class IfNode < Node
|
|||
end
|
||||
end
|
||||
|
||||
class WhileNode < Node
|
||||
def initialize(condition, body)
|
||||
@condition, @body = condition, body
|
||||
end
|
||||
|
||||
def line_ending
|
||||
''
|
||||
end
|
||||
|
||||
def statement?
|
||||
true
|
||||
end
|
||||
|
||||
def compile(indent, opts={})
|
||||
"while (#{@condition.compile(indent, :no_paren => true)}) {\n#{@body.compile(indent + TAB)}\n#{indent}}"
|
||||
end
|
||||
end
|
||||
|
||||
class ForNode < Node
|
||||
I = "__i__"
|
||||
L = "__l__"
|
||||
S = "__s__"
|
||||
|
||||
def initialize(body, name, source, condition=nil)
|
||||
@body, @name, @source, @condition = body, name, source, condition
|
||||
end
|
||||
|
||||
def line_ending
|
||||
''
|
||||
end
|
||||
|
||||
def statement?
|
||||
true
|
||||
end
|
||||
|
||||
def compile(indent, opts={})
|
||||
source_part = "var #{S} = #{@source.compile(indent)};"
|
||||
for_part = "var #{I}=0, #{L}=#{S}.length; #{I}<#{L}; #{I}++"
|
||||
var_part = "\n#{indent + TAB}var #{@name} = #{S}[#{I}];"
|
||||
"#{source_part}\n#{indent}for (#{for_part}) {#{var_part}\n#{indent + TAB}#{@body.compile(indent + TAB)};\n#{indent}}"
|
||||
end
|
||||
end
|
||||
|
||||
class TryNode < Node
|
||||
def initialize(try, error, recovery, finally=nil)
|
||||
@try, @error, @recovery, @finally = try, error, recovery, finally
|
||||
|
|
Loading…
Reference in a new issue