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

source-academy / js-slang / 15237418122

25 May 2025 11:31AM UTC coverage: 77.048% (-3.5%) from 80.538%
15237418122

push

github

web-flow
Rewrite: Stepper (#1742)

3433 of 4826 branches covered (71.14%)

Branch coverage included in aggregate %.

1032 of 1260 new or added lines in 27 files covered. (81.9%)

440 existing lines in 29 files now uncovered.

10099 of 12737 relevant lines covered (79.29%)

142411.96 hits per line

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

93.67
/src/runner/sourceRunner.ts
1
import * as _ from 'lodash'
59✔
2
import type { RawSourceMap } from 'source-map'
3

4
import { JSSLANG_PROPERTIES } from '../constants'
59✔
5
import { CSEResultPromise, evaluate as CSEvaluate } from '../cse-machine/interpreter'
59✔
6
import { ExceptionError } from '../errors/errors'
59✔
7
import { RuntimeSourceError } from '../errors/runtimeSourceError'
59✔
8
import { TimeoutError } from '../errors/timeoutErrors'
59✔
9
import { isPotentialInfiniteLoop } from '../infiniteLoops/errors'
59✔
10
import { testForInfiniteLoop } from '../infiniteLoops/runtime'
59✔
11
import { sandboxedEval } from '../transpiler/evalContainer'
59✔
12
import { transpile } from '../transpiler/transpiler'
59✔
13
import { Variant } from '../types'
59✔
14
import { getSteps } from '../tracer/steppers'
59✔
15
import { toSourceError } from './errors'
59✔
16
import { resolvedErrorPromise } from './utils'
59✔
17
import type { Runner } from './types'
18
import fullJSRunner from './fullJSRunner'
59✔
19

20
let isPreviousCodeTimeoutError = false
59✔
21
const runners = {
59✔
22
  fulljs: fullJSRunner,
23
  'cse-machine': (program, context, options) => {
24
    const value = CSEvaluate(program, context, options)
1,041✔
25
    return CSEResultPromise(context, value)
1,041✔
26
  },
27
  substitution: (program, context, options) => {
NEW
28
    const steps = getSteps(program, context, options)
×
UNCOV
29
    if (context.errors.length > 0) {
×
UNCOV
30
      return resolvedErrorPromise
×
31
    }
UNCOV
32
    return Promise.resolve({
×
33
      status: 'finished',
34
      context,
35
      value: steps
36
    })
37
  },
38
  native: async (program, context, options) => {
39
    if (!options.isPrelude) {
723✔
40
      if (context.shouldIncreaseEvaluationTimeout && isPreviousCodeTimeoutError) {
418✔
41
        context.nativeStorage.maxExecTime *= JSSLANG_PROPERTIES.factorToIncreaseBy
3✔
42
      } else {
43
        context.nativeStorage.maxExecTime = options.originalMaxExecTime
415✔
44
      }
45
    }
46

47
    // For whatever reason, the transpiler mutates the state of the AST as it is transpiling and inserts
48
    // a bunch of global identifiers to it. Once that happens, the infinite loop detection instrumentation
49
    // ends up generating code that has syntax errors. As such, we need to make a deep copy here to preserve
50
    // the original AST for future use, such as with the infinite loop detector.
51
    const transpiledProgram = _.cloneDeep(program)
723✔
52
    let transpiled
53
    let sourceMapJson: RawSourceMap | undefined
54
    try {
723✔
55
      ;({ transpiled, sourceMapJson } = transpile(transpiledProgram, context))
723✔
56
      let value = sandboxedEval(transpiled, context.nativeStorage)
719✔
57

58
      if (!options.isPrelude) {
653✔
59
        isPreviousCodeTimeoutError = false
348✔
60
      }
61

62
      return {
653✔
63
        status: 'finished',
64
        context,
65
        value
66
      }
67
    } catch (error) {
68
      const isDefaultVariant = options.variant === undefined || options.variant === Variant.DEFAULT
70✔
69
      if (isDefaultVariant && isPotentialInfiniteLoop(error)) {
70✔
70
        const detectedInfiniteLoop = testForInfiniteLoop(
15✔
71
          program,
72
          context.previousPrograms.slice(1),
73
          context.nativeStorage.loadedModules
74
        )
75
        if (detectedInfiniteLoop !== undefined) {
15✔
76
          if (options.throwInfiniteLoops) {
13✔
77
            context.errors.push(detectedInfiniteLoop)
5✔
78
            return resolvedErrorPromise
5✔
79
          } else {
80
            error.infiniteLoopError = detectedInfiniteLoop
8✔
81
            if (error instanceof ExceptionError) {
8✔
82
              ;(error.error as any).infiniteLoopError = detectedInfiniteLoop
1✔
83
            }
84
          }
85
        }
86
      }
87
      if (error instanceof RuntimeSourceError) {
65✔
88
        context.errors.push(error)
21✔
89
        if (error instanceof TimeoutError) {
21✔
90
          isPreviousCodeTimeoutError = true
7✔
91
        }
92
        return resolvedErrorPromise
21✔
93
      }
94
      if (error instanceof ExceptionError) {
44✔
95
        // if we know the location of the error, just throw it
96
        if (error.location.start.line !== -1) {
41✔
97
          context.errors.push(error)
37✔
98
          return resolvedErrorPromise
37✔
99
        } else {
100
          error = error.error // else we try to get the location from source map
4✔
101
        }
102
      }
103

104
      const sourceError = await toSourceError(error, sourceMapJson)
7✔
105
      context.errors.push(sourceError)
7✔
106
      return resolvedErrorPromise
7✔
107
    }
108
  }
109
} satisfies Record<string, Runner>
110

111
export default runners
59✔
112

113
export type RunnerTypes = keyof typeof runners
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