ranger-compiler 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/README.md +101 -9
- package/dist/Lang.rgr +362 -20
- package/dist/api.d.ts +881 -47
- package/dist/api.js +13986 -961
- package/dist/lib/IsoDate/DateMath.rgr +219 -0
- package/dist/lib/IsoDate/IsoCalendar.rgr +137 -0
- package/dist/lib/IsoDate/IsoDateParse.rgr +57 -0
- package/dist/lib/IsoDateLib.rgr +15 -0
- package/dist/lib/RangerProcess.rgr +47 -0
- package/dist/lib/Regex/RegexMatch.rgr +134 -0
- package/dist/lib/RegexLib.rgr +10 -0
- package/dist/lib/Time.rgr +2 -1
- package/dist/lib/ranger-dir.rgr +25 -5
- package/dist/package.json +1 -1
- package/dist/rgrc.js +13193 -2715
- package/package.json +150 -7
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
|
|
2
|
+
; Portable calendar math on ISO-8601 date strings (YYYY-MM-DD).
|
|
3
|
+
; No host Date, timezone, or locale — safe to compile to any Ranger target.
|
|
4
|
+
|
|
5
|
+
class DateParts {
|
|
6
|
+
def year:int 2000
|
|
7
|
+
def month:int 1
|
|
8
|
+
def day:int 1
|
|
9
|
+
|
|
10
|
+
static fn fromIso:DateParts (iso:string) {
|
|
11
|
+
def p (new DateParts)
|
|
12
|
+
p.year = (DateMath.parseIsoComponent(iso 0 4))
|
|
13
|
+
p.month = (DateMath.parseIsoComponent(iso 5 2))
|
|
14
|
+
p.day = (DateMath.parseIsoComponent(iso 8 2))
|
|
15
|
+
return p
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
fn toIso:string () {
|
|
19
|
+
return (DateMath.formatIso(this.year this.month this.day))
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class DateMath {
|
|
24
|
+
static fn parseIsoComponent:int (iso:string start:int len:int) {
|
|
25
|
+
def out@(mutable):int 0
|
|
26
|
+
def i@(mutable):int 0
|
|
27
|
+
while (i < len) {
|
|
28
|
+
def ch (charAt iso (start + i))
|
|
29
|
+
out = (out * 10) + (ch - 48)
|
|
30
|
+
i = i + 1
|
|
31
|
+
}
|
|
32
|
+
return out
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static fn intToString:string (n:int) {
|
|
36
|
+
if (n == 0) {
|
|
37
|
+
return "0"
|
|
38
|
+
}
|
|
39
|
+
def digits:[string]
|
|
40
|
+
def v@(mutable):int n
|
|
41
|
+
while (v > 0) {
|
|
42
|
+
def digit (v % 10)
|
|
43
|
+
push digits (DateMath.digitChar(digit))
|
|
44
|
+
v = (floor ((v - digit) / 10))
|
|
45
|
+
}
|
|
46
|
+
def out:string ""
|
|
47
|
+
def cnt (array_length digits)
|
|
48
|
+
def i@(mutable):int (cnt - 1)
|
|
49
|
+
while (i >= 0) {
|
|
50
|
+
out = out + (itemAt digits i)
|
|
51
|
+
i = i - 1
|
|
52
|
+
}
|
|
53
|
+
return out
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static fn digitChar:string (d:int) {
|
|
57
|
+
if (d == 0) {
|
|
58
|
+
return "0"
|
|
59
|
+
}
|
|
60
|
+
if (d == 1) {
|
|
61
|
+
return "1"
|
|
62
|
+
}
|
|
63
|
+
if (d == 2) {
|
|
64
|
+
return "2"
|
|
65
|
+
}
|
|
66
|
+
if (d == 3) {
|
|
67
|
+
return "3"
|
|
68
|
+
}
|
|
69
|
+
if (d == 4) {
|
|
70
|
+
return "4"
|
|
71
|
+
}
|
|
72
|
+
if (d == 5) {
|
|
73
|
+
return "5"
|
|
74
|
+
}
|
|
75
|
+
if (d == 6) {
|
|
76
|
+
return "6"
|
|
77
|
+
}
|
|
78
|
+
if (d == 7) {
|
|
79
|
+
return "7"
|
|
80
|
+
}
|
|
81
|
+
if (d == 8) {
|
|
82
|
+
return "8"
|
|
83
|
+
}
|
|
84
|
+
return "9"
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static fn pad2:string (n:int) {
|
|
88
|
+
if (n < 10) {
|
|
89
|
+
return ("0" + (DateMath.intToString(n)))
|
|
90
|
+
}
|
|
91
|
+
return (DateMath.intToString(n))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
static fn formatIso:string (year:int month:int day:int) {
|
|
95
|
+
return ((DateMath.intToString(year)) + "-" + (DateMath.pad2(month)) + "-" + (DateMath.pad2(day)))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
static fn isLeapYear:boolean (year:int) {
|
|
99
|
+
if ((year % 4) != 0) {
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
102
|
+
if ((year % 100) != 0) {
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
105
|
+
if ((year % 400) != 0) {
|
|
106
|
+
return false
|
|
107
|
+
}
|
|
108
|
+
return true
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static fn daysInMonth:int (year:int month:int) {
|
|
112
|
+
if (month == 2) {
|
|
113
|
+
if ((DateMath.isLeapYear(year))) {
|
|
114
|
+
return 29
|
|
115
|
+
}
|
|
116
|
+
return 28
|
|
117
|
+
}
|
|
118
|
+
if (month == 4) {
|
|
119
|
+
return 30
|
|
120
|
+
}
|
|
121
|
+
if (month == 6) {
|
|
122
|
+
return 30
|
|
123
|
+
}
|
|
124
|
+
if (month == 9) {
|
|
125
|
+
return 30
|
|
126
|
+
}
|
|
127
|
+
if (month == 11) {
|
|
128
|
+
return 30
|
|
129
|
+
}
|
|
130
|
+
return 31
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
static fn subtractOneDay:string (iso:string) {
|
|
134
|
+
def p (DateParts.fromIso(iso))
|
|
135
|
+
p.day = p.day - 1
|
|
136
|
+
if (p.day >= 1) {
|
|
137
|
+
return (p.toIso())
|
|
138
|
+
}
|
|
139
|
+
p.month = p.month - 1
|
|
140
|
+
if (p.month >= 1) {
|
|
141
|
+
p.day = (DateMath.daysInMonth(p.year p.month))
|
|
142
|
+
return (p.toIso())
|
|
143
|
+
}
|
|
144
|
+
p.month = 12
|
|
145
|
+
p.year = p.year - 1
|
|
146
|
+
p.day = (DateMath.daysInMonth(p.year p.month))
|
|
147
|
+
return (p.toIso())
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
static fn addDays:string (iso:string days:int) {
|
|
151
|
+
if (days == 0) {
|
|
152
|
+
def same (DateParts.fromIso(iso))
|
|
153
|
+
return (same.toIso())
|
|
154
|
+
}
|
|
155
|
+
if (days > 0) {
|
|
156
|
+
def p (DateParts.fromIso(iso))
|
|
157
|
+
def remaining@(mutable):int days
|
|
158
|
+
while (remaining > 0) {
|
|
159
|
+
p.day = p.day + 1
|
|
160
|
+
def dim (DateMath.daysInMonth(p.year p.month))
|
|
161
|
+
if (p.day > dim) {
|
|
162
|
+
p.day = 1
|
|
163
|
+
p.month = p.month + 1
|
|
164
|
+
if (p.month > 12) {
|
|
165
|
+
p.month = 1
|
|
166
|
+
p.year = p.year + 1
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
remaining = remaining - 1
|
|
170
|
+
}
|
|
171
|
+
return (p.toIso())
|
|
172
|
+
}
|
|
173
|
+
def remainingNeg@(mutable):int (0 - days)
|
|
174
|
+
def current:string iso
|
|
175
|
+
while (remainingNeg > 0) {
|
|
176
|
+
current = (DateMath.subtractOneDay(current))
|
|
177
|
+
remainingNeg = remainingNeg - 1
|
|
178
|
+
}
|
|
179
|
+
return current
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
static fn compareIso:int (a:string b:string) {
|
|
183
|
+
if (a == b) {
|
|
184
|
+
return 0
|
|
185
|
+
}
|
|
186
|
+
def pa (DateParts.fromIso(a))
|
|
187
|
+
def pb (DateParts.fromIso(b))
|
|
188
|
+
if (pa.year != pb.year) {
|
|
189
|
+
if (pa.year < pb.year) {
|
|
190
|
+
return -1
|
|
191
|
+
}
|
|
192
|
+
return 1
|
|
193
|
+
}
|
|
194
|
+
if (pa.month != pb.month) {
|
|
195
|
+
if (pa.month < pb.month) {
|
|
196
|
+
return -1
|
|
197
|
+
}
|
|
198
|
+
return 1
|
|
199
|
+
}
|
|
200
|
+
if (pa.day < pb.day) {
|
|
201
|
+
return -1
|
|
202
|
+
}
|
|
203
|
+
return 1
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
static fn isBetween:boolean (d:string start:string end:string) {
|
|
207
|
+
if ((DateMath.compareIso(d start)) < 0) {
|
|
208
|
+
return false
|
|
209
|
+
}
|
|
210
|
+
if ((DateMath.compareIso(d end)) > 0) {
|
|
211
|
+
return false
|
|
212
|
+
}
|
|
213
|
+
return true
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
static fn msPerDay:int () {
|
|
217
|
+
return 86400000
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
|
|
2
|
+
Import "DateMath.rgr"
|
|
3
|
+
Import "IsoDateParse.rgr"
|
|
4
|
+
|
|
5
|
+
; ISO week numbers, day-of-week, and calendar offsets (no timezone).
|
|
6
|
+
class IsoCalendar {
|
|
7
|
+
|
|
8
|
+
sfn intDiv:int (numerator:int denominator:int) {
|
|
9
|
+
if (denominator <= 0) {
|
|
10
|
+
return 0
|
|
11
|
+
}
|
|
12
|
+
def num:double (int2double numerator)
|
|
13
|
+
def den:double (int2double denominator)
|
|
14
|
+
return (floor (num / den))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
sfn sakamotoMonthShift:int (month:int) {
|
|
18
|
+
if (month == 1) {
|
|
19
|
+
return 0
|
|
20
|
+
}
|
|
21
|
+
if (month == 2) {
|
|
22
|
+
return 3
|
|
23
|
+
}
|
|
24
|
+
if (month == 3) {
|
|
25
|
+
return 2
|
|
26
|
+
}
|
|
27
|
+
if (month == 4) {
|
|
28
|
+
return 5
|
|
29
|
+
}
|
|
30
|
+
if (month == 5) {
|
|
31
|
+
return 0
|
|
32
|
+
}
|
|
33
|
+
if (month == 6) {
|
|
34
|
+
return 3
|
|
35
|
+
}
|
|
36
|
+
if (month == 7) {
|
|
37
|
+
return 5
|
|
38
|
+
}
|
|
39
|
+
if (month == 8) {
|
|
40
|
+
return 1
|
|
41
|
+
}
|
|
42
|
+
if (month == 9) {
|
|
43
|
+
return 4
|
|
44
|
+
}
|
|
45
|
+
if (month == 10) {
|
|
46
|
+
return 6
|
|
47
|
+
}
|
|
48
|
+
if (month == 11) {
|
|
49
|
+
return 2
|
|
50
|
+
}
|
|
51
|
+
return 4
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
sfn sakamotoDow:int (year:int month:int day:int) {
|
|
55
|
+
def y:int year
|
|
56
|
+
if (month < 3) {
|
|
57
|
+
y = year - 1
|
|
58
|
+
}
|
|
59
|
+
def shift:int (IsoCalendar.sakamotoMonthShift(month))
|
|
60
|
+
def y4:int (IsoCalendar.intDiv(y 4))
|
|
61
|
+
def y100:int (IsoCalendar.intDiv(y 100))
|
|
62
|
+
def y400:int (IsoCalendar.intDiv(y 400))
|
|
63
|
+
def q:int (y + y4 - y100 + y400 + shift + day)
|
|
64
|
+
def r:int (q % 7)
|
|
65
|
+
if (r < 0) {
|
|
66
|
+
r = r + 7
|
|
67
|
+
}
|
|
68
|
+
return r
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
sfn dayOfWeekIso:int (year:int month:int day:int) {
|
|
72
|
+
def dow:int (IsoCalendar.sakamotoDow(year month day))
|
|
73
|
+
if (dow == 0) {
|
|
74
|
+
return 7
|
|
75
|
+
}
|
|
76
|
+
return dow
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
sfn addDaysOffset:string (iso:string days:int) {
|
|
80
|
+
return (DateMath.addDays(iso days))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
sfn daysBetween:int (fromIso:string toIso:string) {
|
|
84
|
+
def count:int 0
|
|
85
|
+
def current:string fromIso
|
|
86
|
+
while ((DateMath.compareIso(current toIso)) < 0) {
|
|
87
|
+
current = (DateMath.addDays(current 1))
|
|
88
|
+
count = count + 1
|
|
89
|
+
if (count > 4000) {
|
|
90
|
+
return 0
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (current == toIso) {
|
|
94
|
+
return count
|
|
95
|
+
}
|
|
96
|
+
return 0
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
sfn pad2:string (n:int) {
|
|
100
|
+
if (n < 10) {
|
|
101
|
+
return ("0" + (DateMath.intToString(n)))
|
|
102
|
+
}
|
|
103
|
+
return (DateMath.intToString(n))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
sfn isoWeekKey:string (iso:string) {
|
|
107
|
+
def dateOnly:string (IsoDateParse.toIsoDateOnly(iso))
|
|
108
|
+
if ((strlen dateOnly) == 0) {
|
|
109
|
+
return ""
|
|
110
|
+
}
|
|
111
|
+
def week:int (IsoCalendar.getIsoWeekNumber(dateOnly))
|
|
112
|
+
if (week <= 0) {
|
|
113
|
+
return ""
|
|
114
|
+
}
|
|
115
|
+
def p:DateParts (DateParts.fromIso(dateOnly))
|
|
116
|
+
def isoDow:int (IsoCalendar.dayOfWeekIso(p.year p.month p.day))
|
|
117
|
+
def toThursday:int (4 - isoDow)
|
|
118
|
+
def thursdayIso:string (IsoCalendar.addDaysOffset(dateOnly toThursday))
|
|
119
|
+
def tp:DateParts (DateParts.fromIso(thursdayIso))
|
|
120
|
+
def isoYear:string (DateMath.intToString(tp.year))
|
|
121
|
+
return (isoYear + "-W" + (IsoCalendar.pad2(week)))
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
sfn getIsoWeekNumber:int (iso:string) {
|
|
125
|
+
def p:DateParts (DateParts.fromIso(iso))
|
|
126
|
+
def isoDow:int (IsoCalendar.dayOfWeekIso(p.year p.month p.day))
|
|
127
|
+
def toThursday:int (4 - isoDow)
|
|
128
|
+
def thursdayIso:string (IsoCalendar.addDaysOffset(iso toThursday))
|
|
129
|
+
def tp:DateParts (DateParts.fromIso(thursdayIso))
|
|
130
|
+
def jan4:string ((DateMath.intToString(tp.year)) + "-01-04")
|
|
131
|
+
def jan4Dow:int (IsoCalendar.dayOfWeekIso(tp.year 1 4))
|
|
132
|
+
def week1Monday:string (IsoCalendar.addDaysOffset(jan4 (1 - jan4Dow)))
|
|
133
|
+
def days:int (IsoCalendar.daysBetween(week1Monday thursdayIso))
|
|
134
|
+
def weeks:int (IsoCalendar.intDiv(days 7))
|
|
135
|
+
return (weeks + 1)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
|
|
2
|
+
Import "DateMath.rgr"
|
|
3
|
+
|
|
4
|
+
; Parse and validate ISO date strings without host locale APIs.
|
|
5
|
+
class IsoDateParse {
|
|
6
|
+
|
|
7
|
+
sfn isDigit:boolean (ch:int) {
|
|
8
|
+
return (ch >= 48 && ch <= 57)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
sfn toIsoDateOnly:string (value:string) {
|
|
12
|
+
if ((strlen value) < 10) {
|
|
13
|
+
return ""
|
|
14
|
+
}
|
|
15
|
+
def candidate:string (substring value 0 10)
|
|
16
|
+
if ((charAt candidate 4) != 45) {
|
|
17
|
+
return ""
|
|
18
|
+
}
|
|
19
|
+
if ((charAt candidate 7) != 45) {
|
|
20
|
+
return ""
|
|
21
|
+
}
|
|
22
|
+
def i:int 0
|
|
23
|
+
while (i < 10) {
|
|
24
|
+
if (i == 4 || i == 7) {
|
|
25
|
+
i = i + 1
|
|
26
|
+
continue
|
|
27
|
+
}
|
|
28
|
+
if ((IsoDateParse.isDigit((charAt candidate i))) == false) {
|
|
29
|
+
return ""
|
|
30
|
+
}
|
|
31
|
+
i = i + 1
|
|
32
|
+
}
|
|
33
|
+
return candidate
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
sfn datePartsToISO:string (year:int month:int day:int) {
|
|
37
|
+
if (year <= 0 || month <= 0 || day <= 0) {
|
|
38
|
+
return ""
|
|
39
|
+
}
|
|
40
|
+
return (DateMath.formatIso(year month day))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
sfn isoDateToYear:int (iso:string) {
|
|
44
|
+
def p:DateParts (DateParts.fromIso(iso))
|
|
45
|
+
return p.year
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
sfn isoDateToMonth:int (iso:string) {
|
|
49
|
+
def p:DateParts (DateParts.fromIso(iso))
|
|
50
|
+
return p.month
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
sfn isoDateToDay:int (iso:string) {
|
|
54
|
+
def p:DateParts (DateParts.fromIso(iso))
|
|
55
|
+
return p.day
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
; Portable ISO-8601 calendar library (date-only, no timezone).
|
|
3
|
+
; Convention: IsoDate = string "YYYY-MM-DD"
|
|
4
|
+
;
|
|
5
|
+
; Modules:
|
|
6
|
+
; IsoDate/DateMath.rgr — addDays, compareIso, isBetween
|
|
7
|
+
; IsoDate/IsoDateParse.rgr — toIsoDateOnly, datePartsToISO
|
|
8
|
+
; IsoDate/IsoCalendar.rgr — ISO week, day-of-week
|
|
9
|
+
;
|
|
10
|
+
; Compiler intrinsics (Lang.rgr): iso_add_days, iso_compare, iso_between
|
|
11
|
+
; Prefer DateMath.addDays in library code; intrinsics optimize hot paths per target.
|
|
12
|
+
|
|
13
|
+
Import "IsoDate/DateMath.rgr"
|
|
14
|
+
Import "IsoDate/IsoDateParse.rgr"
|
|
15
|
+
Import "IsoDate/IsoCalendar.rgr"
|
|
@@ -27,6 +27,7 @@ class RangerProcessBase {
|
|
|
27
27
|
if (uiHost.isUiNotifySuppressed()) {
|
|
28
28
|
return
|
|
29
29
|
}
|
|
30
|
+
uiHost.notifyPathDeliveredCount = uiHost.notifyPathDeliveredCount + 1
|
|
30
31
|
if ((strlen __rangerPath) > 0) {
|
|
31
32
|
uiHost.notifyPath(__rangerPath)
|
|
32
33
|
}
|
|
@@ -55,6 +56,21 @@ class RangerProcessBase {
|
|
|
55
56
|
__rangerChildren = empty
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
; Outermost live ancestor (self if no parent). Used as dispatch-turn root.
|
|
60
|
+
fn __rangerFindRoot:RangerProcessBase () {
|
|
61
|
+
def cur:RangerProcessBase this
|
|
62
|
+
def parent@(optional):RangerProcessBase (cur.__rangerParent)
|
|
63
|
+
while ((null? parent) == false) {
|
|
64
|
+
cur = (unwrap parent)
|
|
65
|
+
parent = cur.__rangerParent
|
|
66
|
+
}
|
|
67
|
+
return cur
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
; Override on app root to merge child pending* into parent before UI notify.
|
|
71
|
+
fn __rangerSyncChildren:void () {
|
|
72
|
+
}
|
|
73
|
+
|
|
58
74
|
fn __rangerInvokeStart:void () {
|
|
59
75
|
}
|
|
60
76
|
|
|
@@ -140,11 +156,17 @@ class ProcessNameRegistry @singleton(true) {
|
|
|
140
156
|
; Hosts may replace notifyPath/notifyId on the singleton instance; markStateDirty respects suppressUiNotify.
|
|
141
157
|
class ProcessUiHost @singleton(true) {
|
|
142
158
|
def __uiNotifySuppressDepth:int 0
|
|
159
|
+
; Test/diagnostic: host notifyPath/notifyId deliveries (not suppressed).
|
|
160
|
+
def notifyPathDeliveredCount:int 0
|
|
143
161
|
|
|
144
162
|
fn isUiNotifySuppressed:boolean () {
|
|
145
163
|
return __uiNotifySuppressDepth > 0
|
|
146
164
|
}
|
|
147
165
|
|
|
166
|
+
fn resetNotifyDeliveryCount:void () {
|
|
167
|
+
notifyPathDeliveredCount = 0
|
|
168
|
+
}
|
|
169
|
+
|
|
148
170
|
fn beginSuppressUiNotify:void () {
|
|
149
171
|
__uiNotifySuppressDepth = __uiNotifySuppressDepth + 1
|
|
150
172
|
}
|
|
@@ -163,6 +185,31 @@ class ProcessUiHost @singleton(true) {
|
|
|
163
185
|
}
|
|
164
186
|
|
|
165
187
|
class ProcessRuntime @singleton(true) {
|
|
188
|
+
def __dispatchTurnDepth:int 0
|
|
189
|
+
|
|
190
|
+
sfn beginDispatchTurn:void (root:RangerProcessBase) {
|
|
191
|
+
def rt:ProcessRuntime (ProcessRuntime.__singleton())
|
|
192
|
+
if (rt.__dispatchTurnDepth == 0) {
|
|
193
|
+
def uiHost:ProcessUiHost (ProcessUiHost.__singleton())
|
|
194
|
+
uiHost.beginSuppressUiNotify()
|
|
195
|
+
}
|
|
196
|
+
rt.__dispatchTurnDepth = rt.__dispatchTurnDepth + 1
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
sfn endDispatchTurn:void (root:RangerProcessBase) {
|
|
200
|
+
def rt:ProcessRuntime (ProcessRuntime.__singleton())
|
|
201
|
+
if (rt.__dispatchTurnDepth == 0) {
|
|
202
|
+
return
|
|
203
|
+
}
|
|
204
|
+
rt.__dispatchTurnDepth = rt.__dispatchTurnDepth - 1
|
|
205
|
+
if (rt.__dispatchTurnDepth > 0) {
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
root.__rangerSyncChildren()
|
|
209
|
+
def uiHost:ProcessUiHost (ProcessUiHost.__singleton())
|
|
210
|
+
uiHost.endSuppressUiNotify()
|
|
211
|
+
root.flushUiNotify()
|
|
212
|
+
}
|
|
166
213
|
|
|
167
214
|
sfn stopInstance:void (proc:RangerProcessBase) {
|
|
168
215
|
ProcessNameRegistry.__singleton().unbindIfConfigured(proc)
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
|
|
2
|
+
; Portable regex search: pattern and haystack are strings (no /literal/ syntax).
|
|
3
|
+
; Semantics match ES6 RegExp(pattern, 'i').test(haystack) — substring search, case-insensitive.
|
|
4
|
+
; Ranger-target implementation supports literals, ., *, ^, $, and \\ escapes.
|
|
5
|
+
; Production targets should use the regex_test compiler intrinsic (native engines).
|
|
6
|
+
|
|
7
|
+
class RegexMatch {
|
|
8
|
+
|
|
9
|
+
static fn testIgnoreCase:boolean (pattern:string haystack:string) {
|
|
10
|
+
def p (to_lowercase pattern)
|
|
11
|
+
def h (to_lowercase haystack)
|
|
12
|
+
return (RegexMatch.searchPattern(p h))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static fn searchPattern:boolean (pat:string text:string) {
|
|
16
|
+
def pLen (strlen pat)
|
|
17
|
+
def tLen (strlen text)
|
|
18
|
+
if (pLen == 0) {
|
|
19
|
+
return true
|
|
20
|
+
}
|
|
21
|
+
def startAnchored:boolean false
|
|
22
|
+
def endAnchored:boolean false
|
|
23
|
+
def coreStart:int 0
|
|
24
|
+
def coreEnd:int pLen
|
|
25
|
+
if ((charAt pat 0) == (ccode "^")) {
|
|
26
|
+
startAnchored = true
|
|
27
|
+
coreStart = 1
|
|
28
|
+
}
|
|
29
|
+
if (pLen > 0) {
|
|
30
|
+
if ((charAt pat (pLen - 1)) == (ccode "$")) {
|
|
31
|
+
endAnchored = true
|
|
32
|
+
coreEnd = pLen - 1
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
def corePat:string (substring pat coreStart (coreEnd - coreStart))
|
|
36
|
+
def cLen (strlen corePat)
|
|
37
|
+
if (cLen == 0) {
|
|
38
|
+
return true
|
|
39
|
+
}
|
|
40
|
+
if (startAnchored) {
|
|
41
|
+
return (RegexMatch.matchAt(corePat 0 text 0 endAnchored))
|
|
42
|
+
}
|
|
43
|
+
def t@(mutable):int 0
|
|
44
|
+
while (t <= tLen) {
|
|
45
|
+
if (RegexMatch.matchAt(corePat 0 text t endAnchored)) {
|
|
46
|
+
return true
|
|
47
|
+
}
|
|
48
|
+
t = t + 1
|
|
49
|
+
}
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static fn matchAt:boolean (pat:string p:int text:string t:int requireEnd:boolean) {
|
|
54
|
+
def pLen (strlen pat)
|
|
55
|
+
def tLen (strlen text)
|
|
56
|
+
if (p >= pLen) {
|
|
57
|
+
if (requireEnd) {
|
|
58
|
+
return t == tLen
|
|
59
|
+
}
|
|
60
|
+
return true
|
|
61
|
+
}
|
|
62
|
+
def ch (charAt pat p)
|
|
63
|
+
if (ch == (ccode "\\")) {
|
|
64
|
+
if ((p + 1) >= pLen) {
|
|
65
|
+
return false
|
|
66
|
+
}
|
|
67
|
+
def esc (charAt pat (p + 1))
|
|
68
|
+
def nextP:int (p + 2)
|
|
69
|
+
if (nextP < pLen) {
|
|
70
|
+
def starCh (charAt pat nextP)
|
|
71
|
+
if (starCh == (ccode "*")) {
|
|
72
|
+
return (RegexMatch.matchStar(esc false nextP pat text t requireEnd))
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (t >= tLen) {
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
if ((charAt text t) != esc) {
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
return (RegexMatch.matchAt(pat nextP text (t + 1) requireEnd))
|
|
82
|
+
}
|
|
83
|
+
if (ch == (ccode ".")) {
|
|
84
|
+
def dotNext:int (p + 1)
|
|
85
|
+
if (dotNext < pLen) {
|
|
86
|
+
def starCh2 (charAt pat dotNext)
|
|
87
|
+
if (starCh2 == (ccode "*")) {
|
|
88
|
+
return (RegexMatch.matchStar((ccode ".") true dotNext pat text t requireEnd))
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (t >= tLen) {
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
return (RegexMatch.matchAt(pat (p + 1) text (t + 1) requireEnd))
|
|
95
|
+
}
|
|
96
|
+
def litNext:int (p + 1)
|
|
97
|
+
if (litNext < pLen) {
|
|
98
|
+
def starCh3 (charAt pat litNext)
|
|
99
|
+
if (starCh3 == (ccode "*")) {
|
|
100
|
+
return (RegexMatch.matchStar(ch false litNext pat text t requireEnd))
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (t >= tLen) {
|
|
104
|
+
return false
|
|
105
|
+
}
|
|
106
|
+
if ((charAt text t) != ch) {
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
109
|
+
return (RegexMatch.matchAt(pat (p + 1) text (t + 1) requireEnd))
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
static fn matchStar:boolean (atomChar:int isDot:boolean starPos:int pat:string text:string t:int requireEnd:boolean) {
|
|
113
|
+
def tLen (strlen text)
|
|
114
|
+
def afterStar:int (starPos + 1)
|
|
115
|
+
def cur@(mutable):int t
|
|
116
|
+
while (cur <= tLen) {
|
|
117
|
+
if (RegexMatch.matchAt(pat afterStar text cur requireEnd)) {
|
|
118
|
+
return true
|
|
119
|
+
}
|
|
120
|
+
if (cur >= tLen) {
|
|
121
|
+
break
|
|
122
|
+
}
|
|
123
|
+
if (isDot) {
|
|
124
|
+
cur = cur + 1
|
|
125
|
+
} {
|
|
126
|
+
if ((charAt text cur) != atomChar) {
|
|
127
|
+
break
|
|
128
|
+
}
|
|
129
|
+
cur = cur + 1
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return false
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
|
|
2
|
+
; String-based regex search (pattern as string, not /literal/ syntax).
|
|
3
|
+
;
|
|
4
|
+
; Modules:
|
|
5
|
+
; Regex/RegexMatch.rgr — testIgnoreCase (portable subset on ranger target)
|
|
6
|
+
;
|
|
7
|
+
; Compiler intrinsic (Lang.rgr): regex_test(pattern, haystack)
|
|
8
|
+
; Prefer regex_test in hot paths; RegexMatch.testIgnoreCase for library code on ranger target.
|
|
9
|
+
|
|
10
|
+
Import "Regex/RegexMatch.rgr"
|
package/dist/lib/Time.rgr
CHANGED