1 | {map, concat, concatMap, difference, nub, union} = require './functional-helpers'
|
2 | exports = module?.exports ? this
|
3 |
|
4 |
|
5 |
|
6 | createNodes = (subclasses, superclasses = []) ->
|
7 | for own className, specs of subclasses then do (className) ->
|
8 |
|
9 | superclass = superclasses[0] ? ->
|
10 | isCategory = specs? and specs.length is 2
|
11 | params =
|
12 | if specs?
|
13 | switch specs.length
|
14 | when 0 then []
|
15 | when 1, 2 then specs[0]
|
16 | else null
|
17 | params ?= superclass::childNodes ? []
|
18 |
|
19 | klass = class extends superclass
|
20 | constructor:
|
21 | if isCategory then ->
|
22 | else ->
|
23 | for param, i in params
|
24 | @[param] = arguments[i]
|
25 | if @initialise?
|
26 | @initialise.apply this, arguments
|
27 | this
|
28 | className: className
|
29 | @superclasses = superclasses
|
30 | if specs?[0]? then klass::childNodes = specs[0]
|
31 |
|
32 | if isCategory then createNodes specs[1], [klass, superclasses...]
|
33 | exports[className] = klass
|
34 |
|
35 | return
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | createNodes
|
42 | Nodes: [
|
43 | []
|
44 | BinOps: [
|
45 | ['left', 'right']
|
46 | AssignOps: [
|
47 | ['assignee', 'expression']
|
48 | AssignOp: null
|
49 | ClassProtoAssignOp: null
|
50 | CompoundAssignOp: [['op', 'assignee', 'expression']]
|
51 | ]
|
52 | BitOps: [
|
53 | null
|
54 | BitAndOp: null
|
55 | BitOrOp: null
|
56 | BitXorOp: null
|
57 | LeftShiftOp: null
|
58 | SignedRightShiftOp: null
|
59 | UnsignedRightShiftOp: null
|
60 | ]
|
61 | ComparisonOps: [
|
62 | null
|
63 | EQOp: null
|
64 | GTEOp: null
|
65 | GTOp: null
|
66 | LTEOp: null
|
67 | LTOp: null
|
68 | NEQOp: null
|
69 | ]
|
70 |
|
71 | ConcatOp: null
|
72 | ExistsOp: null
|
73 | ExtendsOp: null
|
74 | InOp: null
|
75 | InstanceofOp: null
|
76 | LogicalOps: [
|
77 | null
|
78 | LogicalAndOp: null
|
79 | LogicalOrOp: null
|
80 | ]
|
81 | MathsOps: [
|
82 | null
|
83 | ExpOp: null
|
84 | DivideOp: null
|
85 | MultiplyOp: null
|
86 | RemOp: null
|
87 | SubtractOp: null
|
88 | ]
|
89 | OfOp: null
|
90 | PlusOp: null
|
91 | Range: [['isInclusive', 'left', 'right']]
|
92 | SeqOp: null
|
93 | ]
|
94 |
|
95 | Statements: [
|
96 | []
|
97 | Break: null
|
98 | Continue: null
|
99 | Debugger: null
|
100 | Return: [['expression']]
|
101 | Throw: [['expression']]
|
102 | ]
|
103 |
|
104 | UnaryOps: [
|
105 | ['expression']
|
106 | BitNotOp: null
|
107 | DeleteOp: null
|
108 | DoOp: null
|
109 | LogicalNotOp: null
|
110 | NewOp: [['ctor', 'arguments']]
|
111 | PreDecrementOp: null
|
112 | PreIncrementOp: null
|
113 | PostDecrementOp: null
|
114 | PostIncrementOp: null
|
115 | TypeofOp: null
|
116 | UnaryExistsOp: null
|
117 | UnaryNegateOp: null
|
118 | UnaryPlusOp: null
|
119 | ]
|
120 |
|
121 | MemberAccessOps: [
|
122 | null
|
123 | StaticMemberAccessOps: [
|
124 | ['expression', 'memberName']
|
125 | MemberAccessOp: null
|
126 | ProtoMemberAccessOp: null
|
127 | SoakedMemberAccessOp: null
|
128 | SoakedProtoMemberAccessOp: null
|
129 | ]
|
130 | DynamicMemberAccessOps: [
|
131 | ['expression', 'indexingExpr']
|
132 | DynamicMemberAccessOp: null
|
133 | DynamicProtoMemberAccessOp: null
|
134 | SoakedDynamicMemberAccessOp: null
|
135 | SoakedDynamicProtoMemberAccessOp: null
|
136 | ]
|
137 | ]
|
138 |
|
139 | ChainedComparisonOp: [['expression']]
|
140 |
|
141 | FunctionApplications: [
|
142 | ['function', 'arguments']
|
143 | FunctionApplication: null
|
144 | SoakedFunctionApplication: null
|
145 | ]
|
146 | Super: [['arguments']]
|
147 |
|
148 | Program: [['body']]
|
149 | Block: [['statements']]
|
150 | Conditional: [['condition', 'consequent', 'alternate']]
|
151 | ForIn: [['valAssignee', 'keyAssignee', 'target', 'step', 'filter', 'body']]
|
152 | ForOf: [['isOwn', 'keyAssignee', 'valAssignee', 'target', 'filter', 'body']]
|
153 | Switch: [['expression', 'cases', 'alternate']]
|
154 | SwitchCase: [['conditions', 'consequent']]
|
155 | Try: [['body', 'catchAssignee', 'catchBody', 'finallyBody']]
|
156 | While: [['condition', 'body']]
|
157 |
|
158 | ArrayInitialiser: [['members']]
|
159 | ObjectInitialiser: [['members']]
|
160 | ObjectInitialiserMember: [['key', 'expression']]
|
161 | Class: [['nameAssignee', 'parent', 'ctor', 'body', 'boundMembers']]
|
162 | Constructor: [['expression']]
|
163 | Functions: [
|
164 | ['parameters', 'body']
|
165 | Function: null
|
166 | BoundFunction: null
|
167 | ]
|
168 | DefaultParam: [['param', 'default']]
|
169 | Identifiers: [
|
170 | ['data']
|
171 | Identifier: null
|
172 | GenSym: null
|
173 | ]
|
174 | Null: null
|
175 | Primitives: [
|
176 | ['data']
|
177 | Bool: null
|
178 | JavaScript: null
|
179 | Numbers: [
|
180 | null
|
181 | Int: null
|
182 | Float: null
|
183 | ]
|
184 | String: null
|
185 | ]
|
186 | RegExps: [
|
187 | null
|
188 | RegExp: [['data', 'flags']]
|
189 | HeregExp: [['expression', 'flags']]
|
190 | ]
|
191 | This: null
|
192 | Undefined: null
|
193 |
|
194 | Slice: [['expression', 'isInclusive', 'left', 'right']]
|
195 |
|
196 | Rest: [['expression']]
|
197 | Spread: [['expression']]
|
198 | ]
|
199 |
|
200 |
|
201 | {
|
202 | Nodes, Primitives, CompoundAssignOp, StaticMemberAccessOps, Range,
|
203 | ArrayInitialiser, ObjectInitialiser, NegatedConditional, Conditional,
|
204 | Identifier, ForOf, Functions, While, Class, Block, NewOp, Bool,
|
205 | FunctionApplications, RegExps, RegExp, HeregExp, Super, Slice, Switch,
|
206 | Identifiers, SwitchCase, GenSym
|
207 | } = exports
|
208 |
|
209 |
|
210 | Nodes.fromJSON = (json) -> exports[json.type].fromJSON json
|
211 | Nodes::listMembers = []
|
212 | Nodes::toJSON = ->
|
213 | json = { type: @className }
|
214 | if @line? then json.line = @line
|
215 | if @column? then json.column = @column
|
216 | if @raw?
|
217 | json.raw = @raw
|
218 | if @offset?
|
219 | json.range = [
|
220 | @offset
|
221 | @offset + @raw.length
|
222 | ]
|
223 | for child in @childNodes
|
224 | if child in @listMembers
|
225 | json[child] = (p.toJSON() for p in @[child])
|
226 | else
|
227 | json[child] = if @[child]? then @[child].toJSON()
|
228 | json
|
229 | Nodes::fold = (memo, fn) ->
|
230 | for child in @childNodes
|
231 | if child in @listMembers
|
232 | memo = (p.fold memo, fn for p in @[child])
|
233 | else
|
234 | memo = @[child].fold memo, fn
|
235 | fn memo, this
|
236 | Nodes::clone = ->
|
237 | ctor = ->
|
238 | ctor.prototype = @constructor.prototype
|
239 | n = new ctor
|
240 | n[k] = v for own k, v of this
|
241 | n
|
242 | Nodes::instanceof = (ctors...) ->
|
243 |
|
244 | superclasses = map @constructor.superclasses, (c) -> c::className
|
245 | for ctor in ctors when ctor::className in [@className, superclasses...]
|
246 | return yes
|
247 | no
|
248 | Nodes::r = (@raw) -> this
|
249 | Nodes::p = (@line, @column, @offset) -> this
|
250 | Nodes::generated = no
|
251 | Nodes::g = ->
|
252 | @generated = yes
|
253 | this
|
254 |
|
255 |
|
256 |
|
257 |
|
258 | handlePrimitives = (ctor, primitives...) ->
|
259 | ctor::childNodes = difference ctor::childNodes, primitives
|
260 | ctor::toJSON = ->
|
261 | json = Nodes::toJSON.call this
|
262 | for primitive in primitives
|
263 | json[primitive] = @[primitive]
|
264 | json
|
265 |
|
266 | handlePrimitives Class, 'boundMembers'
|
267 | handlePrimitives CompoundAssignOp, 'op'
|
268 | handlePrimitives ForOf, 'isOwn'
|
269 | handlePrimitives HeregExp, 'flags'
|
270 | handlePrimitives Identifiers, 'data'
|
271 | handlePrimitives Primitives, 'data'
|
272 | handlePrimitives Range, 'isInclusive'
|
273 | handlePrimitives RegExp, 'data', 'flags'
|
274 | handlePrimitives Slice, 'isInclusive'
|
275 | handlePrimitives StaticMemberAccessOps, 'memberName'
|
276 |
|
277 |
|
278 |
|
279 |
|
280 | handleLists = (ctor, listProps...) -> ctor::listMembers = listProps
|
281 |
|
282 | handleLists ArrayInitialiser, 'members'
|
283 | handleLists Block, 'statements'
|
284 | handleLists Functions, 'parameters'
|
285 | handleLists FunctionApplications, 'arguments'
|
286 | handleLists NewOp, 'arguments'
|
287 | handleLists ObjectInitialiser, 'members'
|
288 | handleLists Super, 'arguments'
|
289 | handleLists Switch, 'cases'
|
290 | handleLists SwitchCase, 'conditions'
|
291 |
|
292 |
|
293 |
|
294 |
|
295 | Block.wrap = (s) -> new Block(if s? then [s] else []).r(s.raw).p(s.line, s.column)
|
296 |
|
297 | Class::initialise = ->
|
298 | @boundMembers ?= []
|
299 | @name = new GenSym 'class'
|
300 | if @nameAssignee?
|
301 |
|
302 | @name = switch
|
303 | when @nameAssignee.instanceof Identifier
|
304 | new Identifier @nameAssignee.data
|
305 | when @nameAssignee.instanceof StaticMemberAccessOps
|
306 | new Identifier @nameAssignee.memberName
|
307 | else @name
|
308 | Class::childNodes.push 'name'
|
309 |
|
310 | ObjectInitialiser::keys = -> map @members, (m) -> m.key
|
311 | ObjectInitialiser::vals = -> map @members, (m) -> m.expression
|
312 |
|
313 | RegExps::initialise = (_, flags) ->
|
314 | @flags = {}
|
315 | for flag in ['g', 'i', 'm', 'y']
|
316 | @flags[flag] = flag in flags
|
317 | return
|
318 |
|
319 |
|
320 |
|
321 |
|
322 |
|
323 |
|
324 |
|
325 | class exports.NegatedConditional extends Conditional
|
326 | constructor: -> Conditional.apply this, arguments
|
327 |
|
328 |
|
329 |
|
330 |
|
331 | class exports.NegatedWhile extends While
|
332 | constructor: -> While.apply this, arguments
|
333 |
|
334 |
|
335 |
|
336 |
|
337 | class exports.Loop extends While
|
338 | constructor: (body) -> While.call this, (new Bool true).g(), body
|