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

source-academy / js-slang / 6352797471

29 Sep 2023 02:11PM UTC coverage: 82.858%. Remained the same
6352797471

push

github

web-flow
bumping version (#1492)

3633 of 4818 branches covered (0.0%)

Branch coverage included in aggregate %.

10887 of 12706 relevant lines covered (85.68%)

274321.33 hits per line

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

46.23
/src/stepper/lib.ts
1
import * as es from 'estree'
2

3
import * as misc from '../stdlib/misc'
67✔
4
import { Context, substituterNodes } from '../types'
5
import * as ast from '../utils/astCreator'
67✔
6
import { nodeToValue, nodeToValueWithContext, valueToExpression } from './converter'
67✔
7
import { codify } from './stepper'
67✔
8
import { isBuiltinFunction, isNumber } from './util'
67✔
9

10
// define builtins that takes in AST, and return AST
11
//
12
// if (context.chapter >= 1) {
13
//   defineBuiltin(context, 'get_time()', misc.get_time)
14
export function get_time(): es.Literal {
67✔
15
  return ast.literal(misc.get_time())
×
16
}
17

18
//   defineBuiltin(context, 'display(val)', display)
19
//   ignore the "display" capability
20
export function display(val: substituterNodes): substituterNodes {
67✔
21
  return val
×
22
}
23

24
//   defineBuiltin(context, 'raw_display(str)', rawDisplay)
25
//   defineBuiltin(context, 'stringify(val)', stringify)
26
export function stringify(val: substituterNodes): es.Literal {
67✔
27
  return ast.literal(codify(val))
×
28
}
29

30
//   defineBuiltin(context, 'error(str)', misc.error_message)
31
export function error(val: substituterNodes, str?: substituterNodes) {
67✔
32
  const output = (str === undefined ? '' : str + ' ') + stringify(val)
×
33
  throw new Error(output)
×
34
}
35

36
//   defineBuiltin(context, 'prompt(str)', prompt)
37
export function prompt(str: substituterNodes): es.Literal {
67✔
38
  if (str.type !== 'Literal' || typeof str.value !== 'string') {
×
39
    throw new Error('Argument to error must be a string.')
×
40
  }
41
  const result = window.prompt(str.value as string)
×
42
  return ast.literal((result ? result : null) as string)
×
43
}
44

45
//   defineBuiltin(context, 'is_number(val)', misc.is_number)
46
export function is_number(val: substituterNodes): es.Literal {
67✔
47
  return ast.literal(isNumber(val))
×
48
}
49

50
//   defineBuiltin(context, 'is_string(val)', misc.is_string)
51
export function is_string(val: substituterNodes): es.Literal {
67✔
52
  return ast.literal(val.type === 'Literal' && misc.is_string(val.value))
×
53
}
54

55
//   defineBuiltin(context, 'is_function(val)', misc.is_function)
56
export function is_function(val: substituterNodes): es.Literal {
67✔
57
  return ast.literal(val.type.includes('Function') || isBuiltinFunction(val))
431✔
58
}
59

60
//   defineBuiltin(context, 'is_boolean(val)', misc.is_boolean)
61
export function is_boolean(val: substituterNodes): es.Literal {
67✔
62
  return ast.literal(val.type === 'Literal' && misc.is_boolean(val.value))
×
63
}
64

65
//   defineBuiltin(context, 'is_undefined(val)', misc.is_undefined)
66
export function is_undefined(val: substituterNodes): es.Literal {
67✔
67
  return ast.literal(val.type === 'Identifier' && val.name === 'undefined')
×
68
}
69

70
//   defineBuiltin(context, 'parse_int(str, radix)', misc.parse_int)
71
export function parse_int(str: substituterNodes, radix: substituterNodes): es.Expression {
67✔
72
  if (
×
73
    str.type === 'Literal' &&
×
74
    typeof str.value === 'string' &&
75
    radix.type === 'Literal' &&
76
    typeof radix.value === 'number' &&
77
    Number.isInteger(radix.value) &&
78
    2 <= radix.value &&
79
    radix.value <= 36
80
  ) {
81
    return valueToExpression(parseInt(str.value, radix.value))
×
82
  } else {
83
    throw new Error(
×
84
      'parse_int expects two arguments a string s, and a positive integer i between 2 and 36, inclusive.'
85
    )
86
  }
87
}
88

89
//   defineBuiltin(context, 'undefined', undefined)
90
//   defineBuiltin(context, 'NaN', NaN)
91
//   defineBuiltin(context, 'Infinity', Infinity)
92
//   // Define all Math libraries
93
//   const props = Object.getOwnPropertyNames(Math)
94
//   for (const prop of props) {
95
//     defineBuiltin(context, 'math_' + prop, Math[prop])
96
//   }
97
// }
98
// evaluateMath(mathFn: string, ...args: substituterNodes): substituterNodes
99
export function evaluateMath(mathFn: string, ...args: substituterNodes[]): es.Expression {
67✔
100
  const fn = Math[mathFn.split('_')[1]]
4✔
101
  if (!fn) {
4!
102
    throw new Error(`Math function ${mathFn} not found.`)
×
103
  } else if (args.some(arg => !isNumber(arg))) {
4!
104
    throw new Error(`Math functions must be called with number arguments`)
×
105
  }
106
  const jsArgs = args.map(nodeToValue)
4✔
107
  return valueToExpression(fn(...jsArgs))
4✔
108
}
109

110
// evaluateModuleFunction(mathFn: string, context: Context, ...args: substituterNodes): substituterNodes
111
export function evaluateModuleFunction(
67✔
112
  moduleFn: string,
113
  context: Context,
114
  ...args: substituterNodes[]
115
): es.Expression {
116
  const fn = context.runtime.environments[0].head[moduleFn]
×
117
  if (!fn) {
×
118
    throw new Error(`Module function ${moduleFn} not found.`)
×
119
  }
120
  const jsArgs = args.map(arg => nodeToValueWithContext(arg, context))
×
121
  return valueToExpression(fn(...jsArgs), context)
×
122
}
123

124
// if (context.chapter >= 2) {
125
//   // List library
126
//   defineBuiltin(context, 'pair(left, right)', list.pair)
127
export function pair(left: substituterNodes, right: substituterNodes): es.ArrayExpression {
67✔
128
  return ast.arrayExpression([left as es.Expression, right as es.Expression])
38✔
129
}
130

131
//   defineBuiltin(context, 'is_pair(val)', list.is_pair)
132
export function is_pair(val: substituterNodes): es.Literal {
67✔
133
  return ast.literal(val.type === 'ArrayExpression' && val.elements.length === 2)
55✔
134
}
135

136
//   defineBuiltin(context, 'head(xs)', list.head)
137
export function head(xs: substituterNodes): es.Expression {
67✔
138
  if (is_pair(xs).value === false) {
28!
139
    throw new Error(`${codify(xs)} is not a pair`)
×
140
  }
141
  return (xs as es.ArrayExpression).elements[0] as es.Expression
28✔
142
}
143

144
//   defineBuiltin(context, 'tail(xs)', list.tail)
145
export function tail(xs: substituterNodes): es.Expression {
67✔
146
  if (is_pair(xs).value === false) {
27!
147
    throw new Error(`${codify(xs)} is not a pair`)
×
148
  }
149
  return (xs as es.ArrayExpression).elements[1] as es.Expression
27✔
150
}
151

152
//   defineBuiltin(context, 'is_null(val)', list.is_null)
153
export function is_null(val: substituterNodes): es.Literal {
67✔
154
  return ast.literal(val.type === 'Literal' && val.value === null)
38✔
155
}
156

157
//   defineBuiltin(context, 'list(...values)', list.list)
158
export function list(...values: substituterNodes[]): es.ArrayExpression {
67✔
159
  let ret: es.Expression = ast.primitive(null)
4✔
160
  for (const v of values.reverse()) {
4✔
161
    ret = pair(v, ret)
10✔
162
  }
163
  return ret as es.ArrayExpression
4✔
164
}
165
//   defineBuiltin(context, 'draw_data(xs)', visualiseList)
166
export function draw_data(...xs: substituterNodes[]): substituterNodes {
67✔
167
  if (xs.length === 0) {
×
168
    return ast.primitive(undefined)
×
169
  } else {
170
    return xs[0]
×
171
  }
172
}
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