• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Siubaak / sval / 12722229009

11 Jan 2025 07:10AM UTC coverage: 64.374% (-2.5%) from 66.826%
12722229009

push

github

Siubaak
[chore] fix coverage

1421 of 2299 branches covered (61.81%)

Branch coverage included in aggregate %.

1293 of 1917 relevant lines covered (67.45%)

1271.22 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

16.86
/src/evaluate/statement.ts
1
import { BREAK, CONTINUE, RETURN, AWAIT } from '../share/const'
2
import { hoist, pattern, ForXHandler } from './helper'
3
import { getAsyncIterator } from '../share/util'
4
import * as acorn from 'acorn'
5
import Scope from '../scope'
6
import evaluate from '.'
7

8
export function* ExpressionStatement(node: acorn.ExpressionStatement, scope: Scope) {
9
  yield* evaluate(node.expression, scope)
364✔
10
}
11

12
export interface LabelOptions {
13
  label?: string
14
}
15

16
export interface BlockOptions {
17
  invasived?: boolean
18
  hoisted?: boolean
19
}
20

21
export function* BlockStatement(
22
  block: acorn.BlockStatement | acorn.StaticBlock,
23
  scope: Scope,
24
  options: BlockOptions & LabelOptions = {},
5✔
25
) {
26
  const {
27
    invasived = false,
5✔
28
    hoisted = false,
59✔
29
  } = options
174✔
30

31
  const subScope = invasived ? scope : new Scope(scope)
174✔
32

33
  if (!hoisted) {
174✔
34
    yield* hoist(block, subScope, { onlyBlock: true })
118✔
35
  }
36

37
  for (let i = 0; i < block.body.length; i++) {
174✔
38
    const result = yield* evaluate(block.body[i], subScope)
494✔
39
    if (result === BREAK) {
486!
40
      if (result.LABEL && result.LABEL === options.label) {
×
41
        // only labeled break to current block statement doesn't bubble up the result
42
        break
×
43
      }
44
      return result
×
45
    }
46
    if (result === CONTINUE || result === RETURN) {
486✔
47
      return result
2✔
48
    }
49
  }
50
}
51

52
export function* EmptyStatement(): IterableIterator<any> {
53
  // No operation here
54
}
55

56
export function* DebuggerStatement(): IterableIterator<any> {
57
  debugger
×
58
}
59

60
export function* ReturnStatement(node: acorn.ReturnStatement, scope: Scope) {
61
  RETURN.RES = node.argument ? (yield* evaluate(node.argument, scope)) : undefined
2!
62
  return RETURN
2✔
63
}
64

65
export function* BreakStatement(node: acorn.BreakStatement) {
66
  BREAK.LABEL = node.label?.name
×
67
  return BREAK
×
68
}
69

70
export function* ContinueStatement(node: acorn.ContinueStatement) {
71
  CONTINUE.LABEL = node.label?.name
×
72
  return CONTINUE
×
73
}
74

75
export function* LabeledStatement(node: acorn.LabeledStatement, scope: Scope) {
76
  const label = node.label.name
×
77
  if (node.body.type === 'WhileStatement') {
×
78
    return yield* WhileStatement(node.body, scope, { label })
×
79
  }
80
  if (node.body.type === 'DoWhileStatement') {
×
81
    return yield* DoWhileStatement(node.body, scope, { label })
×
82
  }
83
  if (node.body.type === 'ForStatement') {
×
84
    return yield* ForStatement(node.body, scope, { label })
×
85
  }
86
  if (node.body.type === 'ForInStatement') {
×
87
    return yield* ForInStatement(node.body, scope, { label })
×
88
  }
89
  if (node.body.type === 'ForOfStatement') {
×
90
    return yield* ForOfStatement(node.body, scope, { label })
×
91
  }
92
  if (node.body.type === 'BlockStatement') {
×
93
    return yield* BlockStatement(node.body, scope, { label })
×
94
  }
95
  if (node.body.type === 'WithStatement') {
×
96
    return yield* WithStatement(node.body, scope, { label })
×
97
  }
98
  if (node.body.type === 'IfStatement') {
×
99
    return yield* IfStatement(node.body, scope, { label })
×
100
  }
101
  if (node.body.type === 'SwitchStatement') {
×
102
    return yield* SwitchStatement(node.body, scope, { label })
×
103
  }
104
  if (node.body.type === 'TryStatement') {
×
105
    return yield* TryStatement(node.body, scope, { label })
×
106
  }
107
  throw new SyntaxError(`${node.body.type} cannot be labeled`)
×
108
}
109

