@lucent-lang/lucent 0.0.4

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.
Files changed (125) hide show
  1. package/app.plugin.js +92 -0
  2. package/bin/lucent.cjs +16 -0
  3. package/core/index.cjs +11 -0
  4. package/dist/bench-CR3E7e2e.js +304 -0
  5. package/dist/build-CAIrRSYA.js +7 -0
  6. package/dist/build-check-QozuNJm5.js +92 -0
  7. package/dist/check-1SCmYlqA.js +7 -0
  8. package/dist/clean-BVwpbJ5K.js +35 -0
  9. package/dist/cli.js +406 -0
  10. package/dist/codes-CIuwXt1S.js +260 -0
  11. package/dist/compiler.js +4 -0
  12. package/dist/confirm-BYF5eY3q.js +34 -0
  13. package/dist/dashboard-B-NzjjaN.js +91 -0
  14. package/dist/dev-BYWMP7oC.js +221 -0
  15. package/dist/diagnostic-BM9sXmwl.js +30 -0
  16. package/dist/diff-BTDo3Sro.js +44 -0
  17. package/dist/doctor-C0PrfWT6.js +230 -0
  18. package/dist/doctor-DdR4JnVc.js +30 -0
  19. package/dist/explain--vV1oaRl.js +35 -0
  20. package/dist/format-D9fnIMEx.js +53 -0
  21. package/dist/init-gIabu1S_.js +207 -0
  22. package/dist/live-steps-BGcWFM9M.js +79 -0
  23. package/dist/new-module-C2mtb0op.js +66 -0
  24. package/dist/package-manager-BnxwCySi.js +30 -0
  25. package/dist/package.json +3 -0
  26. package/dist/packages-HyskKIsY.js +150 -0
  27. package/dist/pipeline-CH7-2cxu.js +232 -0
  28. package/dist/project-D8tEet0k.js +150 -0
  29. package/dist/sdk-coverage-BoW_3Efd.js +64 -0
  30. package/dist/sdk-prefetch-mo04JDZV.js +89 -0
  31. package/dist/sdk-search-Iv4K3-8a.js +124 -0
  32. package/dist/sdk-show-CkrdlqlP.js +74 -0
  33. package/dist/sdks-Xoyiy2E4.js +28 -0
  34. package/dist/src-BD7f1_aZ.js +11493 -0
  35. package/dist/steps--_h-FFS7.js +24 -0
  36. package/dist/theme-uv5bc0aK.js +134 -0
  37. package/dist/tsconfig-S4uyLNzf.js +59 -0
  38. package/dist/version-bqpIO5sP.js +26 -0
  39. package/gradle/lucent-classpath.gradle +38 -0
  40. package/gradle/lucent-classpath.init.gradle +6 -0
  41. package/gradle/lucent.gradle +24 -0
  42. package/lib/core.cjs +106 -0
  43. package/lib/globals.d.ts +36 -0
  44. package/lib/sdk/android.d.ts +8 -0
  45. package/lib/sdk/core.d.ts +23 -0
  46. package/lib/sdk/ios.d.ts +33 -0
  47. package/lib/sdk/platform.d.ts +8 -0
  48. package/lib/sdk/thread.d.ts +8 -0
  49. package/metro/index.cjs +72 -0
  50. package/metro/index.d.ts +6 -0
  51. package/metro/transformer.cjs +70 -0
  52. package/package.json +61 -0
  53. package/runtime/cpp/lucent/abort.cpp +61 -0
  54. package/runtime/cpp/lucent/abort.h +54 -0
  55. package/runtime/cpp/lucent/array.h +442 -0
  56. package/runtime/cpp/lucent/async.h +236 -0
  57. package/runtime/cpp/lucent/builtins.cpp +163 -0
  58. package/runtime/cpp/lucent/bytes.h +129 -0
  59. package/runtime/cpp/lucent/console.h +17 -0
  60. package/runtime/cpp/lucent/core.h +129 -0
  61. package/runtime/cpp/lucent/date.cpp +441 -0
  62. package/runtime/cpp/lucent/date.h +82 -0
  63. package/runtime/cpp/lucent/equality.h +87 -0
  64. package/runtime/cpp/lucent/function.h +61 -0
  65. package/runtime/cpp/lucent/generator.h +244 -0
  66. package/runtime/cpp/lucent/helpers.h +226 -0
  67. package/runtime/cpp/lucent/jserror.cpp +51 -0
  68. package/runtime/cpp/lucent/jserror.h +66 -0
  69. package/runtime/cpp/lucent/jsi/convert.cpp +202 -0
  70. package/runtime/cpp/lucent/jsi/convert.h +612 -0
  71. package/runtime/cpp/lucent/jsi/host.cpp +322 -0
  72. package/runtime/cpp/lucent/jsi/host.h +166 -0
  73. package/runtime/cpp/lucent/json.cpp +243 -0
  74. package/runtime/cpp/lucent/json.h +164 -0
  75. package/runtime/cpp/lucent/json_parse.h +138 -0
  76. package/runtime/cpp/lucent/jsstring.cpp +874 -0
  77. package/runtime/cpp/lucent/jsstring.h +152 -0
  78. package/runtime/cpp/lucent/lucent.h +24 -0
  79. package/runtime/cpp/lucent/map.h +344 -0
  80. package/runtime/cpp/lucent/native.cpp +76 -0
  81. package/runtime/cpp/lucent/native.h +116 -0
  82. package/runtime/cpp/lucent/number.cpp +545 -0
  83. package/runtime/cpp/lucent/number.h +190 -0
  84. package/runtime/cpp/lucent/ops.h +165 -0
  85. package/runtime/cpp/lucent/platform/android.cpp +437 -0
  86. package/runtime/cpp/lucent/platform/android.h +117 -0
  87. package/runtime/cpp/lucent/platform/ios.h +297 -0
  88. package/runtime/cpp/lucent/platform/ios.mm +31 -0
  89. package/runtime/cpp/lucent/regexp.cpp +440 -0
  90. package/runtime/cpp/lucent/regexp.h +107 -0
  91. package/runtime/cpp/lucent/scheduler.cpp +153 -0
  92. package/runtime/cpp/lucent/scheduler.h +160 -0
  93. package/runtime/cpp/lucent/unicode_data.inc +4051 -0
  94. package/runtime/cpp/rn/LucentModule.cpp +35 -0
  95. package/runtime/cpp/rn/LucentModule.h +37 -0
  96. package/runtime/cpp/third_party/quickjs/LICENSE +22 -0
  97. package/runtime/cpp/third_party/quickjs/README.md +11 -0
  98. package/runtime/cpp/third_party/quickjs/cutils.c +641 -0
  99. package/runtime/cpp/third_party/quickjs/cutils.h +457 -0
  100. package/runtime/cpp/third_party/quickjs/libregexp-opcode.h +73 -0
  101. package/runtime/cpp/third_party/quickjs/libregexp.c +3448 -0
  102. package/runtime/cpp/third_party/quickjs/libregexp.h +65 -0
  103. package/runtime/cpp/third_party/quickjs/libunicode-table.h +5206 -0
  104. package/runtime/cpp/third_party/quickjs/libunicode.c +2124 -0
  105. package/runtime/cpp/third_party/quickjs/libunicode.h +196 -0
  106. package/runtime/js/index.d.ts +7 -0
  107. package/runtime/js/index.js +60 -0
  108. package/runtime/native/LucentNative.podspec +28 -0
  109. package/runtime/native/android/CMakeLists.txt +51 -0
  110. package/runtime/native/android/build.gradle +22 -0
  111. package/runtime/native/android/include/lucentnative.h +16 -0
  112. package/runtime/native/android/src/main/java/dev/lucent/LucentPackage.java +25 -0
  113. package/runtime/native/android/src/main/java/dev/lucent/NativeProxy.java +132 -0
  114. package/runtime/native/ios/LucentRegistration.mm +23 -0
  115. package/runtime/native/package.json +6 -0
  116. package/runtime/native/react-native.config.js +19 -0
  117. package/runtime/test/jsi/harness.cpp +181 -0
  118. package/schemas/build.schema.json +152 -0
  119. package/schemas/check.schema.json +74 -0
  120. package/schemas/doctor.schema.json +40 -0
  121. package/schemas/lucent.schema.json +43 -0
  122. package/schemas/sdk-prefetch.schema.json +37 -0
  123. package/schemas/sdk-search.schema.json +54 -0
  124. package/ts-plugin/index.d.ts +4 -0
  125. package/ts-plugin/index.js +99 -0
