UNPKG

7.76 kBtext/coffeescriptView Raw
1{Scope} = require "./scope"
2config = require "./config"
3kit = require "./kit"
4directive = require "./directives"
5esquery = require "esquery"
6escodegen = require("escodegen")
7resolve = require "resolve"
8path = require "path"
9
10root = module.exports = {}
11
12hier = {}
13
14hierIs = (f, t) ->
15 (h = hier[f] ?= [f]).push t
16 ht = hier[t]
17 if ht?
18 for i in ht
19 h.push(i)
20 return
21
22hierIs("WhileStatement",":loop")
23hierIs("DoWhileStatement",":loop")
24hierIs("ForStatement",":loop")
25hierIs("ForInStatement",":loop")
26hierIs("VariableDeclaration",":assignment")
27hierIs("FunctionExpression","Function")
28hierIs("FunctionDeclaration","Function")
29hierIs("AssignmentExpression",":assignment")
30
31root.selector =
32 property: (name, next) ->
33 p = name.split(".")
34 next ?= (v) -> v
35 (e) ->
36 return next() unless e?
37 for i in p
38 e = e[i]
39 break unless e?
40 next(e)
41 cases: (sel) ->
42 (s) ->
43 v = sel(s)
44 return @cases[v] if v?
45 prop: (n) ->
46 (s) ->
47 @cases[s.generator ? false]
48 generatorCall: -> false
49 matchDeclName: (s,x,tpref) ->
50 m = @match
51 n = kit.getId(s.id)
52 r = do ->
53 if s.id?
54 if n?
55 return true if m.name? and m.name[n]
56 return true if m.qname? and m.qname[n]
57 return true if m.postfix? and m.postfix[n[n.length - 1]]
58 return true if m.prefix? and m.prefix[n[0]]
59 if s.type is "FunctionExpression" and x.name?
60 p = kit.getMembersPathIds(x.name)
61 if p.length
62 n = p[p.length - 1]
63 if n?
64 return true if m.name? and m.name[n]
65 return true if m.postfix? and m.postfix[n[n.length - 1]]
66 return true if m.prefix? and m.prefix[n[0]]
67 return true if m.package? and p[0]? and m.package[p[0]]
68 return true if m.qname? and m.qname[p.join(".")]
69 return false
70 if tpref?
71 console.log("#{tpref}: match decl #{n}: #{r}")
72 return unless r?
73 return @cases[r]
74 matchCallName: (s, p, tpref) ->
75 p = kit.getMembersPathIds(s.callee)
76 m = @match
77 r = do ->
78 n = p[0]
79 if p.length is 1
80 if n?
81 return true if m.libVar and n is config.packageVar
82 return false if m.libVar and p.length is 2 and n is config.packageName
83 if p.length > 0
84 n = p[p.length - 1]
85 return false unless n?
86 return true if m.package? and m.package[p[0]]
87 return true if m.name? and m.name[n]
88 return true if m.postfix? and m.postfix[n[n.length - 1]]
89 return true if m.prefix? and m.prefix[n[0]]
90 return true if m.qname? and m.qname[p.join(".")]
91 return false
92 if tpref?
93 console.log("#{tpref}: match call #{p.join('.')}: #{r}")
94 return unless r?
95 return @cases[r]
96
97rebuildDT = (c) ->
98 copy = (p, c) ->
99 unless p? and p.$
100 throw new Error("invalid transitions")
101 r = {}
102 for i of options
103 unless p.$?
104 throw new Error('invalid config')
105 v = c[i] ? p.$[i]
106 r[i] = v if v?
107 c.$ = r
108 copy({$:{}},c)
109 for state, sv of c when state[0] isnt '$' and not options[state]
110 copy(c,sv)
111 for ty,tv of sv when ty[0] isnt '$' and not options[ty]
112 copy(sv,tv)
113 if tv.select? and tv.select.substr?
114 tv.select = upStage(root.selector,tv.select)
115 if tv.cases?
116 for cn,cv of tv.cases
117 copy(tv,cv)
118 return
119
120options =
121 bind: true
122 compile: true
123 coerce: true
124 expr: true
125 bindAssoc: true
126 block: true
127 loop: true
128 subScope: true
129 keepScope: true
130 varCapt: true
131 branch: true
132 ref: true
133 remove: true
134 keepForOf: true
135 mopt: true
136
137class Policy
138 constructor: (@root,start) ->
139 @root ?= config.states
140 @state = start ? config.start
141 @opts = @root[@state]
142 @rebuild()
143 transit: (n) ->
144 if config.policyTrace
145 console.log("policy: transit to #{n}")
146 @state = n
147 cur = @root[n]
148 unless cur?
149 throw new Error("no state #{n} defined")
150 @opts = cur.$
151 @
152 nameDetails: (@name, @op) ->
153 @
154 scope: (f) ->
155 oldRoot = @root
156 @root = kit.merge({}, oldRoot)
157 oldState = @state
158 res = f()
159 @state = oldState
160 @root = oldRoot
161 @opts = @root[@state].$
162 res
163 _libRequire: ->
164 if @name? and @name.type is "Identifier"
165 config.packageVar = @name.name
166 @transit(config.start)
167 rebuild: (changes) ->
168 if changes?
169 kit.merge(@root,changes)
170 rebuildDT(@root)
171 @opts = @root[@state].$
172 item: (s, fun) ->
173 trace = config.policyTrace
174 if trace
175 tpref = "polciy:#{kit.shortNodeDescr(s)}"
176 console.log("#{tpref}: enter at #{@state}")
177 if @name?
178 console.log("#{tpref}: name #{@name}")
179 if @op?
180 console.log("#{tpref}: op #{@op}")
181 cur = @root[@state]
182 h = hier[s.type] ? [s.type]
183 for i in h when n = cur[i]
184 cur = n
185 console.log("#{tpref}: by type #{i}: #{JSON.stringify(cur)}") if trace
186 break
187 sel = cur.select
188 if sel?
189 selv = sel.call(cur, s, @, tpref)
190 console.log("#{tpref}: selector #{JSON.stringify(selv)}") if trace
191 cur = selv if selv?
192 if cur.move?
193 console.log("#{n}: moving to #{cur.move}") if trace
194 return @transit(cur.move).item(s,fun)
195 jump = cur.sub ? cur.next ? cur.inner
196 if trace
197 console.log("#{tpref}: sub-state #{cur.sub}") if cur.sub
198 console.log("#{tpref}: inner state #{cur.inner}") if cur.inner
199 console.log("#{tpref}: next state #{cur.next}") if cur.next
200 if jump?
201 oldState = @state if jump is cur.sub
202 @state = jump
203 cur = @root[jump] unless jump is cur.inner
204 else if s.type is "BlockStatement"
205 oldState = @state
206 oldOp = @op
207 oldOpts = @opts
208 @opts = cur.$
209 console.log("#{tpref}: opts #{JSON.stringify(@opts)}") if trace
210 oldName = @name
211 @libVar = false
212 index = @index
213 @index = 0
214 res = fun()
215 @index = index+1
216 @name = oldName
217 @op = oldOp
218 if oldState?
219 console.log("#{tpref}: restoring state #{oldState}") if trace
220 @state = oldState
221 @opts = oldOpts
222 console.log("#{tpref}: restoring opts #{JSON.stringify(oldOpts)}") if trace
223 res
224
225Scope::option = (v) ->
226 @policy.rebuild(v)
227 @updateVisitor()
228
229Scope::profile = (v) ->
230 if v.substr?
231 @policy.transit(v)
232 @updateVisitor()
233 return
234 throw new Error("cannot interpret profile #{v}")
235
236root.optionEnv = Object.create(root.selector)
237
238upStage = (env, str) ->
239 args = []
240 vals = []
241 for i,v of env
242 args.push i
243 vals.push v
244 args.push "return #{str};"
245 fun = new Function(args...)
246 fun.apply(env, vals)
247
248opts = directive.option = (e) ->
249 for i in e.arguments
250 if i.type is "Literal" and e.value? and e.value.substr?
251 upStage(env, e.value)
252 else if i.type is "ObjectExpression"
253 @option(upStage(root.optionEnv, escodegen.generate(i)))
254 else throw kit.exprError(
255 "cannot interpret option #{escodegen.generate(i)}", i)
256 @emptyNode()
257
258directive.profile = (e, arg) ->
259 @profile(kit.toStr arg)
260 @emptyNode()
261
262Scope::createPolicy = ->
263 return new Policy()
264
265directive.require = (e,c) ->
266 cs = kit.exprToStr c
267 f = resolve.sync cs, basedir: path.dirname(config.filename)
268 try
269 cp = resolve.sync(config.packageName,
270 basedir: path.dirname(config.filename))
271 core = require cp
272 core.compileTime = true
273 catch e
274 console.warn("couldn't load library ", config.packageName, e)
275 m = require f
276 if m? and m._compile? and m._compile.call?
277 n = @policy.name
278 if n.type is "Identifier"
279 varname = n.name
280 m._compile.call(@,[varname])
281 return @pureExprNode(kit.call(kit.id("require"),[c]))
282
283directive.ref = (e) ->
284 for a in e.arguments
285 i = kit.getId(a)
286 unless i?
287 throw kit.exprError('expected identifiers',a)
288 @refs[i] = true
289 @emptyNode()
290