110
export function* WithStatement(node: acorn.WithStatement, scope: Scope, options: LabelOptions = {}) {
×
111
  const withScope = new Scope(scope)
×
112
  withScope.with(yield* evaluate(node.object, scope))
×
113
  const result = yield* evaluate(node.body, withScope)
×
114
  if (result === BREAK) {
×
115
    if (result.LABEL && result.LABEL === options.label) {
×
116
      // only labeled break to current with statement doesn't bubble up the result
117
      return
×
118
    }
119
    return result
×
120
  }
121
  if (result === CONTINUE || result === RETURN) {
×
122
    return result
×
123
  }
124
}
125

126
export function* IfStatement(node: acorn.IfStatement, scope: Scope, options: LabelOptions = {}) {
×
127
  let result
128

129
  if (yield* evaluate(node.test, scope)) {
×
130
    result = yield* evaluate(node.consequent, scope)
×
131
  } else {
132
    result = yield* evaluate(node.alternate, scope)
×
133
  }
134

135
  if (result === BREAK) {
×
136
    if (result.LABEL && result.LABEL === options.label) {
×
137
      // only labeled break to current if statement doesn't bubble up the result
138
      return
×
139
    }
140
    return result
×
141
  }
142
  if (result === CONTINUE || result === RETURN) {
×
143
    return result
×
144
  }
145
}
146

147
export function* SwitchStatement(node: acorn.SwitchStatement, scope: Scope, options: LabelOptions = {}) {
×
148
  const discriminant = yield* evaluate(node.discriminant, scope)
×
149
  let matched = false
×
150
  for (let i = 0; i < node.cases.length; i++) {
×
151
    const eachCase = node.cases[i]
×
152
    if (
×
153
      !matched
×
154
      && (
155
        !eachCase.test  // default
156
        || (yield* evaluate(eachCase.test, scope)) === discriminant
157
      )
158
    ) {
159
      matched = true
×
160
    }
161
    if (matched) {
×
162
      const result = yield* SwitchCase(eachCase, scope)
×
163
      if (result === BREAK) {
×
164
        if (result.LABEL === options.label) {
×
165
          break
×
166
        }
167
        return result
×
168
      }
169
      if (result === CONTINUE || result === RETURN) {
×
170
        return result
×
171
      }
172
    }
173
  }
174
}
175

176
export function* SwitchCase(node: acorn.SwitchCase, scope: Scope) {
177
  for (let i = 0; i < node.consequent.length; i++) {
×
178
    const result = yield* evaluate(node.consequent[i], scope)
×
179
    if (result === BREAK || result === CONTINUE || result === RETURN) {
×
180
      return result
×
181
    }
182
  }
183
}
184

185
export function* ThrowStatement(node: acorn.ThrowStatement, scope: Scope) {
186
  throw yield* evaluate(node.argument, scope)
×
187
}
188

189
export function* TryStatement(node: acorn.TryStatement, scope: Scope, options: LabelOptions = {}) {
×
190
  let result
191

192
  try {
×
193
    result = yield* BlockStatement(node.block, scope)
×
194
  } catch (err) {
195
    if (node.handler) {
×
196
      const subScope = new Scope(scope)
×
197
      const param = node.handler.param
×
198
      if (param) {
×
199
        if (param.type === 'Identifier') {
×
200
          const name = param.name
×
201
          subScope.var(name, err)
×
202
        } else {
203
          yield* pattern(param, scope, { feed: err })
×
204
        }
205
      }
206
      result = yield* CatchClause(node.handler, subScope)
×
207
    } else {
208
      throw err
×
209
    }
210
  } finally {
211
    if (node.finalizer) {
×
212
      result = yield* BlockStatement(node.finalizer, scope)
×
213
    }
214
  }
215

216
  if (result === BREAK) {
×
217
    if (result.LABEL && result.LABEL === options.label) {
×
218
      // only labeled break to current try statement doesn't bubble up the result
219
      return
×
220
    }
221
    return result
×
222
  }
223
  if (result === CONTINUE || result === RETURN) {
×
224
    return result
×
225
  }
226
}
227

228
export function* CatchClause(node: acorn.CatchClause, scope: Scope) {
229
  return yield* BlockStatement(node.body, scope, { invasived: true })
×
230
}
231

