UNPKG

12.7 kBtext/coffeescriptView Raw
1{map, concat, concatMap, difference, nub, union} = require './functional-helpers'
2exports = module?.exports ? this
3
4# TODO: make sure all the type signatures are correct
5
6createNodes = (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# Note: nullable values are marked with `Maybe` in the type signature
39# Note: primitive values are represented in lowercase
40# Note: type classes are pluralised
41createNodes
42 Nodes: [
43 []
44 BinOps: [
45 ['left', 'right']
46 AssignOps: [
47 ['assignee', 'expression']
48 AssignOp: null # :: Assignables -> Exprs -> AssignOp
49 ClassProtoAssignOp: null # :: ObjectInitialiserKeys -> Exprs -> ClassProtoAssignOp
50 CompoundAssignOp: [['op', 'assignee', 'expression']] # :: string -> Assignables -> Exprs -> CompoundAssignOp
51 ]
52 BitOps: [
53 null
54 BitAndOp: null # :: Exprs -> Exprs -> BitAndOp
55 BitOrOp: null # :: Exprs -> Exprs -> BitOrOp
56 BitXorOp: null # :: Exprs -> Exprs -> BitXorOp
57 LeftShiftOp: null # :: Exprs -> Exprs -> LeftShiftOp
58 SignedRightShiftOp: null # :: Exprs -> Exprs -> SignedRightShiftOp
59 UnsignedRightShiftOp: null # :: Exprs -> Exprs -> UnsignedRightShiftOp
60 ]
61 ComparisonOps: [
62 null
63 EQOp: null # :: Exprs -> Exprs -> EQOp
64 GTEOp: null # :: Exprs -> Exprs -> GTEOp
65 GTOp: null # :: Exprs -> Exprs -> GTOp
66 LTEOp: null # :: Exprs -> Exprs -> LTEOp
67 LTOp: null # :: Exprs -> Exprs -> LTOp
68 NEQOp: null # :: Exprs -> Exprs -> NEQOp
69 ]
70 # Note: A tree of ConcatOp represents interpolation
71 ConcatOp: null # :: Exprs -> Exprs -> ConcatOp
72 ExistsOp: null # :: Exprs -> Exprs -> ExistsOp
73 ExtendsOp: null # :: Exprs -> Exprs -> ExtendsOp
74 InOp: null # :: Exprs -> Exprs -> InOp
75 InstanceofOp: null # :: Exprs -> Exprs -> InstanceofOp
76 LogicalOps: [
77 null
78 LogicalAndOp: null # :: Exprs -> Exprs -> LogicalAndOp
79 LogicalOrOp: null # :: Exprs -> Exprs -> LogicalOrOp
80 ]
81 MathsOps: [
82 null
83 ExpOp: null # :: Exprs -> Exprs -> ExpOp
84 DivideOp: null # :: Exprs -> Exprs -> DivideOp
85 MultiplyOp: null # :: Exprs -> Exprs -> MultiplyOp
86 RemOp: null # :: Exprs -> Exprs -> RemOp
87 SubtractOp: null # :: Exprs -> Exprs -> SubtractOp
88 ]
89 OfOp: null # :: Exprs -> Exprs -> OfOp
90 PlusOp: null # :: Exprs -> Exprs -> PlusOp
91 Range: [['isInclusive', 'left', 'right']] # :: bool -> Exprs -> Exprs -> Range
92 SeqOp: null # :: Exprs -> Exprs -> SeqOp
93 ]
94
95 Statements: [
96 []
97 Break: null # :: Break
98 Continue: null # :: Continue
99 Debugger: null # :: Debugger
100 Return: [['expression']] # :: Maybe Exprs -> Return
101 Throw: [['expression']] # :: Exprs -> Throw
102 ]
103
104 UnaryOps: [
105 ['expression']
106 BitNotOp: null # :: Exprs -> BitNotOp
107 DeleteOp: null # :: MemberAccessOps -> DeleteOp
108 DoOp: null # :: Exprs -> DoOp
109 LogicalNotOp: null # :: Exprs -> LogicalNotOp
110 NewOp: [['ctor', 'arguments']] # :: Exprs -> [Arguments] -> NewOp
111 PreDecrementOp: null # :: Exprs -> PreDecrementOp
112 PreIncrementOp: null # :: Exprs -> PreIncrementOp
113 PostDecrementOp: null # :: Exprs -> PostDecrementOp
114 PostIncrementOp: null # :: Exprs -> PostIncrementOp
115 TypeofOp: null # :: Exprs -> TypeofOp
116 UnaryExistsOp: null # :: Exprs -> UnaryExistsOp
117 UnaryNegateOp: null # :: Exprs -> UnaryNegateOp
118 UnaryPlusOp: null # :: Exprs -> UnaryPlusOp
119 ]
120
121 MemberAccessOps: [
122 null
123 StaticMemberAccessOps: [
124 ['expression', 'memberName']
125 MemberAccessOp: null # :: Exprs -> MemberNames -> MemberAccessOp
126 ProtoMemberAccessOp: null # :: Exprs -> MemberNames -> ProtoMemberAccessOp
127 SoakedMemberAccessOp: null # :: Exprs -> MemberNames -> SoakedMemberAccessOp
128 SoakedProtoMemberAccessOp: null # :: Exprs -> MemberNames -> SoakedProtoMemberAccessOp
129 ]
130 DynamicMemberAccessOps: [
131 ['expression', 'indexingExpr']
132 DynamicMemberAccessOp: null # :: Exprs -> Exprs -> DynamicMemberAccessOp
133 DynamicProtoMemberAccessOp: null # :: Exprs -> Exprs -> DynamicProtoMemberAccessOp
134 SoakedDynamicMemberAccessOp: null # :: Exprs -> Exprs -> SoakedDynamicMemberAccessOp
135 SoakedDynamicProtoMemberAccessOp: null # :: Exprs -> Exprs -> SoakedDynamicProtoMemberAccessOp
136 ]
137 ]
138
139 ChainedComparisonOp: [['expression']] # :: ComparisonOps -> ChainedComparisonOp
140
141 FunctionApplications: [
142 ['function', 'arguments']
143 FunctionApplication: null # :: Exprs -> [Arguments] -> FunctionApplication
144 SoakedFunctionApplication: null # :: Exprs -> [Arguments] -> SoakedFunctionApplication
145 ]
146 Super: [['arguments']] # :: [Arguments] -> Super
147
148 Program: [['body']] # :: Maybe Exprs -> Program
149 Block: [['statements']] # :: [Statement] -> Block
150 Conditional: [['condition', 'consequent', 'alternate']] # :: Exprs -> Maybe Exprs -> Maybe Exprs -> Conditional
151 ForIn: [['valAssignee', 'keyAssignee', 'target', 'step', 'filter', 'body']] # :: Assignable -> Maybe Assignable -> Exprs -> Exprs -> Maybe Exprs -> Maybe Exprs -> ForIn
152 ForOf: [['isOwn', 'keyAssignee', 'valAssignee', 'target', 'filter', 'body']] # :: bool -> Assignable -> Maybe Assignable -> Exprs -> Maybe Exprs -> Maybe Exprs -> ForOf
153 Switch: [['expression', 'cases', 'alternate']] # :: Maybe Exprs -> [SwitchCase] -> Maybe Exprs -> Switch
154 SwitchCase: [['conditions', 'consequent']] # :: [Exprs] -> Maybe Expr -> SwitchCase
155 Try: [['body', 'catchAssignee', 'catchBody', 'finallyBody']] # :: Exprs -> Maybe Assignable -> Maybe Exprs -> Maybe Exprs -> Try
156 While: [['condition', 'body']] # :: Exprs -> Maybe Exprs -> While
157
158 ArrayInitialiser: [['members']] # :: [ArrayInitialiserMembers] -> ArrayInitialiser
159 ObjectInitialiser: [['members']] # :: [ObjectInitialiserMember] -> ObjectInitialiser
160 ObjectInitialiserMember: [['key', 'expression']] # :: ObjectInitialiserKeys -> Exprs -> ObjectInitialiserMember
161 Class: [['nameAssignee', 'parent', 'ctor', 'body', 'boundMembers']] # :: Maybe Assignable -> Maybe Exprs -> Maybe Exprs -> Maybe Exprs -> [ClassProtoAssignOp] -> Class
162 Constructor: [['expression']] # :: Exprs -> Constructor
163 Functions: [
164 ['parameters', 'body']
165 Function: null # :: [Parameters] -> Maybe Exprs -> Function
166 BoundFunction: null # :: [Parameters] -> Maybe Exprs -> BoundFunction
167 ]
168 DefaultParam: [['param', 'default']] # :: Parameters -> Exprs -> DefaultParam
169 Identifiers: [
170 ['data']
171 Identifier: null # :: string -> Identifier
172 GenSym: null # :: string -> string -> GenSym
173 ]
174 Null: null # :: Null
175 Primitives: [
176 ['data']
177 Bool: null # :: bool -> Bool
178 JavaScript: null # :: string -> JavaScript
179 Numbers: [
180 null
181 Int: null # :: float -> Int
182 Float: null # :: float -> Float
183 ]
184 String: null # :: string -> String
185 ]
186 RegExps: [
187 null
188 RegExp: [['data', 'flags']] # :: string -> [string] -> RegExp
189 HeregExp: [['expression', 'flags']] # :: Exprs -> [string] -> HeregExp
190 ]
191 This: null # :: This
192 Undefined: null # :: Undefined
193
194 Slice: [['expression', 'isInclusive', 'left', 'right']] # :: Exprs -> bool -> Maybe Exprs -> Maybe Exprs -> Slice
195
196 Rest: [['expression']] # :: Exprs -> Rest
197 Spread: [['expression']] # :: Exprs -> Spread
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
210Nodes.fromJSON = (json) -> exports[json.type].fromJSON json
211Nodes::listMembers = []
212Nodes::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
229Nodes::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
236Nodes::clone = ->
237 ctor = ->
238 ctor.prototype = @constructor.prototype
239 n = new ctor
240 n[k] = v for own k, v of this
241 n
242Nodes::instanceof = (ctors...) ->
243 # not a fold for efficiency's sake
244 superclasses = map @constructor.superclasses, (c) -> c::className
245 for ctor in ctors when ctor::className in [@className, superclasses...]
246 return yes
247 no
248Nodes::r = (@raw) -> this
249Nodes::p = (@line, @column, @offset) -> this
250Nodes::generated = no
251Nodes::g = ->
252 @generated = yes
253 this
254
255
256## Nodes that contain primitive properties
257
258handlePrimitives = (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
266handlePrimitives Class, 'boundMembers'
267handlePrimitives CompoundAssignOp, 'op'
268handlePrimitives ForOf, 'isOwn'
269handlePrimitives HeregExp, 'flags'
270handlePrimitives Identifiers, 'data'
271handlePrimitives Primitives, 'data'
272handlePrimitives Range, 'isInclusive'
273handlePrimitives RegExp, 'data', 'flags'
274handlePrimitives Slice, 'isInclusive'
275handlePrimitives StaticMemberAccessOps, 'memberName'
276
277
278## Nodes that contain list properties
279
280handleLists = (ctor, listProps...) -> ctor::listMembers = listProps
281
282handleLists ArrayInitialiser, 'members'
283handleLists Block, 'statements'
284handleLists Functions, 'parameters'
285handleLists FunctionApplications, 'arguments'
286handleLists NewOp, 'arguments'
287handleLists ObjectInitialiser, 'members'
288handleLists Super, 'arguments'
289handleLists Switch, 'cases'
290handleLists SwitchCase, 'conditions'
291
292
293## Nodes with special behaviours
294
295Block.wrap = (s) -> new Block(if s? then [s] else []).r(s.raw).p(s.line, s.column)
296
297Class::initialise = ->
298 @boundMembers ?= []
299 @name = new GenSym 'class'
300 if @nameAssignee?
301 # TODO: factor this out, as it's useful elsewhere: short object literal members, NFEs from assignee, etc.
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
308Class::childNodes.push 'name'
309
310ObjectInitialiser::keys = -> map @members, (m) -> m.key
311ObjectInitialiser::vals = -> map @members, (m) -> m.expression
312
313RegExps::initialise = (_, flags) ->
314 @flags = {}
315 for flag in ['g', 'i', 'm', 'y']
316 @flags[flag] = flag in flags
317 return
318
319
320## Syntactic nodes
321
322# Note: This only represents the original syntactic specification as an
323# "unless". The node should be treated in all other ways as a Conditional.
324# NegatedConditional :: Exprs -> Maybe Exprs -> Maybe Exprs -> NegatedConditional
325class exports.NegatedConditional extends Conditional
326 constructor: -> Conditional.apply this, arguments
327
328# Note: This only represents the original syntactic specification as an
329# "until". The node should be treated in all other ways as a While.
330# NegatedWhile :: Exprs -> Maybe Exprs -> NegatedWhile
331class exports.NegatedWhile extends While
332 constructor: -> While.apply this, arguments
333
334# Note: This only represents the original syntactic specification as a "loop".
335# The node should be treated in all other ways as a While.
336# Loop :: Maybe Exprs -> Loop
337class exports.Loop extends While
338 constructor: (body) -> While.call this, (new Bool true).g(), body