mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-02-18 11:31:20 -05:00
refactoring and commenting nodes.rb Expressions
This commit is contained in:
@@ -41,7 +41,7 @@ module CoffeeScript
|
|||||||
"(function() {\n#{compile_node(o.merge(:return => true))}\n#{indent}})()"
|
"(function() {\n#{compile_node(o.merge(:return => true))}\n#{indent}})()"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Quick method for the current indentation level, plus tabs out.
|
# Quick short method for the current indentation level, plus tabbing in.
|
||||||
def idt(tabs=0)
|
def idt(tabs=0)
|
||||||
@indent + (TAB * tabs)
|
@indent + (TAB * tabs)
|
||||||
end
|
end
|
||||||
@@ -57,7 +57,8 @@ module CoffeeScript
|
|||||||
statement
|
statement
|
||||||
attr_reader :expressions
|
attr_reader :expressions
|
||||||
|
|
||||||
STRIP_TRAILING_WHITESPACE = /\s+$/
|
TRAILING_WHITESPACE = /\s+$/
|
||||||
|
UPPERCASE = /[A-Z]/
|
||||||
|
|
||||||
# Wrap up a node as an Expressions, unless it already is.
|
# Wrap up a node as an Expressions, unless it already is.
|
||||||
def self.wrap(*nodes)
|
def self.wrap(*nodes)
|
||||||
@@ -69,12 +70,13 @@ module CoffeeScript
|
|||||||
@expressions = nodes.flatten
|
@expressions = nodes.flatten
|
||||||
end
|
end
|
||||||
|
|
||||||
# Tack an expression onto the end of this node.
|
# Tack an expression on to the end of this expression list.
|
||||||
def <<(node)
|
def <<(node)
|
||||||
@expressions << node
|
@expressions << node
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Tack an expression on to the beginning of this expression list.
|
||||||
def unshift(node)
|
def unshift(node)
|
||||||
@expressions.unshift(node)
|
@expressions.unshift(node)
|
||||||
self
|
self
|
||||||
@@ -91,36 +93,19 @@ module CoffeeScript
|
|||||||
node == @expressions[@last_index]
|
node == @expressions[@last_index]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Determine if this is the expressions body within a constructor function.
|
||||||
|
# Constructors are capitalized by CoffeeScript convention.
|
||||||
|
def constructor?(o)
|
||||||
|
o[:top] && o[:last_assign] && o[:last_assign][0..0][UPPERCASE]
|
||||||
|
end
|
||||||
|
|
||||||
def compile(o={})
|
def compile(o={})
|
||||||
o[:scope] ? super(o) : compile_root(o)
|
o[:scope] ? super(o) : compile_root(o)
|
||||||
end
|
end
|
||||||
|
|
||||||
# The extra fancy is to handle pushing down returns to the final lines of
|
# Compile each expression in the Expressions body.
|
||||||
# inner statements. Variables first defined within the Expressions body
|
|
||||||
# have their declarations pushed up top of the closest scope.
|
|
||||||
def compile_node(options={})
|
def compile_node(options={})
|
||||||
compiled = @expressions.map do |node|
|
write(@expressions.map {|n| compile_expression(n, options.dup) }.join("\n"))
|
||||||
o = options.dup
|
|
||||||
@indent = o[:indent]
|
|
||||||
returns = o.delete(:return)
|
|
||||||
if last?(node) && returns && !node.statement_only?
|
|
||||||
if node.statement?
|
|
||||||
node.compile(o.merge(:return => true))
|
|
||||||
else
|
|
||||||
if o[:top] && o[:last_assign] && o[:last_assign][0..0][/[A-Z]/]
|
|
||||||
temp = o[:scope].free_variable
|
|
||||||
"#{idt}#{temp} = #{node.compile(o)};\n#{idt}return #{o[:last_assign]} === this.constructor ? this : #{temp};"
|
|
||||||
else
|
|
||||||
"#{idt}return #{node.compile(o)};"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
ending = node.statement? ? '' : ';'
|
|
||||||
indent = node.statement? ? '' : idt
|
|
||||||
"#{indent}#{node.compile(o.merge(:top => true))}#{ending}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
write(compiled.join("\n"))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# If this is the top-level Expressions, wrap everything in a safety closure.
|
# If this is the top-level Expressions, wrap everything in a safety closure.
|
||||||
@@ -129,7 +114,7 @@ module CoffeeScript
|
|||||||
@indent = indent
|
@indent = indent
|
||||||
o.merge!(:indent => indent, :scope => Scope.new(nil, self))
|
o.merge!(:indent => indent, :scope => Scope.new(nil, self))
|
||||||
code = o[:globals] ? compile_node(o) : compile_with_declarations(o)
|
code = o[:globals] ? compile_node(o) : compile_with_declarations(o)
|
||||||
code.gsub!(STRIP_TRAILING_WHITESPACE, '')
|
code.gsub!(TRAILING_WHITESPACE, '')
|
||||||
o[:no_wrap] ? code : "(function(){\n#{code}\n})();"
|
o[:no_wrap] ? code : "(function(){\n#{code}\n})();"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -140,19 +125,39 @@ module CoffeeScript
|
|||||||
decls + code
|
decls + code
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def compile_expression(node, o)
|
||||||
|
@indent = o[:indent]
|
||||||
|
stmt = node.statement?
|
||||||
|
# We need to return the result if this is the last node in the expressions body.
|
||||||
|
returns = o.delete(:return) && last?(node) && !node.statement_only?
|
||||||
|
# Return the regular compile of the node, unless we need to return the result.
|
||||||
|
return "#{stmt ? '' : idt}#{node.compile(o.merge(:top => true))}#{stmt ? '' : ';'}" unless returns
|
||||||
|
# If it's a statement, the node knows how to return itself.
|
||||||
|
return node.compile(o.merge(:return => true)) if node.statement?
|
||||||
|
# If it's not part of a constructor, we can just return the value of the expression.
|
||||||
|
return "#{idt}return #{node.compile(o)};" unless constructor?(o)
|
||||||
|
# It's the last line of a constructor, add a safety check.
|
||||||
|
temp = o[:scope].free_variable
|
||||||
|
"#{idt}#{temp} = #{node.compile(o)};\n#{idt}return #{o[:last_assign]} === this.constructor ? this : #{temp};"
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Literals are static values that have a Ruby representation, eg.: a string, a number,
|
# Literals are static values that have a Ruby representation, eg.: a string, a number,
|
||||||
# true, false, nil, etc.
|
# true, false, nil, etc.
|
||||||
class LiteralNode < Node
|
class LiteralNode < Node
|
||||||
|
|
||||||
|
# Values of a literal node that much be treated as a statement -- no
|
||||||
|
# sense returning or assigning them.
|
||||||
STATEMENTS = ['break', 'continue']
|
STATEMENTS = ['break', 'continue']
|
||||||
|
|
||||||
CONVERSIONS = {
|
# If we get handed a literal reference to an arguments object, convert
|
||||||
'arguments' => 'Array.prototype.slice.call(arguments, 0)'
|
# it to an array.
|
||||||
}
|
ARG_ARRAY = 'Array.prototype.slice.call(arguments, 0)'
|
||||||
|
|
||||||
attr_reader :value
|
attr_reader :value
|
||||||
|
|
||||||
|
# Wrap up a compiler-generated string as a LiteralNode.
|
||||||
def self.wrap(string)
|
def self.wrap(string)
|
||||||
self.new(Value.new(string))
|
self.new(Value.new(string))
|
||||||
end
|
end
|
||||||
@@ -167,14 +172,14 @@ module CoffeeScript
|
|||||||
alias_method :statement_only?, :statement?
|
alias_method :statement_only?, :statement?
|
||||||
|
|
||||||
def compile_node(o)
|
def compile_node(o)
|
||||||
val = CONVERSIONS[@value.to_s] || @value.to_s
|
@value = ARG_ARRAY if @value.to_s.to_sym == :arguments
|
||||||
indent = statement? ? idt : ''
|
indent = statement? ? idt : ''
|
||||||
ending = statement? ? ';' : ''
|
ending = statement? ? ';' : ''
|
||||||
write("#{indent}#{val}#{ending}")
|
write "#{indent}#{@value}#{ending}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Try to return your expression, or tell it to return itself.
|
# Return an expression, or wrap it in a closure and return it.
|
||||||
class ReturnNode < Node
|
class ReturnNode < Node
|
||||||
statement_only
|
statement_only
|
||||||
|
|
||||||
@@ -657,8 +662,7 @@ module CoffeeScript
|
|||||||
else
|
else
|
||||||
index_var = nil
|
index_var = nil
|
||||||
source_part = "#{svar} = #{source.compile(o)};\n#{idt}"
|
source_part = "#{svar} = #{source.compile(o)};\n#{idt}"
|
||||||
for_part = "#{ivar}=0; #{ivar}<#{svar}.length; #{ivar}++"
|
for_part = @object ? "#{ivar} in #{svar}" : "#{ivar}=0; #{ivar}<#{svar}.length; #{ivar}++"
|
||||||
for_part = "#{ivar} in #{svar}" if @object
|
|
||||||
var_part = @name ? "#{body_dent}#{@name} = #{svar}[#{ivar}];\n" : ''
|
var_part = @name ? "#{body_dent}#{@name} = #{svar}[#{ivar}];\n" : ''
|
||||||
end
|
end
|
||||||
body = @body
|
body = @body
|
||||||
|
|||||||
Reference in New Issue
Block a user