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

source-academy / js-slang / 15235726114

25 May 2025 07:55AM UTC coverage: 77.048%. First build
15235726114

Pull #1742

github

web-flow
Merge d7783cf1e into 0be74e78c
Pull Request #1742: Rewrite: Stepper

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%)

10099 of 12737 relevant lines covered (79.29%)

140954.8 hits per line

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

81.18
/src/tracer/nodes/Expression/UnaryExpression.ts
1
import { Comment, Literal, SourceLocation, UnaryExpression, UnaryOperator } from 'estree'
2
import { StepperBaseNode } from '../../interface'
3
import { redex } from '../..'
61✔
4
import { convert } from '../../generator'
61✔
5
import { StepperExpression, StepperPattern } from '..'
6
import { StepperLiteral } from './Literal'
61✔
7

8
export class StepperUnaryExpression implements UnaryExpression, StepperBaseNode {
61✔
9
  type: 'UnaryExpression'
10
  operator: UnaryOperator
11
  prefix: true
12
  argument: StepperExpression
13
  leadingComments?: Comment[]
14
  trailingComments?: Comment[]
15
  loc?: SourceLocation | null
16
  range?: [number, number]
17

18
  constructor(
19
    operator: UnaryOperator,
20
    argument: StepperExpression,
21
    leadingComments?: Comment[],
22
    trailingComments?: Comment[],
23
    loc?: SourceLocation | null,
24
    range?: [number, number]
25
  ) {
26
    this.type = 'UnaryExpression'
312✔
27
    this.operator = operator
312✔
28
    this.prefix = true
312✔
29
    this.argument = argument
312✔
30
    this.leadingComments = leadingComments
312✔
31
    this.trailingComments = trailingComments
312✔
32
    this.loc = loc
312✔
33
    this.range = range
312✔
34
  }
35

36
  static createLiteral(node: StepperUnaryExpression | UnaryExpression): StepperLiteral | undefined {
37
    // if node argument is positive literal(x) and node operator is "-", we replace them with literal(-x) instead.
38
    if (
316✔
39
      node.operator === '-' &&
356✔
40
      node.argument.type === 'Literal' &&
41
      typeof (node.argument as Literal).value === 'number' &&
42
      ((node.argument as Literal).value as number) > 0
43
    ) {
44
      return new StepperLiteral(
5✔
45
        -((node.argument as Literal).value as number),
46
        (-((node.argument as Literal).value as number)).toString(),
47
        node.leadingComments,
48
        node.trailingComments,
49
        node.loc,
50
        node.range
51
      )
52
    }
53
    return undefined
311✔
54
  }
55

56
  static create(node: UnaryExpression) {
57
    const literal = StepperUnaryExpression.createLiteral(node)
103✔
58
    if (literal) {
103✔
59
      return literal
4✔
60
    }
61
    return new StepperUnaryExpression(
99✔
62
      node.operator,
63
      convert(node.argument) as StepperExpression,
64
      node.leadingComments,
65
      node.trailingComments,
66
      node.loc,
67
      node.range
68
    )
69
  }
70

71
  isContractible(): boolean {
72
    if (this.argument.type !== 'Literal') return false
33✔
73

74
    const valueType = typeof this.argument.value
15✔
75
    const markContractible = () => {
15✔
76
      redex.preRedex = [this]
15✔
77
      return true
15✔
78
    }
79

80
    switch (this.operator) {
15!
81
      case '!':
82
        if (valueType === 'boolean') {
12!
83
          return markContractible()
12✔
84
        } else {
NEW
85
          throw new Error(`Line ${this.loc?.start.line || 0}: Expected boolean, got ${valueType}.`)
×
86
        }
87
      case '-':
88
        if (valueType === 'number') {
3!
89
          return markContractible()
3✔
90
        } else {
NEW
91
          throw new Error(`Line ${this.loc?.start.line || 0}: Expected number, got ${valueType}.`)
×
92
        }
93
      default:
NEW
94
        return false
×
95
    }
96
  }
97

98
  isOneStepPossible(): boolean {
99
    return this.isContractible() || this.argument.isOneStepPossible()
24✔
100
  }
101

102
  contract(): StepperLiteral {
103
    redex.preRedex = [this]
4✔
104
    if (this.argument.type !== 'Literal') throw new Error()
4!
105

106
    const operand = this.argument.value
4✔
107
    if (this.operator === '!') {
4✔
108
      const ret = new StepperLiteral(
3✔
109
        !operand,
110
        undefined,
111
        this.leadingComments,
112
        this.trailingComments,
113
        this.loc,
114
        this.range
115
      )
116
      redex.postRedex = [ret]
3✔
117
      return ret
3✔
118
    } else if (this.operator === '-') {
1✔
119
      const ret = new StepperLiteral(
1✔
120
        -(operand as number),
121
        (-(operand as number)).toString(),
122
        this.leadingComments,
123
        this.trailingComments,
124
        this.loc,
125
        this.range
126
      )
127
      redex.postRedex = [ret]
1✔
128
      return ret
1✔
129
    }
130

NEW
131
    throw new Error()
×
132
  }
133

134
  oneStep(): StepperExpression {
135
    if (this.isContractible()) {
9✔
136
      return this.contract()
4✔
137
    }
138
    const res = new StepperUnaryExpression(
5✔
139
      this.operator,
140
      this.argument.oneStep(),
141
      this.leadingComments,
142
      this.trailingComments,
143
      this.loc,
144
      this.range
145
    )
146
    const literal = StepperUnaryExpression.createLiteral(res)
5✔
147
    return literal ? literal : res
5✔
148
  }
149

150
  substitute(id: StepperPattern, value: StepperExpression): StepperExpression {
151
    const res = new StepperUnaryExpression(
208✔
152
      this.operator,
153
      this.argument.substitute(id, value),
154
      this.leadingComments,
155
      this.trailingComments,
156
      this.loc,
157
      this.range
158
    )
159
    const literal = StepperUnaryExpression.createLiteral(res)
208✔
160
    return literal ? literal : res
208!
161
  }
162

163
  freeNames(): string[] {
NEW
164
    return this.argument.freeNames()
×
165
  }
166

167
  allNames(): string[] {
NEW
168
    return this.argument.allNames()
×
169
  }
170

171
  rename(before: string, after: string): StepperExpression {
NEW
172
    return new StepperUnaryExpression(
×
173
      this.operator,
174
      this.argument.rename(before, after),
175
      this.leadingComments,
176
      this.trailingComments,
177
      this.loc,
178
      this.range
179
    )
180
  }
181
}
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