1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

added the ability to super()

This commit is contained in:
Jeremy Ashkenas 2009-12-17 09:07:42 -05:00
parent 1a8311b9d0
commit 1d35910567
5 changed files with 57 additions and 15 deletions

2
TODO
View file

@ -1,5 +1,7 @@
TODO:
* Super in methods. (reserve it).
* Need *way* better syntax errors.
* Is it possible to close blocks (functions, ifs, trys) without an explicit

View file

@ -128,4 +128,12 @@ three_to_six: zero_to_nine[3, 6]
# Multiline strings with inner quotes.
story: "Lorem ipsum dolor \"sit\" amet, consectetuer adipiscing elit,
sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna
aliquam erat volutpat. Ut wisi enim ad."
aliquam erat volutpat. Ut wisi enim ad."
# Calling super from an overridden method.
Greeter: => . # Create the parent object.
Greeter.prototype.hello: name => alert('Hello ' + name). # Define a "hello" method.
Exclaimer: name => this.name: name. # Create the child object.
Exclaimer.prototype: new Greeter() # Set the child to inherit from the parent.
Exclaimer.prototype.hello: => super(this.name + "!"). # The child's "hello" calls the parent's via "super".
(new Exclaimer('Bob')).hello() # Run it.

View file

@ -10,6 +10,7 @@ token TRY CATCH FINALLY THROW
token BREAK CONTINUE
token FOR IN WHILE
token SWITCH CASE DEFAULT
token SUPER
token NEWLINE
token JS
@ -149,10 +150,16 @@ rule
# Method definition
Code:
ParamList "=>" Expressions "." { result = CodeNode.new(val[0], val[2]) }
| "=>" Expressions "." { result = CodeNode.new([], val[1]) }
ParamList "=>" CodeBody "." { result = CodeNode.new(val[0], val[2]) }
| "=>" CodeBody "." { result = CodeNode.new([], val[1]) }
;
CodeBody:
/* nothing */ { result = Nodes.new([]) }
| Expressions { result = val[0] }
;
ParamList:
PARAM { result = val }
| ParamList "," PARAM { result = val[0] << val[2] }
@ -196,12 +203,17 @@ rule
Call:
Invocation { result = val[0] }
| NEW Invocation { result = val[1].new_instance }
| Super { result = val[0] }
;
Invocation:
Value "(" ArgList ")" { result = CallNode.new(val[0], val[2]) }
;
Super:
SUPER "(" ArgList ")" { result = CallNode.new(:super, val[2]) }
;
# An Array.
Array:
"[" ArgList "]" { result = ArrayNode.new(val[1]) }

View file

@ -7,7 +7,8 @@ class Lexer
"try", "catch", "finally", "throw",
"break", "continue",
"for", "in", "while",
"switch", "case", "default"]
"switch", "case", "default",
"super"]
IDENTIFIER = /\A([a-zA-Z$_]\w*)/
NUMBER = /\A([0-9]+(\.[0-9]+)?)/

View file

@ -122,6 +122,8 @@ end
# receiver.method(argument1, argument2)
#
class CallNode < Node
LEADING_DOT = /\A\./
def initialize(variable, arguments=[])
@variable, @arguments = variable, arguments
end
@ -131,14 +133,26 @@ class CallNode < Node
self
end
def super?
@variable == :super
end
def compile(indent, scope, opts={})
args = @arguments.map{|a| a.compile(indent, scope, :no_paren => true) }.join(', ')
return compile_super(args, indent, scope, opts) if super?
prefix = @new ? "new " : ''
"#{prefix}#{@variable.compile(indent, scope)}(#{args})"
end
def compile_super(args, indent, scope, opts)
methname = opts[:last_assign].sub(LEADING_DOT, '')
"this.constructor.prototype.#{methname}.call(this, #{args})"
end
end
class ValueNode < Node
attr_reader :last
def initialize(name, properties=[])
@name, @properties = name, properties
end
@ -153,9 +167,11 @@ class ValueNode < Node
end
def compile(indent, scope, opts={})
[@name, @properties].flatten.map { |v|
parts = [@name, @properties].flatten.map do |v|
v.respond_to?(:compile) ? v.compile(indent, scope) : v.to_s
}.join('')
end
@last = parts.last
parts.join('')
end
end
@ -200,16 +216,18 @@ class AssignNode < Node
end
def compile(indent, scope, opts={})
value = @value.compile(indent + TAB, scope)
name = @variable.compile(indent, scope) if @variable.respond_to?(:compile)
last = @variable.respond_to?(:last) ? @variable.last : name
opts = opts.merge({:assign => name, :last_assign => last})
value = @value.compile(indent, scope, opts)
return "#{@variable}: #{value}" if @context == :object
name = @variable.compile(indent, scope)
return "#{name} = #{value}" if @variable.properties?
defined = scope.find(name)
postfix = !defined && opts[:return] ? ";\n#{indent}return #{name}" : ''
def_part = defined ? "" : "var #{name};\n#{indent}"
return def_part + @value.compile(indent, scope, opts.merge(:assign => name)) if @value.custom_assign?
def_part = defined ? name : "var #{name}"
"#{def_part} = #{@value.compile(indent, scope)}#{postfix}"
defined = scope.find(name)
postfix = !defined && opts[:return] ? ";\n#{indent}return #{name}" : ''
def_part = defined ? "" : "var #{name};\n#{indent}"
return def_part + @value.compile(indent, scope, opts) if @value.custom_assign?
def_part = defined ? name : "var #{name}"
"#{def_part} = #{@value.compile(indent, scope, opts)}#{postfix}"
end
end
@ -260,7 +278,8 @@ class CodeNode < Node
end
def compile(indent, scope, opts={})
code = @body.compile(indent + TAB, Scope.new(scope), {:return => true})
opts = opts.merge(:return => true)
code = @body.compile(indent + TAB, Scope.new(scope), opts)
"function(#{@params.join(', ')}) {\n#{code}\n#{indent}}"
end
end