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

source-academy / js-slang / 13622100329

03 Mar 2025 02:25AM UTC coverage: 81.126% (-0.005%) from 81.131%
13622100329

Pull #1743

github

web-flow
Merge 68a52672d into 3c5afad3e
Pull Request #1743: Remove lazy

3440 of 4608 branches covered (74.65%)

Branch coverage included in aggregate %.

13 of 13 new or added lines in 3 files covered. (100.0%)

15 existing lines in 4 files now uncovered.

10762 of 12898 relevant lines covered (83.44%)

134575.29 hits per line

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

93.16
/src/utils/operators.ts
1
import type { BinaryOperator, UnaryOperator } from 'estree'
2

3
import {
74✔
4
  CallingNonFunctionValue,
5
  ExceptionError,
6
  GetInheritedPropertyError,
7
  InvalidNumberOfArguments
8
} from '../errors/errors'
9
import { RuntimeSourceError } from '../errors/runtimeSourceError'
74✔
10
import {
74✔
11
  PotentialInfiniteLoopError,
12
  PotentialInfiniteRecursionError
13
} from '../errors/timeoutErrors'
14
import { Chapter, type NativeStorage } from '../types'
15
import { callExpression, locationDummyNode } from './ast/astCreator'
74✔
16
import * as create from './ast/astCreator'
74✔
17
import { makeWrapper } from './makeWrapper'
74✔
18
import * as rttc from './rttc'
74✔
19

20
export function throwIfTimeout(
74✔
21
  nativeStorage: NativeStorage,
22
  start: number,
23
  current: number,
24
  line: number,
25
  column: number,
26
  source: string | null
27
) {
28
  if (current - start > nativeStorage.maxExecTime) {
15,931,515✔
29
    throw new PotentialInfiniteLoopError(
2✔
30
      create.locationDummyNode(line, column, source),
31
      nativeStorage.maxExecTime
32
    )
33
  }
34
}
35

36
export function callIfFuncAndRightArgs(
74✔
37
  candidate: any,
38
  line: number,
39
  column: number,
40
  source: string | null,
41
  ...args: any[]
42
) {
43
  const dummy = create.callExpression(create.locationDummyNode(line, column, source), args, {
20,004✔
44
    start: { line, column },
45
    end: { line, column }
46
  })
47

48
  if (typeof candidate === 'function') {
20,004✔
49
    const originalCandidate = candidate
19,999✔
50
    if (candidate.transformedFunction !== undefined) {
19,999✔
51
      candidate = candidate.transformedFunction
10,965✔
52
    }
53
    const expectedLength = candidate.length
19,999✔
54
    const receivedLength = args.length
19,999✔
55
    const hasVarArgs = candidate.minArgsNeeded !== undefined
19,999✔
56
    if (hasVarArgs ? candidate.minArgsNeeded > receivedLength : expectedLength !== receivedLength) {
19,999✔
57
      throw new InvalidNumberOfArguments(
11✔
58
        dummy,
59
        hasVarArgs ? candidate.minArgsNeeded : expectedLength,
11✔
60
        receivedLength,
61
        hasVarArgs
62
      )
63
    }
64
    try {
19,988✔
65
      return originalCandidate(...args)
19,988✔
66
    } catch (error) {
67
      // if we already handled the error, simply pass it on
68
      if (!(error instanceof RuntimeSourceError || error instanceof ExceptionError)) {
3,735✔
69
        throw new ExceptionError(error, dummy.loc)
131✔
70
      } else {
71
        throw error
3,604✔
72
      }
73
    }
74
  } else {
75
    throw new CallingNonFunctionValue(candidate, dummy)
5✔
76
  }
77
}
78

79
export function boolOrErr(candidate: any, line: number, column: number, source: string | null) {
74✔
80
  const error = rttc.checkIfStatement(create.locationDummyNode(line, column, source), candidate)
16,002,772✔
81
  if (error === undefined) {
16,002,772✔
82
    return candidate
16,002,771✔
83
  } else {
84
    throw error
1✔
85
  }
86
}
87

88
export function unaryOp(
74✔
89
  operator: UnaryOperator,
90
  argument: any,
91
  line: number,
92
  column: number,
93
  source: string | null
94
) {
95
  const error = rttc.checkUnaryExpression(
44✔
96
    create.locationDummyNode(line, column, source),
97
    operator,
98
    argument
99
  )
100
  if (error === undefined) {
44!
101
    return evaluateUnaryExpression(operator, argument)
44✔
102
  } else {
103
    throw error
×
104
  }
105
}
106

107
export function evaluateUnaryExpression(operator: UnaryOperator, value: any) {
74✔
108
  if (operator === '!') {
145✔
109
    return !value
25✔
110
  } else if (operator === '-') {
120!
111
    return -value
120✔
112
  } else if (operator === 'typeof') {
×
113
    return typeof value
×
114
  } else {
115
    return +value
×
116
  }
117
}
118

119
export function binaryOp(
74✔
120
  operator: BinaryOperator,
121
  chapter: Chapter,
122
  left: any,
123
  right: any,
124
  line: number,
125
  column: number,
126
  source: string | null
127
) {
128
  const error = rttc.checkBinaryExpression(
22,018,646✔
129
    create.locationDummyNode(line, column, source),
130
    operator,
131
    chapter,
132
    left,
133
    right
134
  )
135
  if (error === undefined) {
22,018,646✔
136
    return evaluateBinaryExpression(operator, left, right)
22,018,640✔
137
  } else {
138
    throw error
6✔
139
  }
140
}
141

