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

source-academy / js-slang / 4684632603

pending completion
4684632603

push

github

GitHub
Add scm-slang to js-slang (#1402)

3526 of 4613 branches covered (76.44%)

Branch coverage included in aggregate %.

183 of 183 new or added lines in 6 files covered. (100.0%)

10522 of 12210 relevant lines covered (86.18%)

130218.03 hits per line

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

86.38
/src/createContext.ts
1
// Variable determining chapter of Source is contained in this file.
2

3
import { GLOBAL, JSSLANG_PROPERTIES } from './constants'
66✔
4
import * as gpu_lib from './gpu/lib'
66✔
5
import * as scheme_libs from './scm-slang/src/stdlib/source-scheme-library'
66✔
6
import { AsyncScheduler } from './schedulers'
66✔
7
import { lazyListPrelude } from './stdlib/lazyList.prelude'
66✔
8
import * as list from './stdlib/list'
66✔
9
import { list_to_vector } from './stdlib/list'
66✔
10
import { listPrelude } from './stdlib/list.prelude'
66✔
11
import { localImportPrelude } from './stdlib/localImport.prelude'
66✔
12
import * as misc from './stdlib/misc'
66✔
13
import { nonDetPrelude } from './stdlib/non-det.prelude'
66✔
14
import * as parser from './stdlib/parser'
66✔
15
import * as stream from './stdlib/stream'
66✔
16
import { streamPrelude } from './stdlib/stream.prelude'
66✔
17
import { createTypeEnvironment, tForAll, tVar } from './typeChecker/utils'
66✔
18
import {
66✔
19
  Chapter,
20
  Context,
21
  CustomBuiltIns,
22
  Environment,
23
  NativeStorage,
24
  Value,
25
  Variant
26
} from './types'
27
import { makeWrapper } from './utils/makeWrapper'
66✔
28
import * as operators from './utils/operators'
66✔
29
import { stringify } from './utils/stringify'
66✔
30

31
export class LazyBuiltIn {
66✔
32
  func: (...arg0: any) => any
33
  evaluateArgs: boolean
34
  constructor(func: (...arg0: any) => any, evaluateArgs: boolean) {
35
    this.func = func
3,149✔
36
    this.evaluateArgs = evaluateArgs
3,149✔
37
  }
38
}
39

40
export class EnvTree {
66✔
41
  private _root: EnvTreeNode | null = null
4,696✔
42
  private map = new Map<Environment, EnvTreeNode>()
4,696✔
43

44
  get root(): EnvTreeNode | null {
45
    return this._root
3✔
46
  }
47

48
  public insert(environment: Environment): void {
49
    const tailEnvironment = environment.tail
290,196✔
50
    if (tailEnvironment === null) {
290,196✔
51
      if (this._root === null) {
3,679✔
52
        this._root = new EnvTreeNode(environment, null)
3,679✔
53
        this.map.set(environment, this._root)
3,679✔
54
      }
55
    } else {
56
      const parentNode = this.map.get(tailEnvironment)
286,517✔
57
      if (parentNode) {
286,517✔
58
        const childNode = new EnvTreeNode(environment, parentNode)
286,517✔
59
        parentNode.addChild(childNode)
286,517✔
60
        this.map.set(environment, childNode)
286,516✔
61
      }
62
    }
63
  }
64

65
  public getTreeNode(environment: Environment): EnvTreeNode | undefined {
66
    return this.map.get(environment)
5✔
67
  }
68
}
69

70
export class EnvTreeNode {
66✔
71
  private _children: EnvTreeNode[] = []
290,197✔
72

73
  constructor(readonly environment: Environment, public parent: EnvTreeNode | null) {}
290,197✔
74

75
  get children(): EnvTreeNode[] {
76
    return this._children
3✔
77
  }
78

79
  public resetChildren(newChildren: EnvTreeNode[]): void {
80
    this.clearChildren()
1✔
81
    this.addChildren(newChildren)
1✔
82
    newChildren.forEach(c => (c.parent = this))
3✔
83
  }
84

85
  private clearChildren(): void {
86
    this._children = []
1✔
87
  }
88

89
  private addChildren(newChildren: EnvTreeNode[]): void {
90
    this._children.push(...newChildren)
1✔
91
  }
92

93
  public addChild(newChild: EnvTreeNode): EnvTreeNode {
94
    this._children.push(newChild)
286,518✔
95
    return newChild
286,518✔
96
  }
97
}
98

99
const createEmptyRuntime = () => ({
3,679✔
100
  break: false,
101
  debuggerOn: true,
102
  isRunning: false,
103
  environmentTree: new EnvTree(),
104
  environments: [],
105
  value: undefined,
106
  nodes: []
107
})
108

109
const createEmptyDebugger = () => ({
3,679✔
110
  observers: { callbacks: Array<() => void>() },
111
  status: false,
112
  state: {
113
    it: (function* (): any {
114
      return
×
115
    })(),
116
    scheduler: new AsyncScheduler()
117
  }
118
})
119

120
export const createGlobalEnvironment = (): Environment => ({
3,679✔
121
  tail: null,
122
  name: 'global',
123
  head: {},
124
  id: '-1'
125
})
126

127
const createNativeStorage = (): NativeStorage => ({
3,679✔
128
  builtins: new Map(),
129
  previousProgramsIdentifiers: new Set(),
130
  operators: new Map(Object.entries(operators)),
131
  gpu: new Map(Object.entries(gpu_lib)),
132
  maxExecTime: JSSLANG_PROPERTIES.maxExecTime,
133
  evaller: null
134
})
135

136
export const createEmptyContext = <T>(
66✔
137
  chapter: Chapter,
138
  variant: Variant = Variant.DEFAULT,
×
139
  externalSymbols: string[],
140
  externalContext?: T
141
): Context<T> => {
142
  return {
3,679✔
143
    chapter,
144
    externalSymbols,
145
    errors: [],
146
    externalContext,
147
    runtime: createEmptyRuntime(),
148
    numberOfOuterEnvironments: 1,
149
    prelude: null,
150
    debugger: createEmptyDebugger(),
151
    nativeStorage: createNativeStorage(),
152
    executionMethod: 'auto',
153
    variant,
154
    moduleContexts: {},
155
    unTypecheckedCode: [],
156
    typeEnvironment: createTypeEnvironment(chapter),
157
    previousPrograms: [],
158
    shouldIncreaseEvaluationTimeout: false
159
  }
160
}
161

162
export const ensureGlobalEnvironmentExist = (context: Context) => {
66✔
163
  if (!context.runtime) {
7,354!
164
    context.runtime = createEmptyRuntime()
×
165
  }
166
  if (!context.runtime.environments) {
7,354!
167
    context.runtime.environments = []
×
168
  }
169
  if (!context.runtime.environmentTree) {
7,354!
170
    context.runtime.environmentTree = new EnvTree()
×
171
  }
172
  if (context.runtime.environments.length === 0) {
7,354✔
173
    const globalEnvironment = createGlobalEnvironment()
3,677✔
174
    context.runtime.environments.push(globalEnvironment)
3,677✔
175
    context.runtime.environmentTree.insert(globalEnvironment)
3,677✔
176
  }
177
}
178

179
export const defineSymbol = (context: Context, name: string, value: Value) => {
66✔
180
  const globalEnvironment = context.runtime.environments[0]
251,523✔
181
  Object.defineProperty(globalEnvironment.head, name, {
251,523✔
182
    value,
183
    writable: false,
184
    enumerable: true
185
  })
186
  context.nativeStorage.builtins.set(name, value)
251,523✔
187
  const typeEnv = context.typeEnvironment[0]
251,523✔
188
  // if the global type env doesn't already have the imported symbol,
189
  // we set it to a type var T that can typecheck with anything.
190
  if (!typeEnv.declKindMap.has(name)) {
251,523✔
191
    typeEnv.typeMap.set(name, tForAll(tVar('T1')))
39,302✔
192
    typeEnv.declKindMap.set(name, 'const')
39,302✔
193
  }
194
}
195

196
export function defineBuiltin(
197
  context: Context,
198
  name: string, // enforce minArgsNeeded
199
  value: Value,
200
  minArgsNeeded: number
201
): void
202
export function defineBuiltin(
203
  context: Context,
204
  name: string,
205
  value: Value,
206
  minArgsNeeded?: number
207
): void
208
// Defines a builtin in the given context
209
// If the builtin is a function, wrap it such that its toString hides the implementation
210
export function defineBuiltin(
66✔
211
  context: Context,
212
  name: string,
213
  value: Value,
214
  minArgsNeeded: undefined | number = undefined
218,967✔
215
) {
216
  if (typeof value === 'function') {
251,523✔
217
    const funName = name.split('(')[0].trim()
213,070✔
218
    const repr = `function ${name} {\n\t[implementation hidden]\n}`
213,070✔
219
    value.toString = () => repr
213,070✔
220
    value.minArgsNeeded = minArgsNeeded
213,070✔
221

222
    defineSymbol(context, funName, value)
213,070✔
223
  } else if (value instanceof LazyBuiltIn) {
38,453✔
224
    const wrapped = (...args: any) => value.func(...args)
39,653✔
225
    const funName = name.split('(')[0].trim()
1,152✔
226
    const repr = `function ${name} {\n\t[implementation hidden]\n}`
1,152✔
227
    wrapped.toString = () => repr
1,152✔
228
    makeWrapper(value.func, wrapped)
1,152✔
229
    defineSymbol(context, funName, new LazyBuiltIn(wrapped, value.evaluateArgs))
1,152✔
230
  } else {
231
    defineSymbol(context, name, value)
37,301✔
232
  }
233
}
234

235
export const importExternalSymbols = (context: Context, externalSymbols: string[]) => {
66✔
236
  ensureGlobalEnvironmentExist(context)
3,677✔
237

238
  externalSymbols.forEach(symbol => {
3,677✔
239
    defineSymbol(context, symbol, GLOBAL[symbol])
×
240
  })
241
}
242

243
/**
244
 * Imports builtins from standard and external libraries.
245
 */
246
export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIns) => {
66✔
247
  ensureGlobalEnvironmentExist(context)
3,677✔
248
  const rawDisplay = (v: Value, ...s: string[]) =>
3,677✔
249
    externalBuiltIns.rawDisplay(v, s[0], context.externalContext)
370✔
250
  const display = (v: Value, ...s: string[]) => {
3,677✔
251
    if (s.length === 1 && s[0] !== undefined && typeof s[0] !== 'string') {
369✔
252
      throw new TypeError('display expects the second argument to be a string')
1✔
253
    }
254
    return rawDisplay(stringify(v), s[0]), v
368✔
255
  }
256
  const displayList = (v: Value, ...s: string[]) => {
3,677✔
257
    if (s.length === 1 && s[0] !== undefined && typeof s[0] !== 'string') {
38✔
258
      throw new TypeError('display_list expects the second argument to be a string')
2✔
259
    }
260
    return list.rawDisplayList(display, v, s[0])
36✔
261
  }
262
  const prompt = (v: Value) => {
3,677✔
263
    const start = Date.now()
×
264
    const promptResult = externalBuiltIns.prompt(v, '', context.externalContext)
×
265
    context.nativeStorage.maxExecTime += Date.now() - start
×
266
    return promptResult
×
267
  }
268
  const alert = (v: Value) => {
3,677✔
269
    const start = Date.now()
×
270
    externalBuiltIns.alert(v, '', context.externalContext)
×
271
    context.nativeStorage.maxExecTime += Date.now() - start
×
272
  }
273
  const visualiseList = (...v: Value) => {
3,677✔
274
    externalBuiltIns.visualiseList(v, context.externalContext)
6✔
275
    return v[0]
6✔
276
  }
277

278
  if (context.chapter >= 1) {
3,677✔
279
    defineBuiltin(context, 'get_time()', misc.get_time)
3,391✔
280
    defineBuiltin(context, 'display(val, prepend = undefined)', display, 1)
3,391✔
281
    defineBuiltin(context, 'raw_display(str, prepend = undefined)', rawDisplay, 1)
3,391✔
282
    defineBuiltin(context, 'stringify(val, indent = 2, maxLineLength = 80)', stringify, 1)
3,391✔
283
    defineBuiltin(context, 'error(str, prepend = undefined)', misc.error_message, 1)
3,391✔
284
    defineBuiltin(context, 'prompt(str)', prompt)
3,391✔
285
    defineBuiltin(context, 'is_number(val)', misc.is_number)
3,391✔
286
    defineBuiltin(context, 'is_string(val)', misc.is_string)
3,391✔
287
    defineBuiltin(context, 'is_function(val)', misc.is_function)
3,391✔
288
    defineBuiltin(context, 'is_boolean(val)', misc.is_boolean)
3,391✔
289
    defineBuiltin(context, 'is_undefined(val)', misc.is_undefined)
3,391✔
290
    defineBuiltin(context, 'parse_int(str, radix)', misc.parse_int)
3,391✔
291
    defineBuiltin(context, 'char_at(str, index)', misc.char_at)
3,391✔
292
    defineBuiltin(context, 'arity(f)', misc.arity)
3,391✔
293
    defineBuiltin(context, 'undefined', undefined)
3,391✔
294
    defineBuiltin(context, 'NaN', NaN)
3,391✔
295
    defineBuiltin(context, 'Infinity', Infinity)
3,391✔
296
    // Define all Math libraries
297
    const mathLibraryNames = Object.getOwnPropertyNames(Math)
3,391✔
298
    // Short param names for stringified version of math functions
299
    const parameterNames = [...'abcdefghijklmnopqrstuvwxyz']
3,391✔
300
    for (const name of mathLibraryNames) {
3,391✔
301
      const value = Math[name]
145,813✔
302
      if (typeof value === 'function') {
145,813✔
303
        let paramString: string
304
        let minArgsNeeded = undefined
118,685✔
305
        if (name === 'max' || name === 'min') {
118,685✔
306
          paramString = '...values'
6,782✔
307
          minArgsNeeded = 0
6,782✔
308
        } else {
309
          paramString = parameterNames.slice(0, value.length).join(', ')
111,903✔
310
        }
311
        defineBuiltin(context, `math_${name}(${paramString})`, value, minArgsNeeded)
118,685✔
312
      } else {
313
        defineBuiltin(context, `math_${name}`, value)
27,128✔
314
      }
315
    }
316
  }
317

318
  if (context.chapter >= 2) {
3,677✔
319
    // List library
320

321
    if (context.variant === Variant.LAZY) {
1,802✔
322
      defineBuiltin(context, 'pair(left, right)', new LazyBuiltIn(list.pair, false))
94✔
323
      defineBuiltin(context, 'list(...values)', new LazyBuiltIn(list.list, false), 0)
94✔
324
      defineBuiltin(context, 'is_pair(val)', new LazyBuiltIn(list.is_pair, true))
94✔
325
      defineBuiltin(context, 'head(xs)', new LazyBuiltIn(list.head, true))
94✔
326
      defineBuiltin(context, 'tail(xs)', new LazyBuiltIn(list.tail, true))
94✔
327
      defineBuiltin(context, 'is_null(val)', new LazyBuiltIn(list.is_null, true))
94✔
328
      defineBuiltin(context, 'draw_data(...xs)', new LazyBuiltIn(visualiseList, true), 1)
94✔
329
      defineBuiltin(context, 'is_list(val)', new LazyBuiltIn(list.is_list, true))
94✔
330
    } else {
331
      defineBuiltin(context, 'pair(left, right)', list.pair)
1,708✔
332
      defineBuiltin(context, 'is_pair(val)', list.is_pair)
1,708✔
333
      defineBuiltin(context, 'head(xs)', list.head)
1,708✔
334
      defineBuiltin(context, 'tail(xs)', list.tail)
1,708✔
335
      defineBuiltin(context, 'is_null(val)', list.is_null)
1,708✔
336
      defineBuiltin(context, 'list(...values)', list.list, 0)
1,708✔
337
      defineBuiltin(context, 'draw_data(...xs)', visualiseList, 1)
1,708✔
338
      defineBuiltin(context, 'display_list(val, prepend = undefined)', displayList, 0)
1,708✔
339
      defineBuiltin(context, 'is_list(val)', list.is_list)
1,708✔
340
    }
341
  }
342

343
  if (context.chapter >= 3) {
3,677✔
344
    defineBuiltin(context, 'set_head(xs, val)', list.set_head)
1,452✔
345
    defineBuiltin(context, 'set_tail(xs, val)', list.set_tail)
1,452✔
346
    defineBuiltin(context, 'array_length(arr)', misc.array_length)
1,452✔
347
    defineBuiltin(context, 'is_array(val)', misc.is_array)
1,452✔
348

349
    // Stream library
350
    defineBuiltin(context, 'stream_tail(stream)', stream.stream_tail)
1,452✔
351
    defineBuiltin(context, 'stream(...values)', stream.stream, 0)
1,452✔
352
  }
353

354
  if (context.chapter >= 4) {
3,677✔
355
    defineBuiltin(context, 'parse(program_string)', (str: string) =>
776✔
356
      parser.parse(str, createContext(context.chapter))
131✔
357
    )
358
    defineBuiltin(context, 'tokenize(program_string)', (str: string) =>
776✔
359
      parser.tokenize(str, createContext(context.chapter))
3✔
360
    )
361
    defineBuiltin(
776✔
362
      context,
363
      'apply_in_underlying_javascript(fun, args)',
364
      // tslint:disable-next-line:ban-types
365
      (fun: Function, args: Value) => fun.apply(fun, list_to_vector(args))
2✔
366
    )
367

368
    if (context.variant === Variant.GPU) {
776✔
369
      defineBuiltin(context, '__clearKernelCache()', gpu_lib.__clearKernelCache)
32✔
370
      defineBuiltin(
32✔
371
        context,
372
        '__createKernelSource(shape, extern, localNames, output, fun, kernelId)',
373
        gpu_lib.__createKernelSource
374
      )
375
    }
376
  }
377

378
  if (context.chapter === Chapter.LIBRARY_PARSER) {
3,677✔
379
    defineBuiltin(context, 'is_object(val)', misc.is_object)
309✔
380
    defineBuiltin(context, 'is_NaN(val)', misc.is_NaN)
309✔
381
    defineBuiltin(context, 'has_own_property(obj, prop)', misc.has_own_property)
309✔
382
    defineBuiltin(context, 'alert(val)', alert)
309✔
383
    // tslint:disable-next-line:ban-types
384
    defineBuiltin(context, 'timed(fun)', (f: Function) =>
309✔
385
      misc.timed(context, f, context.externalContext, externalBuiltIns.rawDisplay)
×
386
    )
387
  }
388

389
  if (context.variant === Variant.LAZY) {
3,677✔
390
    defineBuiltin(context, 'wrapLazyCallee(f)', new LazyBuiltIn(operators.wrapLazyCallee, true))
100✔
391
    defineBuiltin(context, 'makeLazyFunction(f)', new LazyBuiltIn(operators.makeLazyFunction, true))
100✔
392
    defineBuiltin(context, 'forceIt(val)', new LazyBuiltIn(operators.forceIt, true))
100✔
393
    defineBuiltin(context, 'delayIt(xs)', new LazyBuiltIn(operators.delayIt, true))
100✔
394
  }
395

396
  if (context.chapter <= +Chapter.SCHEME_1 && context.chapter >= +Chapter.FULL_SCHEME) {
3,677✔
397
    switch (context.chapter) {
256✔
398
      case Chapter.FULL_SCHEME:
352!
399

400
      case Chapter.SCHEME_4:
401
        // Introduction to eval
402

403
        // Scheme apply
404
        defineBuiltin(context, 'apply(f, ...args)', scheme_libs.apply, 2)
14✔
405

406
      case Chapter.SCHEME_3:
407
        // Introduction to mutable values, streams
408

409
        // Scheme pair mutation
410
        defineBuiltin(context, 'set$45$car$33$(pair, val)', scheme_libs.set_carB)
20✔
411
        defineBuiltin(context, 'set$45$cdr$33$(pair, val)', scheme_libs.set_cdrB)
20✔
412

413
        // Scheme list mutation
414
        defineBuiltin(context, 'list$45$set$33$(xs, n, val)', scheme_libs.list_setB)
20✔
415
        //defineBuiltin(context, 'filter$33$(pred, xs)', scheme_libs.filterB);
416

417
        // Scheme promises
418
        defineBuiltin(context, 'promise$63$()', scheme_libs.promiseQ)
20✔
419
        defineBuiltin(context, 'force(p)', scheme_libs.force)
20✔
420

421
      case Chapter.SCHEME_2:
422
        // Scheme pairs
423
        defineBuiltin(context, 'cons(left, right)', scheme_libs.cons)
52✔
424
        defineBuiltin(context, 'pair$63$(val)', scheme_libs.pairQ)
52✔
425
        defineBuiltin(context, 'car(xs)', scheme_libs.car)
52✔
426
        defineBuiltin(context, 'cdr(xs)', scheme_libs.cdr)
52✔
427

428
        // Scheme lists
429
        defineBuiltin(context, 'make$45$list(n, val)', scheme_libs.make_list, 1)
52✔
430
        defineBuiltin(context, 'list(...values)', scheme_libs.list, 0)
52✔
431
        defineBuiltin(context, 'list$63$(val)', scheme_libs.listQ)
52✔
432
        defineBuiltin(context, 'null$63$(val)', scheme_libs.nullQ)
52✔
433
        defineBuiltin(context, 'length(xs)', scheme_libs.length)
52✔
434
        defineBuiltin(context, 'append(...xs)', scheme_libs.append, 0)
52✔
435
        defineBuiltin(context, 'reverse(xs)', scheme_libs.reverse)
52✔
436
        defineBuiltin(context, 'list$45$tail(xs, n)', scheme_libs.list_tail)
52✔
437
        defineBuiltin(context, 'list$45$ref(xs, n)', scheme_libs.list_ref)
52✔
438
        defineBuiltin(context, 'memq(item, xs)', scheme_libs.memq)
52✔
439
        defineBuiltin(context, 'memv(item, xs)', scheme_libs.memv)
52✔
440
        defineBuiltin(context, 'member(item, xs)', scheme_libs.member)
52✔
441
        defineBuiltin(context, 'assq(item, xs)', scheme_libs.assq)
52✔
442
        defineBuiltin(context, 'assv(item, xs)', scheme_libs.assv)
52✔
443
        defineBuiltin(context, 'assoc(item, xs)', scheme_libs.assoc)
52✔
444
        defineBuiltin(context, 'list$45$copy(xs)', scheme_libs.list_copy)
52✔
445
        defineBuiltin(context, 'map(f, ...xs)', scheme_libs.map, 1)
52✔
446
        defineBuiltin(context, 'filter(pred, xs)', scheme_libs.filter)
52✔
447
        defineBuiltin(context, 'fold(f, init, ...xs)', scheme_libs.fold, 2)
52✔
448
        defineBuiltin(context, 'fold$45$right(f, init, ...xs)', scheme_libs.fold_right, 2)
52✔
449
        defineBuiltin(context, 'reduce(f, rIdentity, xs)', scheme_libs.reduce)
52✔
450

451
        // Scheme symbols
452
        defineBuiltin(context, 'symbol$63$(val)', scheme_libs.symbolQ)
52✔
453
        defineBuiltin(context, 'symbol$61$63$(sym1, sym2)', scheme_libs.symbolEQ)
52✔
454
        defineBuiltin(context, 'symbol$45$$62$string(str)', scheme_libs.symbol_Gstring)
52✔
455
        defineBuiltin(context, 'string$45$$62$symbol(sym)', scheme_libs.string_Gsymbol)
52✔
456

457
        // Scheme strings
458
        defineBuiltin(context, 'string$45$$62$list(str)', scheme_libs.string_Glist)
52✔
459
        defineBuiltin(context, 'list$45$$62$string(xs)', scheme_libs.list_Gstring)
52✔
460

461
      case Chapter.SCHEME_1:
462
        // Display
463
        defineBuiltin(context, 'display(val)', (val: any) =>
256✔
464
          display(scheme_libs.schemeToString(val))
×
465
        )
466
        defineBuiltin(context, 'newline()', scheme_libs.newline)
256✔
467

468
        // I/O
469
        defineBuiltin(context, 'read(str)', () => prompt(''))
256✔
470

471
        // Error
472
        defineBuiltin(context, 'error(str, prepend = undefined)', misc.error_message, 1)
256✔
473

474
        // Scheme truthy and falsy value evaluator
475
        defineBuiltin(context, '$36$true(val)', scheme_libs.$true)
256✔
476

477
        // Scheme equality predicates
478
        defineBuiltin(context, 'eq$63$(...vals)', scheme_libs.eqQ)
256✔
479
        defineBuiltin(context, 'eqv$63$(...vals)', scheme_libs.eqvQ)
256✔
480
        defineBuiltin(context, 'equal$63$(...vals)', scheme_libs.equalQ)
256✔
481

482
        // Scheme basic arithmetic
483
        defineBuiltin(context, '$43$(...vals)', scheme_libs.plus, 0)
256✔
484
        defineBuiltin(context, '$42$(...vals)', scheme_libs.multiply, 0)
256✔
485
        defineBuiltin(context, '$45$(...vals)', scheme_libs.minus, 1)
256✔
486
        defineBuiltin(context, '$47$(...vals)', scheme_libs.divide, 1)
256✔
487

488
        // Scheme comparison
489
        defineBuiltin(context, '$61$(...vals)', scheme_libs.E, 1)
256✔
490
        defineBuiltin(context, '$60$(...vals)', scheme_libs.L, 1)
256✔
491
        defineBuiltin(context, '$62$(...vals)', scheme_libs.G, 1)
256✔
492
        defineBuiltin(context, '$60$$61$(...vals)', scheme_libs.LE, 1)
256✔
493
        defineBuiltin(context, '$62$$61$(...vals)', scheme_libs.GE, 1)
256✔
494

495
        // Scheme math functions
496
        defineBuiltin(context, 'number$63$(val)', scheme_libs.numberQ)
256✔
497
        defineBuiltin(context, 'complex$63$(val)', scheme_libs.complexQ)
256✔
498
        defineBuiltin(context, 'real$63$(val)', scheme_libs.realQ)
256✔
499
        defineBuiltin(context, 'rational$63$(val)', scheme_libs.rationalQ)
256✔
500
        defineBuiltin(context, 'integer$63$(val)', scheme_libs.integerQ)
256✔
501
        defineBuiltin(context, 'exact$63$(val)', scheme_libs.exactQ)
256✔
502
        defineBuiltin(context, 'exact$45$integer$63$(val)', scheme_libs.exact_integerQ)
256✔
503
        defineBuiltin(context, 'zero$63$(val)', scheme_libs.zeroQ)
256✔
504
        defineBuiltin(context, 'positive$63$(val)', scheme_libs.positiveQ)
256✔
505
        defineBuiltin(context, 'negative$63$(val)', scheme_libs.negativeQ)
256✔
506
        defineBuiltin(context, 'odd$63$(val)', scheme_libs.oddQ)
256✔
507
        defineBuiltin(context, 'even$63$(val)', scheme_libs.evenQ)
256✔
508
        defineBuiltin(context, 'max(...vals)', scheme_libs.max, 0)
256✔
509
        defineBuiltin(context, 'min(...vals)', scheme_libs.min, 0)
256✔
510
        defineBuiltin(context, 'abs(val)', scheme_libs.abs)
256✔
511
        defineBuiltin(context, 'quotient(n, d)', scheme_libs.quotient)
256✔
512
        defineBuiltin(context, 'modulo(n, d)', scheme_libs.modulo)
256✔
513
        defineBuiltin(context, 'remainder(n, d)', scheme_libs.remainder)
256✔
514
        defineBuiltin(context, 'gcd(...vals)', scheme_libs.gcd, 0)
256✔
515
        defineBuiltin(context, 'lcm(...vals)', scheme_libs.lcm, 0)
256✔
516
        defineBuiltin(context, 'floor(val)', scheme_libs.floor)
256✔
517
        defineBuiltin(context, 'ceiling(val)', scheme_libs.ceiling)
256✔
518
        defineBuiltin(context, 'truncate(val)', scheme_libs.truncate)
256✔
519
        defineBuiltin(context, 'round(val)', scheme_libs.round)
256✔
520
        defineBuiltin(context, 'square(val)', scheme_libs.square)
256✔
521
        defineBuiltin(context, 'exact$45$integer$45$sqrt(val)', scheme_libs.exact_integer_sqrt)
256✔
522
        defineBuiltin(context, 'expt(base, exp)', scheme_libs.expt)
256✔
523
        defineBuiltin(context, 'number$45$$62$string(val)', scheme_libs.number_Gstring)
256✔
524

525
        // Scheme booleans
526
        defineBuiltin(context, 'boolean$63$(val)', scheme_libs.booleanQ)
256✔
527
        defineBuiltin(context, 'boolean$61$$63$(x, y)', scheme_libs.booleanEQ)
256✔
528
        defineBuiltin(context, 'and(...vals)', scheme_libs.and, 0)
256✔
529
        defineBuiltin(context, 'or(...vals)', scheme_libs.or, 0)
256✔
530
        defineBuiltin(context, 'not(val)', scheme_libs.not)
256✔
531

532
        // Scheme strings
533
        defineBuiltin(context, 'string$63$(val)', scheme_libs.stringQ)
256✔
534
        defineBuiltin(context, 'make$45$string(n, char)', scheme_libs.make_string, 1)
256✔
535
        defineBuiltin(context, 'string(...vals)', scheme_libs.string, 0)
256✔
536
        defineBuiltin(context, 'string$45$length(str)', scheme_libs.string_length)
256✔
537
        defineBuiltin(context, 'string$45$ref(str, k)', scheme_libs.string_ref)
256✔
538
        defineBuiltin(context, 'string$61$$63$(str1, str2)', scheme_libs.stringEQ)
256✔
539
        defineBuiltin(context, 'string$60$$63$(str1, str2)', scheme_libs.stringLQ)
256✔
540
        defineBuiltin(context, 'string$62$$63$(str1, str2)', scheme_libs.stringGQ)
256✔
541
        defineBuiltin(context, 'string$60$$61$$63$(str1, str2)', scheme_libs.stringLEQ)
256✔
542
        defineBuiltin(context, 'string$62$$61$$63$(str1, str2)', scheme_libs.stringGEQ)
256✔
543
        defineBuiltin(context, 'substring(str, start, end)', scheme_libs.substring, 2)
256✔
544
        defineBuiltin(context, 'string$45$append(...vals)', scheme_libs.string_append, 0)
256✔
545
        defineBuiltin(context, 'string$45$copy(str)', scheme_libs.string_copy)
256✔
546
        defineBuiltin(context, 'string$45$map(f, str)', scheme_libs.string_map)
256✔
547
        defineBuiltin(context, 'string$45$for$45$each(f, str)', scheme_libs.string_for_each)
256✔
548
        defineBuiltin(context, 'string$45$$62$number(str)', scheme_libs.string_Gnumber)
256✔
549

550
        // Scheme procedures
551
        defineBuiltin(context, 'procedure$63$(val)', scheme_libs.procedureQ)
256✔
552

553
        break
256✔
554
      default:
555
      //should be unreachable
556
    }
557
  }
558

559
  if (context.chapter <= Chapter.PYTHON_1 && context.chapter >= Chapter.PYTHON_1) {
3,677!
560
    if (context.chapter == Chapter.PYTHON_1) {
×
561
      // Display
562
      defineBuiltin(context, 'get_time()', misc.get_time)
×
563
      defineBuiltin(context, 'print(val)', display, 1)
×
564
      defineBuiltin(context, 'raw_print(str)', rawDisplay, 1)
×
565
      defineBuiltin(context, 'str(val)', (val: any) => stringify(val, 2, 80), 1)
×
566
      defineBuiltin(context, 'error(str)', misc.error_message, 1)
×
567
      defineBuiltin(context, 'prompt(str)', prompt)
×
568
      defineBuiltin(context, 'is_number(val)', misc.is_number)
×
569
      defineBuiltin(context, 'is_string(val)', misc.is_string)
×
570
      defineBuiltin(context, 'is_function(val)', misc.is_function)
×
571
      defineBuiltin(context, 'is_boolean(val)', misc.is_boolean)
×
572
      defineBuiltin(context, 'is_None(val)', misc.is_undefined)
×
573
      defineBuiltin(context, 'parse_int(str, radix)', misc.parse_int)
×
574
      defineBuiltin(context, 'char_at(str, index)', misc.char_at)
×
575
      defineBuiltin(context, 'arity(f)', misc.arity)
×
576
      defineBuiltin(context, 'None', undefined)
×
577
      defineBuiltin(context, 'NaN', NaN)
×
578
      defineBuiltin(context, 'Infinity', Infinity)
×
579
      // Define all Math libraries
580
      const mathLibraryNames = Object.getOwnPropertyNames(Math)
×
581
      // Short param names for stringified version of math functions
582
      const parameterNames = [...'abcdefghijklmnopqrstuvwxyz']
×
583
      for (const name of mathLibraryNames) {
×
584
        const value = Math[name]
×
585
        if (typeof value === 'function') {
×
586
          let paramString: string
587
          let minArgsNeeded = undefined
×
588
          if (name === 'max' || name === 'min') {
×
589
            paramString = '...values'
×
590
            minArgsNeeded = 0
×
591
          } else {
592
            paramString = parameterNames.slice(0, value.length).join(', ')
×
593
          }
594
          defineBuiltin(context, `math_${name}(${paramString})`, value, minArgsNeeded)
×
595
        } else {
596
          defineBuiltin(context, `math_${name}`, value)
×
597
        }
598
      }
599
    }
600
  }
601
}
602

