@@ -4,6 +4,7 @@ import { redex } from '../..'
4
4
import { StepperLiteral } from './Literal'
5
5
import { StepperExpression , StepperPattern } from '..'
6
6
import { convert } from '../../generator'
7
+ import { StepperIdentifier } from './Identifier'
7
8
export class StepperBinaryExpression implements BinaryExpression , StepperBaseNode {
8
9
type : 'BinaryExpression'
9
10
operator : BinaryOperator
@@ -46,27 +47,32 @@ export class StepperBinaryExpression implements BinaryExpression, StepperBaseNod
46
47
}
47
48
48
49
isContractible ( ) : boolean {
49
- if ( this . left . type !== 'Literal' || this . right . type !== 'Literal' ) {
50
+ // Check if both operands are literals or special numeric values (NaN, Infinity)
51
+ const isLeftLiteral = this . left . type === 'Literal' ||
52
+ ( this . left . type === 'Identifier' && [ 'NaN' , 'Infinity' ] . includes ( this . left . name ) ) ;
53
+ const isRightLiteral = this . right . type === 'Literal' ||
54
+ ( this . right . type === 'Identifier' && [ 'NaN' , 'Infinity' ] . includes ( this . right . name ) ) ;
55
+
56
+ if ( ! isLeftLiteral || ! isRightLiteral ) {
50
57
return false ;
51
58
}
52
- const left_type = typeof this . left . value
53
- const right_type = typeof this . right . value
54
-
59
+
60
+ // Get values, handling special cases
61
+ const leftValue = this . left . type === 'Literal' ? this . left . value :
62
+ ( this . left . type === 'Identifier' && this . left . name === 'NaN' ? NaN : Infinity ) ;
63
+ const rightValue = this . right . type === 'Literal' ? this . right . value :
64
+ ( this . right . type === 'Identifier' && this . right . name === 'NaN' ? NaN : Infinity ) ;
65
+
66
+ const left_type = typeof leftValue ;
67
+ const right_type = typeof rightValue ;
68
+
55
69
if ( left_type === 'boolean' && right_type === 'boolean' ) {
56
70
const ret = ( this . operator as string ) === '&&' || ( this . operator as string ) === '||'
57
71
if ( ret ) {
58
72
redex . preRedex = [ this ]
59
73
}
60
74
return ret
61
75
} else if ( left_type === 'number' && right_type === 'number' ) {
62
- if ( this . operator === '/' && this . right . value === 0 ) {
63
- throw new Error ( 'Division by zero' ) ;
64
- }
65
-
66
- if ( this . operator === '%' && this . right . value === 0 ) {
67
- throw new Error ( 'Modulo by zero' ) ;
68
- }
69
-
70
76
const ret =
71
77
[ '*' , '+' , '/' , '-' , '===' , '!==' , '<' , '>' , '<=' , '>=' , '%' ] . includes ( this . operator as string )
72
78
if ( ret ) {
@@ -84,57 +90,91 @@ export class StepperBinaryExpression implements BinaryExpression, StepperBaseNod
84
90
85
91
contract ( ) : StepperExpression {
86
92
redex . preRedex = [ this ]
87
- if ( this . left . type !== 'Literal' || this . right . type !== 'Literal' ) throw new Error ( )
88
-
89
- const left = this . left . value
90
- const right = this . right . value
93
+
94
+ // Get values, handling special cases
95
+ const leftValue = this . left . type === 'Literal' ? this . left . value :
96
+ ( this . left . type === 'Identifier' && this . left . name === 'NaN' ? NaN : Infinity ) ;
97
+ const rightValue = this . right . type === 'Literal' ? this . right . value :
98
+ ( this . right . type === 'Identifier' && this . right . name === 'NaN' ? NaN : Infinity ) ;
91
99
92
100
const op = this . operator as string
93
101
94
102
const value =
95
103
( this . operator as string ) === '&&'
96
- ? left && right
104
+ ? leftValue && rightValue
97
105
: op === '||'
98
- ? left || right
99
- : op === '+' && typeof left === 'number' && typeof right === 'number'
100
- ? ( left as number ) + ( right as number )
101
- : op === '+' && typeof left === 'string' && typeof right === 'string'
102
- ? ( left as string ) + ( right as string )
106
+ ? leftValue || rightValue
107
+ : op === '+' && typeof leftValue === 'number' && typeof rightValue === 'number'
108
+ ? ( leftValue as number ) + ( rightValue as number )
109
+ : op === '+' && typeof leftValue === 'string' && typeof rightValue === 'string'
110
+ ? ( leftValue as string ) + ( rightValue as string )
103
111
: op === '-'
104
- ? ( left as number ) - ( right as number )
112
+ ? ( leftValue as number ) - ( rightValue as number )
105
113
: op === '*'
106
- ? ( left as number ) * ( right as number )
114
+ ? ( leftValue as number ) * ( rightValue as number )
107
115
: op === '%'
108
- ? ( left as number ) % ( right as number )
116
+ ? ( leftValue as number ) % ( rightValue as number )
109
117
: op === '/'
110
- ? ( left as number ) / ( right as number )
118
+ ? ( leftValue as number ) / ( rightValue as number )
111
119
: op === '==='
112
- ? left === right
120
+ ? leftValue === rightValue
113
121
: op === '!=='
114
- ? left !== right
122
+ ? leftValue !== rightValue
115
123
: op === '<'
116
- ? left ! < right !
124
+ ? leftValue ! < rightValue !
117
125
: op === '<='
118
- ? left ! <= right !
126
+ ? leftValue ! <= rightValue !
119
127
: op === '>='
120
- ? left ! >= right !
121
- : left ! > right !
122
-
123
- let ret = new StepperLiteral ( value )
124
- redex . postRedex = [ ret ]
125
- return ret
128
+ ? leftValue ! >= rightValue !
129
+ : leftValue ! > rightValue !
130
+
131
+
132
+ let ret : StepperExpression ;
133
+ if ( Number . isNaN ( value ) ) {
134
+ ret = new StepperIdentifier ( 'NaN' ) ;
135
+ } else if ( ! Number . isFinite ( value ) && typeof value === 'number' ) {
136
+ ret = new StepperIdentifier ( 'Infinity' ) ;
137
+ } else {
138
+ ret = new StepperLiteral ( value , undefined , undefined , undefined , this . loc , this . range ) ;
139
+ }
140
+ redex . postRedex = [ ret ] ;
141
+ return ret ;
126
142
}
127
143
128
144
oneStep ( ) : StepperExpression {
129
145
return this . isContractible ( )
130
146
? this . contract ( )
131
147
: this . left . isOneStepPossible ( )
132
- ? new StepperBinaryExpression ( this . operator , this . left . oneStep ( ) , this . right )
133
- : new StepperBinaryExpression ( this . operator , this . left , this . right . oneStep ( ) )
148
+ ? new StepperBinaryExpression (
149
+ this . operator ,
150
+ this . left . oneStep ( ) ,
151
+ this . right ,
152
+ this . leadingComments ,
153
+ this . trailingComments ,
154
+ this . loc ,
155
+ this . range
156
+ )
157
+ : new StepperBinaryExpression (
158
+ this . operator ,
159
+ this . left ,
160
+ this . right . oneStep ( ) ,
161
+ this . leadingComments ,
162
+ this . trailingComments ,
163
+ this . loc ,
164
+ this . range
165
+ )
134
166
}
135
167
136
168
substitute ( id : StepperPattern , value : StepperExpression ) : StepperExpression {
137
- return new StepperBinaryExpression ( this . operator , this . left . substitute ( id , value ) , this . right . substitute ( id , value ) )
169
+ return new StepperBinaryExpression (
170
+ this . operator ,
171
+ this . left . substitute ( id , value ) ,
172
+ this . right . substitute ( id , value ) ,
173
+ this . leadingComments ,
174
+ this . trailingComments ,
175
+ this . loc ,
176
+ this . range
177
+ )
138
178
}
139
179
140
180
freeNames ( ) : string [ ] {
@@ -146,7 +186,14 @@ export class StepperBinaryExpression implements BinaryExpression, StepperBaseNod
146
186
}
147
187
148
188
rename ( before : string , after : string ) : StepperExpression {
149
- return new StepperBinaryExpression ( this . operator ,
150
- this . left . rename ( before , after ) , this . right . rename ( before , after ) ) ;
189
+ return new StepperBinaryExpression (
190
+ this . operator ,
191
+ this . left . rename ( before , after ) ,
192
+ this . right . rename ( before , after ) ,
193
+ this . leadingComments ,
194
+ this . trailingComments ,
195
+ this . loc ,
196
+ this . range
197
+ ) ;
151
198
}
152
199
}
0 commit comments