232
export function* WhileStatement(node: acorn.WhileStatement, scope: Scope, options: LabelOptions = {}) {
1✔
233
  while (yield* evaluate(node.test, scope)) {
2✔
234
    const result = yield* evaluate(node.body, scope)
6✔
235
    if (result === BREAK) {
6!
236
      if (result.LABEL === options.label) {
×
237
        break
×
238
      }
239
      return result
×
240
    } else if (result === CONTINUE) {
6!
241
      if (result.LABEL === options.label) {
×
242
        continue
×
243
      }
244
      return result
×
245
    } else if (result === RETURN) {
6!
246
      return result
×
247
    }
248
  }
249
}
250

251
export function* DoWhileStatement(node: acorn.DoWhileStatement, scope: Scope, options: LabelOptions = {}) {
×
252
  do {
×
253
    const result = yield* evaluate(node.body, scope)
×
254
    if (result === BREAK) {
×
255
      if (result.LABEL === options.label) {
×
256
        break
×
257
      }
258
      return result
×
259
    } else if (result === CONTINUE) {
×
260
      if (result.LABEL === options.label) {
×
261
        continue
×
262
      }
263
      return result
×
264
    } else if (result === RETURN) {
×
265
      return result
×
266
    }
267
  } while (yield* evaluate(node.test, scope))
268
}
269

270
export function* ForStatement(node: acorn.ForStatement, scope: Scope, options: LabelOptions = {}) {
×
271
  const forScope = new Scope(scope)
×
272
  
273
  for (
×
274
    yield* evaluate(node.init, forScope);
275
    node.test ? (yield* evaluate(node.test, forScope)) : true;
×
276
    yield* evaluate(node.update, forScope)
277
  ) {
278
    const subScope = new Scope(forScope)
×
279
    let result: any
280
    if (node.body.type === 'BlockStatement') {
×
281
      result = yield* BlockStatement(node.body, subScope, { invasived: true })
×
282
    } else {
283
      result = yield* evaluate(node.body, subScope)
×
284
    }
285

286
    if (result === BREAK) {
×
287
      if (result.LABEL === options.label) {
×
288
        break
×
289
      }
290
      return result
×
291
    } else if (result === CONTINUE) {
×
292
      if (result.LABEL === options.label) {
×
293
        continue
×
294
      }
295
      return result
×
296
    } else if (result === RETURN) {
×
297
      return result
×
298
    }
299
  }
300
}
301

302
export function* ForInStatement(node: acorn.ForInStatement, scope: Scope, options: LabelOptions = {}) {
×
303
  for (const value in yield* evaluate(node.right, scope)) {
×
304
    const result = yield* ForXHandler(node, scope, { value })
×
305
    if (result === BREAK) {
×
306
      if (result.LABEL === options.label) {
×
307
        break
×
308
      }
309
      return result
×
310
    } else if (result === CONTINUE) {
×
311
      if (result.LABEL === options.label) {
×
312
        continue
×
313
      }
314
      return result
×
315
    } else if (result === RETURN) {
×
316
      return result
×
317
    }
318
  }
319
}
320

321
export function* ForOfStatement(node: acorn.ForOfStatement, scope: Scope, options: LabelOptions = {}): any {
18✔
322
  const right = yield* evaluate(node.right, scope)
36✔
323
  /*<remove>*/
324
  if (node.await) {
36✔
325
    const iterator = getAsyncIterator(right)
18✔
326
    let ret: any
327
    for (
18✔
328
      AWAIT.RES = iterator.next(), ret = yield AWAIT;
329
      !ret.done;
330
      AWAIT.RES = iterator.next(), ret = yield AWAIT
331
    ) {
332
      const result = yield* ForXHandler(node, scope, { value: ret.value })
56✔
333
      if (result === BREAK) {
56!
334
        if (result.LABEL === options.label) {
×
335
          break
×
336
        }
337
        return result
×
338
      } else if (result === CONTINUE) {
56!
339
        if (result.LABEL === options.label) {
×
340
          continue
×
341
        }
342
        return result
×
343
      } else if (result === RETURN) {
56!
344
        return result
×
345
      }
346
    }
347
  } else {
348
  /*</remove>*/
349
    for (const value of right) {
18✔
350
      const result = yield* ForXHandler(node, scope, { value })
52✔
351
      if (result === BREAK) {
48!
352
        if (result.LABEL === options.label) {
×
353
          break
×
354
        }
355
        return result
×
356
      } else if (result === CONTINUE) {
48!
357
        if (result.LABEL === options.label) {
×
358
          continue
×
359
        }
360
        return result
×
361
      } else if (result === RETURN) {
48!
362
        return result
×
363
      }
364
    }
365
  /*<remove>*/
366
  }
367
  /*</remove>*/
368
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc