UNPKG

7.77 kBtext/coffeescriptView Raw
1config = require "./config"
2{Scope} = require "./scope"
3{Visitor, ActiveVisitor, DisabledVisitor} = require "./visitor"
4kit = require "./kit"
5policy = require "./policy"
6directive = require "./directives"
7{VarUsage} = require "./builder"
8require "./graph"
9require "./expr"
10
11class ExprBuilder
12 constructor: (@expr, @ctx) ->
13 @init()
14 @cur = if @ctx.policy.opts.bind
15 @ctx.effValNode(@expr)
16 else @ctx.exprNode(@expr)
17 init: ->
18 @deps = []
19 add: (s,par,x,opts) ->
20 r = @ctx.expr s, opts
21 if r.pureExpr? and not r.vdeps.mod
22 par[x] = r.pureExpr
23 @cur.vdeps.addInnerDeep(r.vdeps)
24 return
25 r.setPosition([par,x])
26 @deps.push(r)
27 return
28 result: ->
29 res = @cur
30 {vdeps} = res
31 if @deps.length
32 res = @ctx.bindNode(res, @deps)
33 res.origExpr = false if @orig is false
34 @init()
35 @cur = res
36
37class DummyBuilder
38 constructor: (@expr,@ctx) ->
39 add: (s,par,x,opts) ->
40 r = @ctx.expr s, opts
41 if r.pureExpr?
42 par[x] = r.pureExpr
43 return
44 throw new Error("INTERNAL: not expected effectful expression")
45 result: -> @ctx.pureExprNode(@expr)
46
47Visitor::CallExpression = (e) ->
48 opts = @policy.opts
49 {callee,arguments:args} = e
50 if callee.type is "Identifier"
51 n = callee.name
52 if n is "require" and args.length is 1
53 a = args[0]
54 if a.type is "Literal" and a.value is config.packageName
55 @ctx.policy._libRequire()
56 return @ctx.pureExprNode(e)
57 dir = do ->
58 return directive.$packVar if n is config.packageVar
59 return unless callee.type is "MemberExpression"
60 obj = callee.object
61 return unless obj.type is "Identifier" and obj.name is config.packageVar
62 prop = callee.property
63 if prop.type is "Identifier"
64 dn = prop.name
65 else if callee.computed and prop.type is "Literal" and prop.value.substr
66 dn = prop.value
67 else
68 return
69 directive[dn]
70 if dir?
71 res = kit.errorPos(e, => dir.call(@ctx,e,e.arguments...))
72 return @ctx.emptyNode() unless res?
73 return res
74 idn = opts.identity
75 if idn? and idn isnt false
76 idn = 0 if idn is true
77 return @ctx.expr(e.arguments[idn])
78 builder = @getExprBuilder(e)
79 {callee,arguments:args} = e
80 builder.add(callee, e, "callee")
81 if opts.subScope isnt false and callee.$dm$eff is true
82 opts.bind = true
83 builder.add(i, args, x) for i, x in args
84 builder.result()
85
86directive.$packVar = (e,arg) ->
87 bnd = @policy.opts.bind
88 e = @expr arg
89 return @effValNode(e.pureExpr).morphInit(e) if bnd and e.pureExpr
90 return e
91
92directive.reflect = (e,arg) ->
93 bnd = @policy.opts.bind
94 expr = kit.call(kit.packId("reflect"), [arg])
95 @bindNode(@effValNode(expr),
96 [@expr(arg).setPosition([expr.arguments,0])])
97
98directive.reify = (e, arg) ->
99 @reifyNode().setBody(@expr(arg))
100 .setIsThunk(arg.type is "FunctionExpression")
101
102directive.p = directive.p = (e, arg) -> @pureExprNode(arg)
103
104Visitor::FunctionExpression = (e) ->
105 ctx = @ctx.subScope(e)
106 if e.params?
107 ctx.vars[i.name] = true for i in e.params when i.name
108 return @ctx.pureExprNode(e) unless ctx?
109 e.body = ctx.prog e.body
110 e.$dm$eff = true if ctx.eff
111 res = @ctx.exprNode(e)
112 vars = ctx.vars
113 @ctx.refs[i] = true for i, v of ctx.upds when v and not ctx.vars[i]
114 if e.generator
115 e.generator = false
116 return res
117
118ActiveVisitor::ThisExpression = (e) ->
119 @ctx.thisVar ?= @ctx.uniqId("_this")
120 return @ctx.exprNode(@ctx.thisVar)
121
122Visitor::AssignmentExpression = (e) ->
123 {left,right} = e
124 deps = []
125 res = @ctx.exprNode(e)
126 @policy.nameDetails(left,e.operator)
127 if left.type is "Identifier"
128 if e.operator is "="
129 res.vdeps.addAssign(left.name)
130 else
131 res.vdeps.addUpd(left.name)
132 unless @ctx.vars[left.name]
133 @ctx.upds[left.name] = true
134 else
135 lv = @ctx.expr left
136 if lv.pureExpr?
137 res.vdeps.addInnerDeep(lv.vdeps)
138 e.left = lv.pureExpr
139 else
140 deps.push(lv.setPosition([e,"left"]))
141 rv = @ctx.expr right
142 if rv.pureExpr?
143 res.vdeps.addInnerDeep(rv.vdeps)
144 e.right = rv.pureExpr
145 else
146 deps.push(rv.setPosition([e,"right"]))
147 if deps.length
148 res = @ctx.bindNode(res,deps)
149 res
150
151ActiveVisitor::UpdateExpression = (e) ->
152 res = @ctx.exprNode(e)
153 a = e.argument
154 if a.type is "Identifier"
155 unless @ctx.vars[a.name]
156 @ctx.upds[a.name] = true
157 res.vdeps.addUpd(a.name)
158 else
159 av = @ctx.expr a
160 if av.pureExpr
161 e.argument = av.pureExpr
162 else
163 res = @ctx.bindNode(res, [av.setPosition([e,"argument"])])
164 res
165
166directive.$ = (e, arg) ->
167 @placeholderNode(arg)
168
169ActiveVisitor::MemberExpression = (e) ->
170 {object, property} = e
171 if object.type is "Identifier" and object.name is config.packageVar and
172 property.type is "Identifier" and property.name is "$"
173 return @ctx.placeholderNode()
174 builder = @getExprBuilder(e)
175 builder.add(object, e, "object")
176 if e.computed
177 builder.add(property, e,"property")
178 builder.result()
179
180ActiveVisitor::Identifier = (e) ->
181 res = @ctx.exprNode(e)
182 res.vdeps.uses[e.name] = true
183 @ctx.ids[e.name] = true unless e.$dm$orig
184 res
185
186Visitor::getExprBuilder = (e) -> new DummyBuilder(e,@ctx)
187ActiveVisitor::getExprBuilder = (e) -> new ExprBuilder(e,@ctx)
188
189ActiveVisitor::LogicalExpression = (e) ->
190 if @policy.opts.expr is "par"
191 builder = @getExprBuilder(e)
192 builder.add(e.left, e, "left")
193 builder.add(e.right, e, "right")
194 return builder.result()
195 cexpr = {type:"ConditionalExpression"}
196 l = @ctx.expr(e.left)
197 r = @ctx.expr(e.right)
198 return @ctx.exprNode(e) unless l.eff or r.eff
199 rexpr = r.getBuilder().setOpts(@policy.opts).toExpr()
200 b = if r.eff then @ctx.effValNode(cexpr) else @ctx.pureExprNode(cexpr)
201 res = @ctx.sharedNode(l,b)
202 lexpr = cexpr.test = res._ref
203 lexpr = kit.pure(lexpr) if @policy.opts.coerce is "none" and r.eff
204 if e.operator is "||"
205 cexpr.consequent = lexpr
206 cexpr.alternate = rexpr
207 else
208 cexpr.consequent = rexpr
209 cexpr.alternate = lexpr
210 res
211
212ActiveVisitor::ConditionalExpression = (e) ->
213 if @policy.opts.expr is "par"
214 builder = @getExprBuilder(e)
215 builder.add(e.test, e, "test")
216 builder.add(e.consequent, e, "consequent")
217 builder.add(e.alternate, e, "alternate")
218 return builder.result()
219 c = @ctx.expr(e.consequent)
220 a = @ctx.expr(e.alternate)
221 if c.eff or a.eff
222 e.consequent = c.getFullExpr(true)
223 e.alternate = a.getFullExpr(true)
224 n = @ctx.effValNode(e)
225 else
226 n = @ctx.pureExprNode(e)
227 @ctx.bindNode(n, [@ctx.expr(e.test).setPosition([e,"test"])])
228
229directive.answer = directive.yield = (s,arg) ->
230 e = @expr(arg) if arg?
231 @root.yieldNode(e)
232
233ActiveVisitor::YieldExpression = (e) ->
234 if @ctx.policy.opts.mopt is false
235 if e.delegate
236 return directive.$packVar.call(@ctx,e,e.argument)
237 return directive.reflect.call(@ctx,e,e.argument)
238 @ctx.root.yieldNode(@ctx.expr(e.argument))
239
240ActiveVisitor::BinaryExpression = (e) ->
241 builder = @getExprBuilder(e)
242 builder.add(e.left, e, "left")
243 builder.add(e.right, e, "right")
244 builder.result()
245
246ActiveVisitor::UnaryExpression = (e) ->
247 builder = @getExprBuilder(e)
248 builder.add(e.argument, e, "argument")
249 builder.result()
250
251ActiveVisitor::NewExpression = (e) ->
252 builder = @getExprBuilder(e)
253 args = e.arguments
254 builder.add(i, args, x) for i, x in args
255 builder.result()
256
257ActiveVisitor::SequenceExpression = (e) ->
258 builder = @getExprBuilder(e)
259 args = e.expressions
260 builder.add(i, args, x) for i, x in args
261 builder.result()
262
263ActiveVisitor::ArrayExpression = (e) ->
264 builder = @getExprBuilder(e)
265 args = e.elements
266 builder.add(i, args, x) for i, x in args when i
267 builder.result()
268
269ActiveVisitor::ObjectExpression = (e) ->
270 builder = @getExprBuilder(e)
271 builder.add(i.value, i, "value") for i in e.properties
272 builder.result()
273
274module.exports = {}
275