11local LNumber = require (" nattlua.types.number" ).LNumber
22local LNumberRange = require (" nattlua.types.range" ).LNumberRange
3- --[[ #local type NumericType = any]]
4- local operators = {
5- [" >" ] = function (a --[[ #: number]] , b --[[ #: number]] )
6- return a > b
7- end ,
8- [" <" ] = function (a --[[ #: number]] , b --[[ #: number]] )
9- return a < b
10- end ,
11- [" <=" ] = function (a --[[ #: number]] , b --[[ #: number]] )
12- return a <= b
13- end ,
14- [" >=" ] = function (a --[[ #: number]] , b --[[ #: number]] )
15- return a >= b
16- end ,
17- }
183local max = math.max
194local min = math.min
205
216local function intersect (a_min , a_max , operator , b_min , b_max )
227 if operator == " <" then
23- if a_min < b_min and a_min < b_max and a_max < b_min and a_min < b_max then
24- return min (a_min , b_max ), min (a_max , b_max - 1 ), nil , nil
8+ -- Case 1: A < B is always true (A's upper bound < B's lower bound)
9+ if a_max < b_min then
10+ return a_min , a_max , b_min , b_max , nil , nil , nil , nil
2511 end
26-
27- if a_min >= b_min and a_min >= b_max and a_max >= b_min and a_min >= b_max then
28- return nil , nil , min (b_min , a_max ), min (b_max , a_max )
12+
13+ -- Case 2: A < B is always false (A's lower bound ≥ B's upper bound)
14+ if a_min >= b_max then
15+ return nil , nil , nil , nil , a_min , a_max , b_min , b_max
2916 end
30-
31- return min (a_min , b_max ),
32- min (a_max , b_max - 1 ),
33- min (b_min , a_max ),
34- min (b_max , a_max )
17+
18+ -- Case 3: Ranges overlap, narrowing needed
19+
20+ -- TRUE branch (A < B):
21+ local a_min_true = a_min -- A's lower bound doesn't change
22+ local a_max_true = math.min (a_max , b_max - 1 ) -- A must be less than B's maximum
23+ local b_min_true = math.max (b_min , a_min + 1 ) -- B must be greater than A's minimum
24+ local b_max_true = b_max -- B's upper bound doesn't change
25+
26+ -- FALSE branch (A ≥ B):
27+ local a_min_false = math.max (a_min , b_min ) -- A must be at least B's minimum
28+ local a_max_false = a_max -- A's upper bound doesn't change
29+ local b_min_false = b_min -- B's lower bound doesn't change
30+ local b_max_false = math.min (b_max , a_max ) -- B can't exceed A's maximum
31+
32+ return a_min_true , a_max_true , b_min_true , b_max_true ,
33+ a_min_false , a_max_false , b_min_false , b_max_false
3534 elseif operator == " >" then
36- if a_min > b_min and a_min > b_max and a_max > b_min and a_min > b_max then
37- return max (a_min , b_max ), max (a_max , b_max + 1 ), nil , nil
35+ -- Return value structure:
36+ -- a_min_true, a_max_true, b_min_true, b_max_true, a_min_false, a_max_false, b_min_false, b_max_false
37+
38+ -- Case 1: A > B is always true (A's lower bound > B's upper bound)
39+ if a_min > b_max then
40+ return a_min , a_max , b_min , b_max , nil , nil , nil , nil
3841 end
39-
40- if a_min <= b_min and a_min <= b_max and a_max <= b_min and a_min <= b_max then
41- return nil , nil , max (b_min , a_max ), max (b_max , a_max )
42+
43+ -- Case 2: A > B is always false (A's upper bound ≤ B's lower bound)
44+ if a_max <= b_min then
45+ return nil , nil , nil , nil , a_min , a_max , b_min , b_max
4246 end
43-
44- return max (a_min , b_min + 1 ),
45- max (a_max , b_min ),
46- max (b_min , a_min ),
47- max (b_max , b_min )
47+
48+ -- Case 3: Ranges overlap, narrowing needed
49+
50+ -- TRUE branch (A > B):
51+ local a_min_true = math.max (a_min , b_min + 1 ) -- A must be greater than B's minimum
52+ local a_max_true = a_max -- A's upper bound doesn't change
53+ local b_min_true = b_min -- B's lower bound doesn't change
54+ local b_max_true = math.min (b_max , a_max - 1 ) -- B must be less than A's maximum
55+
56+ -- FALSE branch (A ≤ B):
57+ local a_min_false = a_min -- A's lower bound doesn't change
58+ local a_max_false = math.min (a_max , b_max ) -- A can't exceed B's maximum
59+ local b_min_false = math.max (b_min , a_min ) -- B must be at least A's minimum
60+ local b_max_false = b_max -- B's upper bound doesn't change
61+
62+ return a_min_true , a_max_true , b_min_true , b_max_true ,
63+ a_min_false , a_max_false , b_min_false , b_max_false
4864 elseif operator == " <=" then
49- if a_min <= b_min and a_min <= b_max and a_max <= b_min and a_min <= b_max then
50- return min (a_min , b_max ), min (a_max , b_max ), nil , nil
65+ -- Case 1: A <= B is always true (A's upper bound <= B's lower bound)
66+ if a_max <= b_min then
67+ return a_min , a_max , b_min , b_max , nil , nil , nil , nil
5168 end
52-
53- if a_min > b_min and a_min > b_max and a_max > b_min and a_min > b_max then
54- return nil , nil , min (b_min , a_max ), min (b_max , a_max )
69+
70+ -- Case 2: A <= B is always false (A's lower bound > B's upper bound)
71+ if a_min > b_max then
72+ return nil , nil , nil , nil , a_min , a_max , b_min , b_max
5573 end
56-
57- return min (a_min , b_max ),
58- min (a_max , b_max ),
59- min (b_min , a_max ),
60- min (b_max , a_max - 1 )
74+
75+ -- Case 3: Ranges overlap, narrowing needed
76+
77+ -- TRUE branch (A <= B):
78+ local a_min_true = a_min -- A's lower bound doesn't change
79+ local a_max_true = math.min (a_max , b_max ) -- A must be less than or equal to B's maximum
80+ local b_min_true = math.max (b_min , a_min ) -- B must be at least A's minimum
81+ local b_max_true = b_max -- B's upper bound doesn't change
82+
83+ -- FALSE branch (A > B):
84+ local a_min_false = math.max (a_min , b_max + 1 ) -- A must be greater than B's maximum
85+ local a_max_false = a_max -- A's upper bound doesn't change
86+ local b_min_false = b_min -- B's lower bound doesn't change
87+ local b_max_false = math.min (b_max , a_min - 1 ) -- B must be less than A's minimum
88+
89+ return a_min_true , a_max_true , b_min_true , b_max_true ,
90+ a_min_false , a_max_false , b_min_false , b_max_false
6191 elseif operator == " >=" then
62- if a_min >= b_min and a_min >= b_max and a_max >= b_min and a_min >= b_max then
63- return max (a_min , b_max ), max (a_max , b_max ), nil , nil
92+ -- Case 1: A >= B is always true (A's lower bound >= B's upper bound)
93+ if a_min >= b_max then
94+ return a_min , a_max , b_min , b_max , nil , nil , nil , nil
6495 end
65-
66- if a_min < b_min and a_min < b_max and a_max < b_min and a_min < b_max then
67- return nil , nil , max (b_min , a_max ), max (b_max , a_max )
96+
97+ -- Case 2: A >= B is always false (A's upper bound < B's lower bound)
98+ if a_max < b_min then
99+ return nil , nil , nil , nil , a_min , a_max , b_min , b_max
68100 end
69-
70- return max (a_min , b_min ),
71- max (a_max , b_min ),
72- max (b_min , a_min + 1 ),
73- max (b_max , b_min )
101+
102+ -- Case 3: Ranges overlap, narrowing needed
103+
104+ -- TRUE branch (A >= B):
105+ local a_min_true = math.max (a_min , b_min ) -- A must be at least B's minimum
106+ local a_max_true = a_max -- A's upper bound doesn't change
107+ local b_min_true = b_min -- B's lower bound doesn't change
108+ local b_max_true = math.min (b_max , a_max ) -- B can't exceed A's maximum
109+
110+ -- FALSE branch (A < B):
111+ local a_min_false = a_min -- A's lower bound doesn't change
112+ local a_max_false = math.min (a_max , b_min - 1 ) -- A must be less than B's minimum
113+ local b_min_false = math.max (b_min , a_max + 1 ) -- B must be greater than A's maximum
114+ local b_max_false = b_max -- B's upper bound doesn't change
115+
116+ return a_min_true , a_max_true , b_min_true , b_max_true ,
117+ a_min_false , a_max_false , b_min_false , b_max_false
74118 elseif operator == " ==" then
75- if a_max < b_min or b_max < a_min then return nil , nil , b_min , b_max end
76-
77- if a_min == a_max and b_min == b_max and a_min == b_max then
78- return a_min , a_max , nil , nil
119+ -- Case 1: A == B is impossible (non-overlapping ranges)
120+ if a_max < b_min or b_max < a_min then
121+ return nil , nil , nil , nil , a_min , a_max , b_min , b_max
79122 end
80123
81- if a_min <= b_max and b_min <= a_max then
82- if a_min == a_max and min ( a_max , b_max ) == b_max then
83- return max ( a_min , b_min ), min ( a_max , b_max ), b_min , b_max - 1
84- end
124+ -- Case 2: A == B is always true (both are the same single value)
125+ if a_min == a_max and b_min == b_max and a_min == b_min then
126+ return a_min , a_max , b_min , b_max , nil , nil , nil , nil
127+ end
85128
86- if a_min == a_max and max (a_min , b_min ) == b_min then
87- return max (a_min , b_min ), min (a_max , b_max ), b_min + 1 , b_max
129+ -- Case 3: Ranges overlap, narrowing needed
130+
131+ -- TRUE branch (A == B): intersection of the two ranges
132+ local a_min_true = math.max (a_min , b_min )
133+ local a_max_true = math.min (a_max , b_max )
134+ local b_min_true = a_min_true -- For equality, the ranges must have the same values
135+ local b_max_true = a_max_true
136+
137+ -- FALSE branch (A != B): all values where they don't overlap
138+ local a_min_false1 = a_min
139+ local a_max_false1 = math.min (a_max , b_min - 1 )
140+ local a_min_false2 = math.max (a_min , b_max + 1 )
141+ local a_max_false2 = a_max
142+
143+ local b_min_false1 = b_min
144+ local b_max_false1 = math.min (b_max , a_min - 1 )
145+ local b_min_false2 = math.max (b_min , a_max + 1 )
146+ local b_max_false2 = b_max
147+
148+ -- Combine the false ranges if possible
149+ local a_min_false , a_max_false
150+ if a_max_false1 >= a_min_false1 and a_max_false2 >= a_min_false2 then
151+ a_min_false = math.min (a_min_false1 , a_min_false2 )
152+ a_max_false = math.max (a_max_false1 , a_max_false2 )
153+ elseif a_max_false1 >= a_min_false1 then
154+ a_min_false = a_min_false1
155+ a_max_false = a_max_false1
156+ elseif a_max_false2 >= a_min_false2 then
157+ a_min_false = a_min_false2
158+ a_max_false = a_max_false2
159+ else
160+ a_min_false = nil
161+ a_max_false = nil
162+ end
163+
164+ local b_min_false , b_max_false
165+ if b_max_false1 >= b_min_false1 and b_max_false2 >= b_min_false2 then
166+ b_min_false = math.min (b_min_false1 , b_min_false2 )
167+ b_max_false = math.max (b_max_false1 , b_max_false2 )
168+ elseif b_max_false1 >= b_min_false1 then
169+ b_min_false = b_min_false1
170+ b_max_false = b_max_false1
171+ elseif b_max_false2 >= b_min_false2 then
172+ b_min_false = b_min_false2
173+ b_max_false = b_max_false2
174+ else
175+ b_min_false = nil
176+ b_max_false = nil
88177 end
89178
90- return max ( a_min , b_min ), min ( a_max , b_max ), b_min , b_max
91- end
179+ return a_min_true , a_max_true , b_min_true , b_max_true ,
180+ a_min_false , a_max_false , b_min_false , b_max_false
92181 elseif operator == " ~=" then
93- local x , y , z , w = intersect (b_min , b_max , " ==" , a_min , a_max )
94- return z , w , x , y
182+ -- Implement ~= as the logical inverse of ==
183+ local a_min_true , a_max_true , b_min_true , b_max_true , a_min_false , a_max_false , b_min_false , b_max_false =
184+ intersect (a_min , a_max , " ==" , b_min , b_max )
185+
186+ -- Swap the true and false branches to represent the logical NOT
187+ return a_min_false , a_max_false , b_min_false , b_max_false , a_min_true , a_max_true , b_min_true , b_max_true
95188 end
96189end
97190
98- local function intersect_comparison (a --[[ #: NumericType]] , b --[[ #: NumericType]] , operator --[[ #: keysof<|operators|> ]] )--[[ #: NumericType | nil,NumericType | nil]]
191+ local function intersect_comparison (a --[[ #: NumericType]] , b --[[ #: NumericType]] , operator --[[ #: string ]] )--[[ #: NumericType | nil,NumericType | nil]]
99192 -- TODO: not sure if this makes sense
100193 if a :IsNan () or b :IsNan () then return a , b end
101194
@@ -104,26 +197,41 @@ local function intersect_comparison(a--[[#: NumericType]], b--[[#: NumericType]]
104197 local a_max = a .Type == " range" and a :GetMax () or a .Data or not a .Data and math.huge or a_min
105198 local b_min = b .Type == " range" and b :GetMin () or b .Data or b .Data or - math.huge
106199 local b_max = b .Type == " range" and b :GetMax () or b .Data or not b .Data and math.huge or b_min
107- local a_min_res , a_max_res , b_min_res , b_max_res = intersect (a_min , a_max , operator , b_min , b_max )
108- local result_a , result_b
200+ local a_min_res_true , a_max_res_true , b_min_res_true , b_max_res_true , a_min_res_false , a_max_res_false , b_min_res_false , b_max_res_false = intersect (a_min , a_max , operator , b_min , b_max )
201+ local result_a_true , result_a_false , result_b_true , result_b_false
109202
110- if a_min_res and a_max_res then
111- if a_min_res == a_max_res then
112- result_a = LNumber (a_min_res )
203+ if a_min_res_true and a_max_res_true then
204+ if a_min_res_true == a_max_res_true then
205+ result_a_true = LNumber (a_min_res_true )
206+ else
207+ result_a_true = LNumberRange (a_min_res_true , a_max_res_true )
208+ end
209+ end
210+
211+ if a_min_res_false and a_max_res_false then
212+ if a_min_res_false == a_max_res_false then
213+ result_a_false = LNumber (a_min_res_false )
214+ else
215+ result_a_false = LNumberRange (a_min_res_false , a_max_res_false )
216+ end
217+ end
218+ if b_min_res_true and b_max_res_true then
219+ if b_min_res_true == b_max_res_true then
220+ result_b_true = LNumber (b_min_res_true )
113221 else
114- result_a = LNumberRange (a_min_res , a_max_res )
222+ result_b_true = LNumberRange (b_min_res_true , b_max_res_true )
115223 end
116224 end
117225
118- if b_min_res and b_max_res then
119- if b_min_res == b_max_res then
120- result_b = LNumber (b_min_res )
226+ if b_min_res_false and b_max_res_false then
227+ if b_min_res_false == b_max_res_false then
228+ result_b_false = LNumber (b_min_res_false )
121229 else
122- result_b = LNumberRange (b_min_res , b_max_res )
230+ result_b_false = LNumberRange (b_min_res_false , b_max_res_false )
123231 end
124232 end
125233
126- return result_a , result_b
234+ return result_a_true , result_a_false , result_b_true , result_b_false
127235end
128236
129237return intersect_comparison
0 commit comments