@@ -0,0 +1,441 @@
1
+ #include "date.h"
2
+
3
+ #include <cmath>
4
+ #include <cstdio>
5
+ #include <ctime>
6
+ #include <string>
7
+
8
+ #include "jserror.h"
9
+ #include "number.h"
10
+
11
+ namespace lucent {
12
+
13
+ namespace {
14
+
15
+ constexpr double kMsPerSecond = 1000;
16
+ constexpr double kMsPerMinute = 60000;
17
+ constexpr double kMsPerHour = 3600000;
18
+ constexpr double kMsPerDay = 86400000;
19
+
20
+ const char* const kDays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
21
+ const char* const kMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
22
+
23
+ double posMod(double a, double b) {
24
+ double r = std::fmod(a, b);
25
+ return r < 0 ? r + b : r;
26
+ }
27
+
28
+ // --- ECMAScript time value algorithms (ECMA-262 §21.4.1) -------------------------------------
29
+
30
+ double day(double t) { return std::floor(t / kMsPerDay); }
31
+ double timeWithinDay(double t) { return posMod(t, kMsPerDay); }
32
+ double daysInYear(double y) {
33
+ if (std::fmod(y, 4) != 0) return 365;
34
+ if (std::fmod(y, 100) != 0) return 366;
35
+ if (std::fmod(y, 400) != 0) return 365;
36
+ return 366;
37
+ }
38
+ double dayFromYear(double y) {
39
+ return 365 * (y - 1970) + std::floor((y - 1969) / 4) - std::floor((y - 1901) / 100) + std::floor((y - 1601) / 400);
40
+ }
41
+ double timeFromYear(double y) { return kMsPerDay * dayFromYear(y); }
42
+ double yearFromTime(double t) {
43
+ double y = std::floor(t / (kMsPerDay * 365.2425)) + 1970;
44
+ while (timeFromYear(y) > t) y--;
45
+ while (timeFromYear(y + 1) <= t) y++;
46
+ return y;
47
+ }
48
+ bool inLeapYear(double t) { return daysInYear(yearFromTime(t)) == 366; }
49
+ double dayWithinYear(double t) { return day(t) - dayFromYear(yearFromTime(t)); }
50
+
51
+ // First day of each month in a common year, and in a leap year.
52
+ const int kMonthStart[2][13] = {{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
53
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
54
+
55
+ double monthFromTime(double t) {
56
+ double d = dayWithinYear(t);
57
+ const int* starts = kMonthStart[inLeapYear(t) ? 1 : 0];
58
+ int m = 0;
59
+ while (m < 11 && d >= starts[m + 1]) m++;
60
+ return m;
61
+ }
62
+ double dateFromTime(double t) {
63
+ return dayWithinYear(t) - kMonthStart[inLeapYear(t) ? 1 : 0][static_cast<int>(monthFromTime(t))] + 1;
64
+ }
65
+ double weekDay(double t) { return posMod(day(t) + 4, 7); }
66
+ double hourFromTime(double t) { return posMod(std::floor(t / kMsPerHour), 24); }
67
+ double minFromTime(double t) { return posMod(std::floor(t / kMsPerMinute), 60); }
68
+ double secFromTime(double t) { return posMod(std::floor(t / kMsPerSecond), 60); }
69
+ double msFromTime(double t) { return posMod(t, kMsPerSecond); }
70
+
71
+ double makeTime(double h, double m, double s, double ms) {
72
+ if (!std::isfinite(h) || !std::isfinite(m) || !std::isfinite(s) || !std::isfinite(ms)) return kNaN;
73
+ return std::trunc(h) * kMsPerHour + std::trunc(m) * kMsPerMinute + std::trunc(s) * kMsPerSecond + std::trunc(ms);
74
+ }
75
+ double makeDay(double year, double month, double date) {
76
+ if (!std::isfinite(year) || !std::isfinite(month) || !std::isfinite(date)) return kNaN;
77
+ double y = std::trunc(year), m = std::trunc(month), dt = std::trunc(date);
78
+ double ym = y + std::floor(m / 12);
79
+ if (std::fabs(ym) > 400000) return kNaN;
80
+ int mn = static_cast<int>(posMod(m, 12));
81
+ double first = dayFromYear(ym) + kMonthStart[daysInYear(ym) == 366 ? 1 : 0][mn];
82
+ return first + dt - 1;
83
+ }
84
+ double timeValue(double dayValue, double time) {
85
+ if (!std::isfinite(dayValue) || !std::isfinite(time)) return kNaN;
86
+ double tv = dayValue * kMsPerDay + time;
87
+ return std::isfinite(tv) ? tv : kNaN;
88
+ }
89
+ double timeClip(double t) {
90
+ if (!std::isfinite(t) || std::fabs(t) > 8.64e15) return kNaN;
91
+ return std::trunc(t) + 0.0; // + 0.0 turns -0 into +0
92
+ }
93
+
94
+ // --- local time ----------------------------------------------------------------------------------
95
+
96
+ /// The zone's offset from UTC at the UTC instant `t`, in milliseconds.
97
+ double offsetAt(double t) {
98
+ if (!std::isfinite(t)) return 0;
99
+ std::time_t secs = static_cast<std::time_t>(std::floor(t / kMsPerSecond));
100
+ std::tm tm{};
101
+ if (!::localtime_r(&secs, &tm)) return 0;
102
+ return static_cast<double>(tm.tm_gmtoff) * kMsPerSecond;
103
+ }
104
+ double localTime(double t) { return t + offsetAt(t); }
105
+
106
+ /// The UTC instant of local time `t`. Offsets a day before and after bracket
107
+ /// any transition: a time valid with both (no transition, or the fall-back
108
+ /// overlap) resolves to the earlier instant; a time valid with neither (the
109
+ /// spring-forward gap) uses the offset before the transition.
110
+ double utcFromLocal(double t) {
111
+ if (!std::isfinite(t)) return kNaN;
112
+ double before = offsetAt(t - kMsPerDay), after = offsetAt(t + kMsPerDay);
113
+ double ub = t - before, ua = t - after;
114
+ bool okBefore = offsetAt(ub) == before, okAfter = offsetAt(ua) == after;
115
+ if (okBefore && okAfter) return std::min(ub, ua);
116
+ if (okAfter) return ua;
117
+ return ub;
118
+ }
119
+
120
+ std::string pad(double v, int width) {
121
+ char buf[32];
122
+ std::snprintf(buf, sizeof buf, "%0*lld", width, static_cast<long long>(v));
123
+ return buf;
124
+ }
125
+ std::string yearString(double y) {
126
+ if (y >= 0) return pad(y, 4);
127
+ return "-" + pad(-y, 6);
128
+ }
129
+ std::string offsetString(double offsetMs) {
130
+ double mins = offsetMs / kMsPerMinute;
131
+ char sign = mins < 0 ? '-' : '+';
132
+ mins = std::fabs(mins);
133
+ return std::string("GMT") + sign + pad(std::floor(mins / 60), 2) + pad(std::fmod(mins, 60), 2);
134
+ }
135
+ std::string datePart(double lt) {
136
+ return std::string(kDays[static_cast<int>(weekDay(lt))]) + " " + kMonths[static_cast<int>(monthFromTime(lt))] + " " + pad(dateFromTime(lt), 2) + " " +
137
+ yearString(yearFromTime(lt));
138
+ }
139
+ std::string timePart(double lt) { return pad(hourFromTime(lt), 2) + ":" + pad(minFromTime(lt), 2) + ":" + pad(secFromTime(lt), 2); }
140
+
141
+ // --- parsing -------------------------------------------------------------------------------------
142
+
143
+ struct Cursor {
144
+ std::string s;
145
+ size_t i = 0;
146
+ bool done() const { return i >= s.size(); }
147
+ char peek() const { return done() ? '\0' : s[i]; }
148
+ bool eat(char c) {
149
+ if (peek() != c) return false;
150
+ i++;
151
+ return true;
152
+ }
153
+ /// Exactly `n` digits.
154
+ bool digits(int n, double& out) {
155
+ if (i + n > s.size()) return false;
156
+ double v = 0;
157
+ for (int k = 0; k < n; k++) {
158
+ char c = s[i + k];
159
+ if (c < '0' || c > '9') return false;
160
+ v = v * 10 + (c - '0');
161
+ }
162
+ i += n;
163
+ out = v;
164
+ return true;
165
+ }
166
+ /// One or more digits.
167
+ bool number(double& out) {
168
+ size_t start = i;
169
+ double v = 0;
170
+ while (!done() && s[i] >= '0' && s[i] <= '9') v = v * 10 + (s[i++] - '0');
171
+ out = v;
172
+ return i > start;
173
+ }
174
+ void spaces() {
175
+ while (!done() && (s[i] == ' ' || s[i] == ',')) i++;
176
+ }
177
+ std::string word() {
178
+ size_t start = i;
179
+ while (!done() && ((s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z'))) i++;
180
+ return s.substr(start, i - start);
181
+ }
182
+ };
183
+
184
+ double parseIso(const std::string& text) {
185
+ Cursor c{text};
186
+ double year, month = 1, dayOfMonth = 1, h = 0, m = 0, s = 0, ms = 0;
187
+ if (c.peek() == '+' || c.peek() == '-') {
188
+ bool neg = c.peek() == '-';
189
+ c.i++;
190
+ if (!c.digits(6, year)) return kNaN;
191
+ if (neg && year == 0) return kNaN;
192
+ if (neg) year = -year;
193
+ } else if (!c.digits(4, year)) {
194
+ return kNaN;
195
+ }
196
+ if (c.eat('-')) {
197
+ if (!c.digits(2, month) || month < 1 || month > 12) return kNaN;
198
+ if (c.eat('-') && (!c.digits(2, dayOfMonth) || dayOfMonth < 1 || dayOfMonth > 31)) return kNaN;
199
+ }
200
+ bool hasTime = false, hasOffset = false;
201
+ double offset = 0;
202
+ if (c.eat('T')) {
203
+ hasTime = true;
204
+ if (!c.digits(2, h) || !c.eat(':') || !c.digits(2, m)) return kNaN;
205
+ if (c.eat(':')) {
206
+ if (!c.digits(2, s)) return kNaN;
207
+ if (c.eat('.')) {
208
+ size_t start = c.i;
209
+ double frac;
210
+ if (!c.number(frac)) return kNaN;
211
+ std::string digits = text.substr(start, c.i - start);
212
+ digits.resize(3, '0');
213
+ ms = std::stod(digits);
214
+ }
215
+ }
216
+ if (h > 24 || m > 59 || s > 59 || (h == 24 && (m > 0 || s > 0 || ms > 0))) return kNaN;
217
+ if (c.eat('Z')) {
218
+ hasOffset = true;
219
+ } else if (c.peek() == '+' || c.peek() == '-') {
220
+ double sign = c.peek() == '-' ? -1 : 1;
221
+ c.i++;
222
+ double oh, om;
223
+ if (!c.digits(2, oh) || !c.eat(':') || !c.digits(2, om) || oh > 23 || om > 59) return kNaN;
224
+ hasOffset = true;
225
+ offset = sign * (oh * kMsPerHour + om * kMsPerMinute);
226
+ }
227
+ }
228
+ if (!c.done()) return kNaN;
229
+ double t = timeValue(makeDay(year, month - 1, dayOfMonth), makeTime(h, m, s, ms));
230
+ // Date-only forms are UTC; date-times without an offset are local.
231
+ if (hasTime && !hasOffset) return timeClip(utcFromLocal(t));
232
+ return timeClip(t - offset);
233
+ }
234
+
235
+ int monthIndex(const std::string& w) {
236
+ for (int i = 0; i < 12; i++) {
237
+ if (w.size() >= 3 && (w[0] | 32) == (kMonths[i][0] | 32) && (w[1] | 32) == kMonths[i][1] && (w[2] | 32) == kMonths[i][2]) return i;
238
+ }
239
+ return -1;
240
+ }
241
+
242
+ /// "Mon Jul 22 2019 15:51:50 GMT-0700 (…)" and "Mon, 22 Jul 2019 22:51:50 GMT".
243
+ double parseLegacy(const std::string& text) {
244
+ Cursor c{text};
245
+ c.spaces();
246
+ std::string w = c.word();
247
+ if (!w.empty() && monthIndex(w) < 0) {
248
+ c.spaces(); // weekday
249
+ w = c.word();
250
+ }
251
+ double dayOfMonth, year;
252
+ int month;
253
+ if (!w.empty()) { // "Jul 22 2019"
254
+ month = monthIndex(w);
255
+ c.spaces();
256
+ if (month < 0 || !c.number(dayOfMonth)) return kNaN;
257
+ } else { // "22 Jul 2019"
258
+ if (!c.number(dayOfMonth)) return kNaN;
259
+ c.spaces();
260
+ month = monthIndex(c.word());
261
+ if (month < 0) return kNaN;
262
+ }
263
+ c.spaces();
264
+ bool negYear = c.eat('-');
265
+ if (!c.number(year)) return kNaN;
266
+ if (negYear) year = -year;
267
+ double h = 0, m = 0, s = 0;
268
+ c.spaces();
269
+ if (c.number(h)) {
270
+ if (!c.eat(':') || !c.number(m)) return kNaN;
271
+ if (c.eat(':') && !c.number(s)) return kNaN;
272
+ }
273
+ c.spaces();
274
+ bool hasZone = false;
275
+ double offset = 0;
276
+ std::string zone = c.word();
277
+ if (zone == "GMT" || zone == "UTC" || zone == "Z") {
278
+ hasZone = true;
279
+ if (c.peek() == '+' || c.peek() == '-') {
280
+ double sign = c.peek() == '-' ? -1 : 1;
281
+ c.i++;
282
+ double hhmm;
283
+ size_t start = c.i;
284
+ if (!c.number(hhmm) || c.i - start != 4) return kNaN;
285
+ offset = sign * (std::floor(hhmm / 100) * kMsPerHour + std::fmod(hhmm, 100) * kMsPerMinute);
286
+ }
287
+ } else if (!zone.empty()) {
288
+ return kNaN;
289
+ }
290
+ c.spaces();
291
+ if (c.eat('(')) {
292
+ while (!c.done() && c.peek() != ')') c.i++;
293
+ if (!c.eat(')')) return kNaN;
294
+ }
295
+ c.spaces();
296
+ if (!c.done()) return kNaN;
297
+ double t = timeValue(makeDay(year, month, dayOfMonth), makeTime(h, m, s, 0));
298
+ return timeClip(hasZone ? t - offset : utcFromLocal(t));
299
+ }
300
+
301
+ } // namespace
302
+
303
+ DateObject::DateObject(double t) : t_(timeClip(t)) {}
304
+
305
+ double DateObject::setTime(double t) { return t_ = timeClip(t); }
306
+
307
+ #define LUCENT_LOCAL(fn, expr) \
308
+ double DateObject::fn() const { \
309
+ if (std::isnan(t_)) return kNaN; \
310
+ double t = localTime(t_); \
311
+ return expr; \
312
+ }
313
+ #define LUCENT_UTC(fn, expr) \
314
+ double DateObject::fn() const { \
315
+ if (std::isnan(t_)) return kNaN; \
316
+ double t = t_; \
317
+ return expr; \
318
+ }
319
+ LUCENT_LOCAL(getFullYear, yearFromTime(t))
320
+ LUCENT_LOCAL(getMonth, monthFromTime(t))
321
+ LUCENT_LOCAL(getDate, dateFromTime(t))
322
+ LUCENT_LOCAL(getDay, weekDay(t))
323
+ LUCENT_LOCAL(getHours, hourFromTime(t))
324
+ LUCENT_LOCAL(getMinutes, minFromTime(t))
325
+ LUCENT_LOCAL(getSeconds, secFromTime(t))
326
+ LUCENT_LOCAL(getMilliseconds, msFromTime(t))
327
+ LUCENT_UTC(getUTCFullYear, yearFromTime(t))
328
+ LUCENT_UTC(getUTCMonth, monthFromTime(t))
329
+ LUCENT_UTC(getUTCDate, dateFromTime(t))
330
+ LUCENT_UTC(getUTCDay, weekDay(t))
331
+ LUCENT_UTC(getUTCHours, hourFromTime(t))
332
+ LUCENT_UTC(getUTCMinutes, minFromTime(t))
333
+ LUCENT_UTC(getUTCSeconds, secFromTime(t))
334
+ LUCENT_UTC(getUTCMilliseconds, msFromTime(t))
335
+ #undef LUCENT_LOCAL
336
+ #undef LUCENT_UTC
337
+
338
+ double DateObject::getTimezoneOffset() const {
339
+ if (std::isnan(t_)) return kNaN;
340
+ return (t_ - localTime(t_)) / kMsPerMinute;
341
+ }
342
+
343
+ double DateObject::setLocal(bool utc, double date, double time) {
344
+ double v = timeValue(date, time);
345
+ return t_ = timeClip(utc ? v : utcFromLocal(v));
346
+ }
347
+
348
+ // Each setter reads the current fields in local time (or UTC), replaces the
349
+ // given ones and recomputes the time value.
350
+ #define LUCENT_SETTERS(Prefix, utc, now) \
351
+ double DateObject::set##Prefix##FullYear(double y, Opt<double> m, Opt<double> d) { \
352
+ double t = std::isnan(t_) ? 0 : now; \
353
+ return setLocal(utc, makeDay(y, m.has() ? m.get() : monthFromTime(t), d.has() ? d.get() : dateFromTime(t)), timeWithinDay(t)); \
354
+ } \
355
+ double DateObject::set##Prefix##Month(double m, Opt<double> d) { \
356
+ if (std::isnan(t_)) return kNaN; \
357
+ double t = now; \
358
+ return setLocal(utc, makeDay(yearFromTime(t), m, d.has() ? d.get() : dateFromTime(t)), timeWithinDay(t)); \
359
+ } \
360
+ double DateObject::set##Prefix##Date(double d) { \
361
+ if (std::isnan(t_)) return kNaN; \
362
+ double t = now; \
363
+ return setLocal(utc, makeDay(yearFromTime(t), monthFromTime(t), d), timeWithinDay(t)); \
364
+ } \
365
+ double DateObject::set##Prefix##Hours(double h, Opt<double> m, Opt<double> s, Opt<double> ms) { \
366
+ if (std::isnan(t_)) return kNaN; \
367
+ double t = now; \
368
+ return setLocal(utc, day(t), makeTime(h, m.has() ? m.get() : minFromTime(t), s.has() ? s.get() : secFromTime(t), ms.has() ? ms.get() : msFromTime(t))); \
369
+ } \
370
+ double DateObject::set##Prefix##Minutes(double m, Opt<double> s, Opt<double> ms) { \
371
+ if (std::isnan(t_)) return kNaN; \
372
+ double t = now; \
373
+ return setLocal(utc, day(t), makeTime(hourFromTime(t), m, s.has() ? s.get() : secFromTime(t), ms.has() ? ms.get() : msFromTime(t))); \
374
+ } \
375
+ double DateObject::set##Prefix##Seconds(double s, Opt<double> ms) { \
376
+ if (std::isnan(t_)) return kNaN; \
377
+ double t = now; \
378
+ return setLocal(utc, day(t), makeTime(hourFromTime(t), minFromTime(t), s, ms.has() ? ms.get() : msFromTime(t))); \
379
+ } \
380
+ double DateObject::set##Prefix##Milliseconds(double ms) { \
381
+ if (std::isnan(t_)) return kNaN; \
382
+ double t = now; \
383
+ return setLocal(utc, day(t), makeTime(hourFromTime(t), minFromTime(t), secFromTime(t), ms)); \
384
+ }
385
+ LUCENT_SETTERS(, false, localTime(t_))
386
+ LUCENT_SETTERS(UTC, true, t_)
387
+ #undef LUCENT_SETTERS
388
+
389
+ String DateObject::toISOString() const {
390
+ if (std::isnan(t_)) throwRangeError("Invalid time value");
391
+ double y = yearFromTime(t_);
392
+ std::string year = (y >= 0 && y <= 9999) ? pad(y, 4) : (y < 0 ? "-" : "+") + pad(std::fabs(y), 6);
393
+ return String::fromLatin1(year + "-" + pad(monthFromTime(t_) + 1, 2) + "-" + pad(dateFromTime(t_), 2) + "T" + timePart(t_) + "." + pad(msFromTime(t_), 3) + "Z");
394
+ }
395
+
396
+ String DateObject::toString() const {
397
+ if (std::isnan(t_)) return String::fromLatin1("Invalid Date");
398
+ double lt = localTime(t_);
399
+ return String::fromLatin1(datePart(lt) + " " + timePart(lt) + " " + offsetString(lt - t_));
400
+ }
401
+
402
+ String DateObject::toDateString() const {
403
+ if (std::isnan(t_)) return String::fromLatin1("Invalid Date");
404
+ return String::fromLatin1(datePart(localTime(t_)));
405
+ }
406
+
407
+ String DateObject::toTimeString() const {
408
+ if (std::isnan(t_)) return String::fromLatin1("Invalid Date");
409
+ double lt = localTime(t_);
410
+ return String::fromLatin1(timePart(lt) + " " + offsetString(lt - t_));
411
+ }
412
+
413
+ String DateObject::toUTCString() const {
414
+ if (std::isnan(t_)) return String::fromLatin1("Invalid Date");
415
+ return String::fromLatin1(std::string(kDays[static_cast<int>(weekDay(t_))]) + ", " + pad(dateFromTime(t_), 2) + " " + kMonths[static_cast<int>(monthFromTime(t_))] + " " +
416
+ yearString(yearFromTime(t_)) + " " + timePart(t_) + " GMT");
417
+ }
418
+
419
+ Date makeDate(double t) { return std::make_shared<DateObject>(t); }
420
+
421
+ static double fullYear(double y) {
422
+ double yi = std::trunc(y);
423
+ return std::isfinite(y) && yi >= 0 && yi <= 99 ? 1900 + yi : y;
424
+ }
425
+
426
+ Date dateFromLocal(double y, double m, double d, double h, double mi, double s, double ms) {
427
+ double t = timeValue(makeDay(fullYear(y), m, d), makeTime(h, mi, s, ms));
428
+ return makeDate(utcFromLocal(t));
429
+ }
430
+
431
+ double dateUTC(double y, double m, double d, double h, double mi, double s, double ms) {
432
+ return timeClip(timeValue(makeDay(fullYear(y), m, d), makeTime(h, mi, s, ms)));
433
+ }
434
+
435
+ double dateParse(const String& s) {
436
+ std::string text = s.toUtf8();
437
+ double t = parseIso(text);
438
+ return std::isnan(t) ? parseLegacy(text) : t;
439
+ }
440
+
441
+ } // namespace lucent
@@ -0,0 +1,82 @@
1
+ // Lucent runtime — Date.
2
+ //
3
+ // A Date is a shared, mutable time value (milliseconds since the epoch, NaN
4
+ // when invalid), with the ECMAScript algorithms for calendar fields. Local
5
+ // time comes from the C library's time zone database (localtime_r), like
6
+ // Hermes. String forms follow Hermes: toString() has no zone name.
7
+ #pragma once
8
+
9
+ #include "core.h"
10
+ #include "jsstring.h"
11
+
12
+ namespace lucent {
13
+
14
+ class DateObject : public Object {
15
+ public:
16
+ explicit DateObject(double t);
17
+
18
+ double getTime() const { return t_; }
19
+ double valueOf() const { return t_; }
20
+ double setTime(double t);
21
+
22
+ double getFullYear() const;
23
+ double getMonth() const;
24
+ double getDate() const;
25
+ double getDay() const;
26
+ double getHours() const;
27
+ double getMinutes() const;
28
+ double getSeconds() const;
29
+ double getMilliseconds() const;
30
+ double getTimezoneOffset() const;
31
+ double getUTCFullYear() const;
32
+ double getUTCMonth() const;
33
+ double getUTCDate() const;
34
+ double getUTCDay() const;
35
+ double getUTCHours() const;
36
+ double getUTCMinutes() const;
37
+ double getUTCSeconds() const;
38
+ double getUTCMilliseconds() const;
39
+
40
+ // Setters return the new time value. Optional arguments keep the current field.
41
+ double setFullYear(double y, Opt<double> m = undefined, Opt<double> d = undefined);
42
+ double setMonth(double m, Opt<double> d = undefined);
43
+ double setDate(double d);
44
+ double setHours(double h, Opt<double> m = undefined, Opt<double> s = undefined, Opt<double> ms = undefined);
45
+ double setMinutes(double m, Opt<double> s = undefined, Opt<double> ms = undefined);
46
+ double setSeconds(double s, Opt<double> ms = undefined);
47
+ double setMilliseconds(double ms);
48
+ double setUTCFullYear(double y, Opt<double> m = undefined, Opt<double> d = undefined);
49
+ double setUTCMonth(double m, Opt<double> d = undefined);
50
+ double setUTCDate(double d);
51
+ double setUTCHours(double h, Opt<double> m = undefined, Opt<double> s = undefined, Opt<double> ms = undefined);
52
+ double setUTCMinutes(double m, Opt<double> s = undefined, Opt<double> ms = undefined);
53
+ double setUTCSeconds(double s, Opt<double> ms = undefined);
54
+ double setUTCMilliseconds(double ms);
55
+
56
+ /// Throws RangeError for an invalid date.
57
+ String toISOString() const;
58
+ String toString() const;
59
+ String toDateString() const;
60
+ String toTimeString() const;
61
+ String toUTCString() const;
62
+
63
+ private:
64
+ double setLocal(bool utc, double date, double time);
65
+ double t_;
66
+ };
67
+ using Date = Ref<DateObject>;
68
+
69
+ /// `new Date(t)`: the time value is clipped (NaN beyond ±8.64e15).
70
+ Date makeDate(double t);
71
+ /// `new Date(y, m, d, h, mi, s, ms)` in local time (years 0–99 mean 1900–1999).
72
+ Date dateFromLocal(double y, double m, double d = 1, double h = 0, double mi = 0, double s = 0, double ms = 0);
73
+ /// `Date.UTC(y, m, d, h, mi, s, ms)`.
74
+ double dateUTC(double y, double m = 0, double d = 1, double h = 0, double mi = 0, double s = 0, double ms = 0);
75
+ /// `Date.parse(s)`: ISO 8601 (date-only forms are UTC, date-times without an
76
+ /// offset are local) and the formats toString / toUTCString produce; NaN otherwise.
77
+ double dateParse(const String& s);
78
+ inline Date dateFromString(const String& s) { return makeDate(dateParse(s)); }
79
+
80
+ inline String toJsString(const Date& d) { return d->toString(); }
81
+
82
+ } // namespace lucent
@@ -0,0 +1,87 @@
1
+ // Lucent runtime — `===` and SameValueZero.
2
+ #pragma once
3
+
4
+ #include <cmath>
5
+ #include <variant>
6
+
7
+ #include "core.h"
8
+ #include "jsstring.h"
9
+
10
+ namespace lucent {
11
+
12
+ inline bool strictEquals(double a, double b) { return a == b; }
13
+ inline bool strictEquals(bool a, bool b) { return a == b; }
14
+ inline bool strictEquals(const String& a, const String& b) { return a == b; }
15
+ inline bool strictEquals(Undefined, Undefined) { return true; }
16
+ inline bool strictEquals(Null, Null) { return true; }
17
+
18
+ template <class A, class B>
19
+ bool strictEquals(const Ref<A>& a, const Ref<B>& b) {
20
+ return static_cast<const void*>(a.get()) == static_cast<const void*>(b.get());
21
+ }
22
+
23
+ template <class T>
24
+ bool strictEquals(const Opt<T>& a, const Opt<T>& b) {
25
+ if (a.state() != b.state()) return false;
26
+ return !a.has() || strictEquals(a.get(), b.get());
27
+ }
28
+ template <class T>
29
+ bool strictEquals(const Opt<T>& a, Undefined) {
30
+ return a.isUndefined();
31
+ }
32
+ template <class T>
33
+ bool strictEquals(const Opt<T>& a, Null) {
34
+ return a.isNull();
35
+ }
36
+ template <class T>
37
+ bool strictEquals(Undefined, const Opt<T>& a) {
38
+ return a.isUndefined();
39
+ }
40
+ template <class T>
41
+ bool strictEquals(Null, const Opt<T>& a) {
42
+ return a.isNull();
43
+ }
44
+ template <class T, class U, std::enable_if_t<!IsOpt<U>::value && !std::is_same_v<U, Undefined> && !std::is_same_v<U, Null>, int> = 0>
45
+ bool strictEquals(const Opt<T>& a, const U& b) {
46
+ return a.has() && strictEquals(a.get(), b);
47
+ }
48
+ template <class T, class U, std::enable_if_t<!IsOpt<U>::value && !std::is_same_v<U, Undefined> && !std::is_same_v<U, Null>, int> = 0>
49
+ bool strictEquals(const U& b, const Opt<T>& a) {
50
+ return a.has() && strictEquals(b, a.get());
51
+ }
52
+
53
+ template <class... Ts>
54
+ bool strictEquals(const std::variant<Ts...>& a, const std::variant<Ts...>& b) {
55
+ if (a.index() != b.index()) return false;
56
+ return std::visit(
57
+ [&](const auto& x) {
58
+ using X = std::decay_t<decltype(x)>;
59
+ return strictEquals(x, std::get<X>(b));
60
+ },
61
+ a);
62
+ }
63
+ template <class... Ts, class U, std::enable_if_t<!IsOpt<U>::value, int> = 0>
64
+ bool strictEquals(const std::variant<Ts...>& a, const U& b) {
65
+ if (const U* p = std::get_if<U>(&a)) return strictEquals(*p, b);
66
+ return false;
67
+ }
68
+
69
+ /// Loose `==` only differs from `===` for null/undefined in Lucent's typed
70
+ /// world: `x == null` is true for both absent states.
71
+ template <class T>
72
+ bool looseEqualsNull(const Opt<T>& a) {
73
+ return !a.has();
74
+ }
75
+
76
+ inline bool sameValueZero(double a, double b) { return a == b || (std::isnan(a) && std::isnan(b)); }
77
+ template <class A, class B>
78
+ bool sameValueZero(const A& a, const B& b) {
79
+ return strictEquals(a, b);
80
+ }
81
+ template <class T>
82
+ bool sameValueZero(const Opt<T>& a, const Opt<T>& b) {
83
+ if (a.state() != b.state()) return false;
84
+ return !a.has() || sameValueZero(a.get(), b.get());
85
+ }
86
+
87
+ } // namespace lucent
@@ -0,0 +1,61 @@
1
+ // Lucent runtime — function values.
2
+ #pragma once
3
+
4
+ #include <functional>
5
+ #include <memory>
6
+
7
+ #include "core.h"
8
+
9
+ namespace lucent {
10
+
11
+ template <class Sig>
12
+ class Fn;
13
+
14
+ /// A first-class function value. Copies alias the same function, so `===`
15
+ /// compares identity as in JavaScript.
16
+ template <class R, class... A>
17
+ class Fn<R(A...)> {
18
+ public:
19
+ using Signature = R(A...);
20
+ Fn() = default;
21
+ template <class F, std::enable_if_t<!std::is_same_v<std::decay_t<F>, Fn> && std::is_invocable_v<F&, A...>, int> = 0>
22
+ Fn(F&& f) : f_(std::make_shared<std::function<R(A...)>>(std::forward<F>(f))) {}
23
+
24
+ R operator()(A... args) const {
25
+ if (!f_) throwTypeError("Called an uninitialized function value");
26
+ return (*f_)(std::forward<A>(args)...);
27
+ }
28
+ explicit operator bool() const { return f_ != nullptr; }
29
+ const void* identity() const { return f_.get(); }
30
+ friend bool operator==(const Fn& a, const Fn& b) { return a.f_ == b.f_; }
31
+ friend bool operator!=(const Fn& a, const Fn& b) { return a.f_ != b.f_; }
32
+
33
+ private:
34
+ std::shared_ptr<std::function<R(A...)>> f_;
35
+ };
36
+
37
+ /// Calls `f` with as many of (a, b, c) as it accepts, the way JavaScript
38
+ /// callbacks ignore extra arguments.
39
+ template <class F, class A, class B, class C>
40
+ decltype(auto) invokeCallback(F& f, A&& a, B&& b, C&& c) {
41
+ if constexpr (std::is_invocable_v<F&, A, B, C>) {
42
+ return f(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c));
43
+ } else if constexpr (std::is_invocable_v<F&, A, B>) {
44
+ return f(std::forward<A>(a), std::forward<B>(b));
45
+ } else if constexpr (std::is_invocable_v<F&, A>) {
46
+ return f(std::forward<A>(a));
47
+ } else {
48
+ return f();
49
+ }
50
+ }
51
+
52
+ template <class F, class A, class B, class C, class D>
53
+ decltype(auto) invokeCallback(F& f, A&& a, B&& b, C&& c, D&& d) {
54
+ if constexpr (std::is_invocable_v<F&, A, B, C, D>) {
55
+ return f(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c), std::forward<D>(d));
56
+ } else {
57
+ return invokeCallback(f, std::forward<A>(a), std::forward<B>(b), std::forward<C>(c));
58
+ }
59
+ }
60
+
61
+ } // namespace lucent