142
export function evaluateBinaryExpression(operator: BinaryOperator, left: any, right: any) {
74✔
143
  switch (operator) {
23,064,468!
144
    case '+':
145
      return left + right
22,024,980✔
146
    case '-':
147
      return left - right
494,987✔
148
    case '*':
149
      return left * right
193✔
150
    case '/':
151
      return left / right
4,594✔
152
    case '%':
153
      return left % right
54✔
154
    case '===':
155
      return left === right
261,784✔
156
    case '!==':
157
      return left !== right
67✔
158
    case '<=':
159
      return left <= right
255,163✔
160
    case '<':
161
      return left < right
7,083✔
162
    case '>':
163
      return left > right
15,433✔
164
    case '>=':
165
      return left >= right
130✔
166
    default:
167
      return undefined
×
168
  }
169
}
170

171
/**
172
 * Limitations for current properTailCalls implementation:
173
 * Obviously, if objects ({}) are reintroduced,
174
 * we have to change this for a more stringent check,
175
 * as isTail and transformedFunctions are properties
176
 * and may be added by Source code.
177
 */
178
export const callIteratively = (f: any, nativeStorage: NativeStorage, ...args: any[]) => {
74✔
179
  let line = -1
10,959✔
180
  let column = -1
10,959✔
181
  let source: string | null = null
10,959✔
182
  const startTime = Date.now()
10,959✔
183
  const pastCalls: [string, any[]][] = []
10,959✔
184
  while (true) {
10,959✔
185
    const dummy = locationDummyNode(line, column, source)
11,733,570✔
186
    if (typeof f === 'function') {
11,733,570!
187
      if (f.transformedFunction !== undefined) {
11,733,570✔
188
        f = f.transformedFunction
11,720,996✔
189
      }
190
      const expectedLength = f.length
11,733,570✔
191
      const receivedLength = args.length
11,733,570✔
192
      const hasVarArgs = f.minArgsNeeded !== undefined
11,733,570✔
193
      if (hasVarArgs ? f.minArgsNeeded > receivedLength : expectedLength !== receivedLength) {
11,733,570✔
194
        throw new InvalidNumberOfArguments(
1✔
195
          callExpression(dummy, args, {
196
            start: { line, column },
197
            end: { line, column },
198
            source
199
          }),
200
          hasVarArgs ? f.minArgsNeeded : expectedLength,
1!
201
          receivedLength,
202
          hasVarArgs
203
        )
204
      }
205
    } else {
UNCOV
206
      throw new CallingNonFunctionValue(f, dummy)
×
207
    }
208
    let res
209
    try {
11,733,569✔
210
      res = f(...args)
11,733,569✔
211
      if (Date.now() - startTime > nativeStorage.maxExecTime) {
11,729,858✔
212
        throw new PotentialInfiniteRecursionError(dummy, pastCalls, nativeStorage.maxExecTime)
5✔
213
      }
214
    } catch (error) {
215
      // if we already handled the error, simply pass it on
216
      if (!(error instanceof RuntimeSourceError || error instanceof ExceptionError)) {
3,716✔
217
        throw new ExceptionError(error, dummy.loc)
117✔
218
      } else {
219
        throw error
3,599✔
220
      }
221
    }
222
    if (res === null || res === undefined) {
11,729,853✔
223
      return res
28✔
224
    } else if (res.isTail === true) {
11,729,825✔
225
      f = res.function
11,722,611✔
226
      args = res.arguments
11,722,611✔
227
      line = res.line
11,722,611✔
228
      column = res.column
11,722,611✔
229
      source = res.source
11,722,611✔
230
      pastCalls.push([res.functionName, args])
11,722,611✔
231
    } else if (res.isTail === false) {
7,214✔
232
      return res.value
5,612✔
233
    } else {
234
      return res
1,602✔
235
    }
236
  }
237
}
238

239
export const wrap = (
74✔
240
  f: (...args: any[]) => any,
241
  stringified: string,
242
  hasVarArgs: boolean,
243
  nativeStorage: NativeStorage
244
) => {
245
  if (hasVarArgs) {
12,648✔
246
    // @ts-ignore
247
    f.minArgsNeeded = f.length
4✔
248
  }
249
  const wrapped = (...args: any[]) => callIteratively(f, nativeStorage, ...args)
12,648✔
250
  makeWrapper(f, wrapped)
12,648✔
251
  wrapped.transformedFunction = f
12,648✔
252
  wrapped[Symbol.toStringTag] = () => stringified
12,648✔
253
  wrapped.toString = () => stringified
12,648✔
254
  return wrapped
12,648✔
255
}
256

257
export const setProp = (
74✔
258
  obj: any,
259
  prop: any,
260
  value: any,
261
  line: number,
262
  column: number,
263
  source: string | null
264
) => {
265
  const dummy = locationDummyNode(line, column, source)
129✔
266
  const error = rttc.checkMemberAccess(dummy, obj, prop)
129✔
267
  if (error === undefined) {
129✔
268
    return (obj[prop] = value)
127✔
269
  } else {
270
    throw error
2✔
271
  }
272
}
273

274
export const getProp = (
74✔
275
  obj: any,
276
  prop: any,
277
  line: number,
278
  column: number,
279
  source: string | null
280
) => {
281
  const dummy = locationDummyNode(line, column, source)
26✔
282
  const error = rttc.checkMemberAccess(dummy, obj, prop)
26✔
283
  if (error === undefined) {
26✔
284
    if (obj[prop] !== undefined && !obj.hasOwnProperty(prop)) {
23✔
285
      throw new GetInheritedPropertyError(dummy, obj, prop)
1✔
286
    } else {
287
      return obj[prop]
22✔
288
    }
289
  } else {
290
    throw error
3✔
291
  }
292
}
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

© 2025 Coveralls, Inc