@@ -79,7 +79,17 @@ exports.Base = class Base
79
79
if jumpNode = @ jumps ()
80
80
jumpNode .error ' cannot use a pure statement in an expression'
81
81
o .sharedScope = yes
82
- Closure .wrap (this ).compileNode o
82
+ func = new Code [], Block .wrap [this ]
83
+ args = []
84
+ if (argumentsNode = @ contains isLiteralArguments) or @ contains isLiteralThis
85
+ args = [new Literal ' this' ]
86
+ if argumentsNode
87
+ meth = ' apply'
88
+ args .push new Literal ' arguments'
89
+ else
90
+ meth = ' call'
91
+ func = new Value func, [new Access new Literal meth]
92
+ (new Call func, args).compileNode o
83
93
84
94
# If the code generation wishes to use the result of a complex expression
85
95
# in multiple places, ensure that the expression is only ever evaluated once,
@@ -848,7 +858,7 @@ exports.Range = class Range extends Base
848
858
cond = " #{ @fromVar } <= #{ @toVar } "
849
859
body = " var #{ vars} ; #{ cond} ? #{ i} <#{ @equals } #{ @toVar } : #{ i} >#{ @equals } #{ @toVar } ; #{ cond} ? #{ i} ++ : #{ i} --"
850
860
post = " { #{ result} .push(#{ i} ); }\n #{ idt} return #{ result} ;\n #{ o .indent } "
851
- hasArgs = (node ) -> node ? .contains (n) -> n instanceof Literal and n . value is ' arguments ' and not n . asKey
861
+ hasArgs = (node ) -> node ? .contains isLiteralArguments
852
862
args = ' , arguments' if hasArgs (@from ) or hasArgs (@to )
853
863
[@ makeCode " (function() {#{ pre} \n #{ idt} for (#{ body} )#{ post} }).apply(this#{ args ? ' ' } )" ]
854
864
@@ -1021,7 +1031,7 @@ exports.Class = class Class extends Base
1021
1031
if func instanceof Code
1022
1032
assign = @ctor = func
1023
1033
else
1024
- @externalCtor = o .scope .freeVariable ' class'
1034
+ @externalCtor = o .classScope .freeVariable ' class'
1025
1035
assign = new Assign new Literal (@externalCtor ), func
1026
1036
else
1027
1037
if assign .variable .this
@@ -1078,31 +1088,35 @@ exports.Class = class Class extends Base
1078
1088
# equivalent syntax tree and compile that, in pieces. You can see the
1079
1089
# constructor, property assignments, and inheritance getting built out below.
1080
1090
compileNode : (o ) ->
1091
+ if jumpNode = @body .jumps ()
1092
+ jumpNode .error ' Class bodies cannot contain pure statements'
1093
+ if argumentsNode = @body .contains isLiteralArguments
1094
+ argumentsNode .error " Class bodies shouldn't reference arguments"
1095
+
1081
1096
name = @ determineName () or ' _Class'
1082
- name = " _#{ name} " if name .reserved
1097
+ name = " _#{ name} " if name .reserved
1083
1098
lname = new Literal name
1099
+ func = new Code [], Block .wrap [@body ]
1100
+ args = []
1101
+ o .classScope = func .makeScope o .scope
1084
1102
1085
1103
@ hoistDirectivePrologue ()
1086
1104
@ setContext name
1087
1105
@ walkBody name, o
1088
1106
@ ensureConstructor name
1089
1107
@ addBoundFunctions o
1090
1108
@body .spaced = yes
1091
- @body .expressions .unshift @ctor unless @ctor instanceof Code
1092
1109
@body .expressions .push lname
1093
1110
1094
- call = Closure .wrap @body
1095
-
1096
- if @parent and call .args
1097
- @superClass = new Literal o .scope .freeVariable ' super' , no
1098
- @body .expressions .unshift new Extends lname, @superClass
1099
- call .args .push @parent
1100
- params = call .variable .params or call .variable .base .params
1101
- params .push new Param @superClass
1111
+ if @parent
1112
+ superClass = new Literal o .classScope .freeVariable ' super' , no
1113
+ @body .expressions .unshift new Extends lname, superClass
1114
+ func .params .push new Param superClass
1115
+ args .push @parent
1102
1116
1103
1117
@body .expressions .unshift @directives ...
1104
1118
1105
- klass = new Parens call, yes
1119
+ klass = new Parens new Call func, args
1106
1120
klass = new Assign @variable , klass if @variable
1107
1121
klass .compileToFragments o
1108
1122
@@ -1291,6 +1305,8 @@ exports.Code = class Code extends Base
1291
1305
1292
1306
jumps : NO
1293
1307
1308
+ makeScope : (parentScope ) -> new Scope parentScope, @body , this
1309
+
1294
1310
# Compilation creates a new scope unless explicitly asked to share with the
1295
1311
# outer scope. Handles splat parameters in the parameter list by peeking at
1296
1312
# the JavaScript `arguments` object. If the function is bound with the `=>`
@@ -1306,7 +1322,7 @@ exports.Code = class Code extends Base
1306
1322
boundfunc .updateLocationDataIfMissing @locationData
1307
1323
return boundfunc .compileNode (o)
1308
1324
1309
- o .scope = new Scope o . scope , @body , this
1325
+ o .scope = del (o, ' classScope ' ) or @ makeScope o . scope
1310
1326
o .scope .shared = del (o, ' sharedScope' )
1311
1327
o .indent += TAB
1312
1328
delete o .bare
@@ -2080,50 +2096,6 @@ exports.If = class If extends Base
2080
2096
unfoldSoak : ->
2081
2097
@soak and this
2082
2098
2083
- # Faux-Nodes
2084
- # ----------
2085
- # Faux-nodes are never created by the grammar, but are used during code
2086
- # generation to generate other combinations of nodes.
2087
-
2088
- # ### Closure
2089
-
2090
- # A faux-node used to wrap an expressions body in a closure.
2091
- Closure =
2092
-
2093
- # Wrap the expressions body, unless it contains a pure statement,
2094
- # in which case, no dice. If the body mentions `this` or `arguments`,
2095
- # then make sure that the closure wrapper preserves the original values.
2096
- wrap : (expressions , statement , noReturn ) ->
2097
- return expressions if expressions .jumps ()
2098
- func = new Code [], Block .wrap [expressions]
2099
- args = []
2100
- argumentsNode = expressions .contains @isLiteralArguments
2101
- if argumentsNode and expressions .classBody
2102
- argumentsNode .error " Class bodies shouldn't reference arguments"
2103
- if argumentsNode or expressions .contains @isLiteralThis
2104
- meth = new Literal if argumentsNode then ' apply' else ' call'
2105
- args = [new Literal ' this' ]
2106
- args .push new Literal ' arguments' if argumentsNode
2107
- func = new Value func, [new Access meth]
2108
- func .noReturn = noReturn
2109
- call = new Call func, args
2110
- if statement then Block .wrap [call] else call
2111
-
2112
- isLiteralArguments : (node ) ->
2113
- node instanceof Literal and node .value is ' arguments' and not node .asKey
2114
-
2115
- isLiteralThis : (node ) ->
2116
- (node instanceof Literal and node .value is ' this' and not node .asKey ) or
2117
- (node instanceof Code and node .bound ) or
2118
- (node instanceof Call and node .isSuper )
2119
-
2120
- # Unfold a node's child if soak, then tuck the node under created `If`
2121
- unfoldSoak = (o , parent , name ) ->
2122
- return unless ifn = parent[name].unfoldSoak o
2123
- parent[name] = ifn .body
2124
- ifn .body = new Value parent
2125
- ifn
2126
-
2127
2099
# Constants
2128
2100
# ---------
2129
2101
@@ -2190,8 +2162,8 @@ METHOD_DEF = ///
2190
2162
IS_STRING = / ^ ['"] /
2191
2163
IS_REGEX = / ^ \/ /
2192
2164
2193
- # Utility Functions
2194
- # -----------------
2165
+ # Helper Functions
2166
+ # ----------------
2195
2167
2196
2168
# Helper for ensuring that utility functions are assigned at the top level.
2197
2169
utility = (name ) ->
@@ -2212,3 +2184,18 @@ parseNum = (x) ->
2212
2184
parseInt x, 16
2213
2185
else
2214
2186
parseFloat x
2187
+
2188
+ isLiteralArguments = (node ) ->
2189
+ node instanceof Literal and node .value is ' arguments' and not node .asKey
2190
+
2191
+ isLiteralThis = (node ) ->
2192
+ (node instanceof Literal and node .value is ' this' and not node .asKey ) or
2193
+ (node instanceof Code and node .bound ) or
2194
+ (node instanceof Call and node .isSuper )
2195
+
2196
+ # Unfold a node's child if soak, then tuck the node under created `If`
2197
+ unfoldSoak = (o , parent , name ) ->
2198
+ return unless ifn = parent[name].unfoldSoak o
2199
+ parent[name] = ifn .body
2200
+ ifn .body = new Value parent
2201
+ ifn
0 commit comments