603
function importPrelude(context: Context) {
604
  let prelude = ''
3,677✔
605
  if (context.chapter >= 2) {
3,677✔
606
    prelude += context.variant === Variant.LAZY ? lazyListPrelude : listPrelude
1,802✔
607
    prelude += localImportPrelude
1,802✔
608
  }
609
  if (context.chapter >= 3) {
3,677✔
610
    prelude += streamPrelude
1,452✔
611
  }
612

613
  if (context.variant === Variant.NON_DET) {
3,677✔
614
    prelude += nonDetPrelude
249✔
615
  }
616

617
  if (prelude !== '') {
3,677✔
618
    context.prelude = prelude
1,802✔
619
  }
620
}
621

622
const defaultBuiltIns: CustomBuiltIns = {
66✔
623
  rawDisplay: misc.rawDisplay,
624
  // See issue #5
625
  prompt: misc.rawDisplay,
626
  // See issue #11
627
  alert: misc.rawDisplay,
628
  visualiseList: (_v: Value) => {
629
    throw new Error('List visualizer is not enabled')
×
630
  }
631
}
632

633
const createContext = <T>(
66✔
634
  chapter: Chapter = Chapter.SOURCE_1,
1,014✔
635
  variant: Variant = Variant.DEFAULT,
1,192✔
636
  externalSymbols: string[] = [],
2,065✔
637
  externalContext?: T,
638
  externalBuiltIns: CustomBuiltIns = defaultBuiltIns
2,065✔
639
): Context => {
640
  if (chapter === Chapter.FULL_JS || chapter === Chapter.FULL_TS || chapter === Chapter.PYTHON_1) {
3,698✔
641
    // fullJS will include all builtins and preludes of source 4
642
    return {
21✔
643
      ...createContext(
644
        Chapter.SOURCE_4,
645
        variant,
646
        externalSymbols,
647
        externalContext,
648
        externalBuiltIns
649
      ),
650
      chapter: chapter,
651
      variant: variant
652
    } as Context
653
  }
654
  const context = createEmptyContext(chapter, variant, externalSymbols, externalContext)
3,677✔
655

656
  importBuiltins(context, externalBuiltIns)
3,677✔
657
  importPrelude(context)
3,677✔
658
  importExternalSymbols(context, externalSymbols)
3,677✔
659

660
  return context
3,677✔
661
}
662

663
export default createContext
66✔
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