@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,244 @@
1
+ // Lucent runtime — iterators and generators.
2
+ //
3
+ // Every iterable value is an Iter<T>: a shared iterator with next() and
4
+ // ret() (JavaScript's iterator.return()). Generator functions are C++20
5
+ // coroutines whose declared return type is Iter<T> (see the coroutine_traits
6
+ // specialization below); they start lazily, like JavaScript generators.
7
+ //
8
+ // ret() resumes a suspended generator with a flag that makes its pending
9
+ // co_yield throw GeneratorReturn. That unwinds through the generated
10
+ // `finally` blocks (JS `catch` blocks let it pass), and the coroutine then
11
+ // completes normally.
12
+ #pragma once
13
+
14
+ #include <coroutine>
15
+ #include <exception>
16
+ #include <optional>
17
+ #include <tuple>
18
+ #include <utility>
19
+
20
+ #include "array.h"
21
+ #include "bytes.h"
22
+ #include "core.h"
23
+ #include "jsstring.h"
24
+ #include "map.h"
25
+
26
+ namespace lucent {
27
+
28
+ /// Thrown into a generator by iterator.return(); never seen by JS catch blocks.
29
+ struct GeneratorReturn {};
30
+
31
+ template <class T>
32
+ class IterObject : public Object {
33
+ public:
34
+ /// The next value, or nullopt once the iterator is exhausted.
35
+ virtual std::optional<T> next() = 0;
36
+ /// iterator.return(): stops early, running a generator's finally blocks.
37
+ virtual void ret() {}
38
+ };
39
+ template <class T>
40
+ using Iter = Ref<IterObject<T>>;
41
+
42
+ /// `{ value, done }` from `iterator.next()`.
43
+ template <class T>
44
+ struct IterResult {
45
+ bool done = true;
46
+ Opt<T> value;
47
+ };
48
+
49
+ template <class T>
50
+ IterResult<T> iterNext(const Iter<T>& it) {
51
+ auto v = it->next();
52
+ if (!v) return {};
53
+ return IterResult<T>{false, Opt<T>(std::move(*v))};
54
+ }
55
+
56
+ /// Calls ret() when a for-of or yield* exits before its iterator is exhausted.
57
+ template <class T>
58
+ class IterCloser {
59
+ public:
60
+ explicit IterCloser(Iter<T> it) : it_(std::move(it)), exceptions_(std::uncaught_exceptions()) {}
61
+ /// The iterator reported done: nothing to close.
62
+ void exhausted() { it_ = nullptr; }
63
+ ~IterCloser() noexcept(false) {
64
+ if (!it_) return;
65
+ if (std::uncaught_exceptions() > exceptions_) {
66
+ // Leaving because of an exception: it wins over one from return().
67
+ try {
68
+ it_->ret();
69
+ } catch (...) {
70
+ }
71
+ } else {
72
+ it_->ret();
73
+ }
74
+ }
75
+ IterCloser(const IterCloser&) = delete;
76
+ IterCloser& operator=(const IterCloser&) = delete;
77
+
78
+ private:
79
+ Iter<T> it_;
80
+ int exceptions_;
81
+ };
82
+
83
+ namespace detail {
84
+
85
+ template <class T>
86
+ class GeneratorIter;
87
+
88
+ template <class T>
89
+ struct GeneratorPromise {
90
+ std::optional<T> current;
91
+ std::exception_ptr error;
92
+ bool returning = false;
93
+
94
+ Iter<T> get_return_object();
95
+ std::suspend_always initial_suspend() noexcept { return {}; }
96
+ std::suspend_always final_suspend() noexcept { return {}; }
97
+ void return_void() {}
98
+ void unhandled_exception() {
99
+ try {
100
+ throw;
101
+ } catch (const GeneratorReturn&) {
102
+ // return() finished running the finally blocks.
103
+ } catch (...) {
104
+ error = std::current_exception();
105
+ }
106
+ }
107
+
108
+ struct Yield {
109
+ GeneratorPromise& p;
110
+ bool await_ready() const noexcept { return false; }
111
+ void await_suspend(std::coroutine_handle<>) const noexcept {}
112
+ void await_resume() const {
113
+ if (p.returning) throw GeneratorReturn{};
114
+ }
115
+ };
116
+ Yield yield_value(T v) {
117
+ current = std::move(v);
118
+ return Yield{*this};
119
+ }
120
+ };
121
+
122
+ template <class T>
123
+ class GeneratorIter final : public IterObject<T> {
124
+ public:
125
+ using Handle = std::coroutine_handle<GeneratorPromise<T>>;
126
+ explicit GeneratorIter(Handle h) : h_(h) {}
127
+ ~GeneratorIter() override {
128
+ if (h_) h_.destroy();
129
+ }
130
+
131
+ std::optional<T> next() override {
132
+ if (done_) return std::nullopt;
133
+ started_ = true;
134
+ h_.resume();
135
+ return settle();
136
+ }
137
+
138
+ void ret() override {
139
+ if (done_) return;
140
+ if (!started_) {
141
+ done_ = true;
142
+ return;
143
+ }
144
+ h_.promise().returning = true;
145
+ h_.resume();
146
+ settle();
147
+ done_ = true;
148
+ }
149
+
150
+ private:
151
+ std::optional<T> settle() {
152
+ auto& p = h_.promise();
153
+ if (h_.done()) {
154
+ done_ = true;
155
+ if (p.error) std::rethrow_exception(std::exchange(p.error, nullptr));
156
+ return std::nullopt;
157
+ }
158
+ return std::exchange(p.current, std::nullopt);
159
+ }
160
+
161
+ Handle h_;
162
+ bool started_ = false;
163
+ bool done_ = false;
164
+ };
165
+
166
+ template <class T>
167
+ Iter<T> GeneratorPromise<T>::get_return_object() {
168
+ return std::make_shared<GeneratorIter<T>>(GeneratorIter<T>::Handle::from_promise(*this));
169
+ }
170
+
171
+ // --- iterators over collections (live, like JavaScript's) --------------------------------------
172
+
173
+ template <class T>
174
+ class ArrayIter final : public IterObject<T> {
175
+ public:
176
+ explicit ArrayIter(Array<T> a) : a_(std::move(a)) {}
177
+ std::optional<T> next() override {
178
+ if (i_ >= a_.size()) return std::nullopt;
179
+ return a_.at(i_++);
180
+ }
181
+
182
+ private:
183
+ Array<T> a_;
184
+ size_t i_ = 0;
185
+ };
186
+
187
+ template <class T, class Table, class Get>
188
+ class TableIter final : public IterObject<T> {
189
+ public:
190
+ TableIter(Table t, Get get) : t_(std::move(t)), get_(get) {}
191
+ std::optional<T> next() override {
192
+ auto& table = t_.table();
193
+ while (i_ < table.slotCount()) {
194
+ size_t i = i_++;
195
+ if (table.slotLive(i)) return get_(table.slot(i));
196
+ }
197
+ return std::nullopt;
198
+ }
199
+
200
+ private:
201
+ Table t_;
202
+ Get get_;
203
+ size_t i_ = 0;
204
+ };
205
+
206
+ } // namespace detail
207
+
208
+ template <class T>
209
+ Iter<T> iterOf(const Iter<T>& it) {
210
+ return it;
211
+ }
212
+ template <class T>
213
+ Iter<T> iterOf(const Array<T>& a) {
214
+ return std::make_shared<detail::ArrayIter<T>>(a);
215
+ }
216
+ template <class T>
217
+ Iter<T> iterOf(const Set<T>& s) {
218
+ auto get = [](const auto& slot) { return slot.key; };
219
+ return std::make_shared<detail::TableIter<T, Set<T>, decltype(get)>>(s, get);
220
+ }
221
+ template <class K, class V>
222
+ Iter<std::tuple<K, V>> iterOf(const Map<K, V>& m) {
223
+ auto get = [](const auto& slot) { return std::tuple<K, V>(slot.key, slot.value); };
224
+ return std::make_shared<detail::TableIter<std::tuple<K, V>, Map<K, V>, decltype(get)>>(m, get);
225
+ }
226
+ /// Strings iterate by code point.
227
+ Iter<String> iterOf(const String& s);
228
+ Iter<double> iterOf(const Bytes& b);
229
+
230
+ /// `[...it]` / `Array.from(it)`.
231
+ template <class T>
232
+ Array<T> iterToArray(const Iter<T>& it) {
233
+ Array<T> out;
234
+ while (auto v = it->next()) out.push(std::move(*v));
235
+ return out;
236
+ }
237
+
238
+ } // namespace lucent
239
+
240
+ /// Coroutines declared to return Iter<T> are generators.
241
+ template <class T, class... Args>
242
+ struct std::coroutine_traits<lucent::Iter<T>, Args...> {
243
+ using promise_type = lucent::detail::GeneratorPromise<T>;
244
+ };
@@ -0,0 +1,226 @@
1
+ // Lucent runtime — small helpers the compiler emits calls to.
2
+ #pragma once
3
+
4
+ #include <chrono>
5
+ #include <cmath>
6
+ #include <initializer_list>
7
+ #include <tuple>
8
+ #include <variant>
9
+
10
+ #include "array.h"
11
+ #include "async.h"
12
+ #include "bytes.h"
13
+ #include "core.h"
14
+ #include "jserror.h"
15
+ #include "map.h"
16
+ #include "number.h"
17
+ #include "ops.h"
18
+ #include "jsstring.h"
19
+
20
+ namespace lucent {
21
+
22
+ /// `this` as a strong reference, inside a member function.
23
+ template <class T>
24
+ Ref<T> selfRef(T* p) {
25
+ return std::static_pointer_cast<T>(static_cast<Object*>(p)->shared_from_this());
26
+ }
27
+ template <class T>
28
+ Ref<T> selfRef(const T* p) {
29
+ return selfRef(const_cast<T*>(p));
30
+ }
31
+
32
+ // --- element access for compound assignment ------------------------------------------
33
+
34
+ template <class T>
35
+ T elementAt(const Array<T>& a, double i) {
36
+ Opt<T> v = a.get(i);
37
+ if (!v.has()) throwRangeError("Array index out of bounds");
38
+ return v.get();
39
+ }
40
+ template <class T, class V>
41
+ T setElement(Array<T>& a, double i, V&& v) {
42
+ T value(std::forward<V>(v));
43
+ a.set(i, value);
44
+ return value;
45
+ }
46
+ template <class T, class V>
47
+ T setElement(const Array<T>& a, double i, V&& v) {
48
+ Array<T> copy = a;
49
+ return setElement(copy, i, std::forward<V>(v));
50
+ }
51
+ inline double elementAt(const Bytes& b, double i) {
52
+ Opt<double> v = b.get(i);
53
+ if (!v.has()) throwRangeError("Uint8Array index out of bounds");
54
+ return v.get();
55
+ }
56
+ inline double setElement(const Bytes& b, double i, double v) {
57
+ Bytes copy = b;
58
+ copy.set(i, v);
59
+ return v;
60
+ }
61
+ template <class V>
62
+ V entryAt(const Dict<V>& d, const String& k) {
63
+ Opt<V> v = d.get(k);
64
+ if (!v.has()) throwTypeError("Record has no such key");
65
+ return v.get();
66
+ }
67
+ template <class V, class X>
68
+ V setEntry(const Dict<V>& d, const String& k, X&& v) {
69
+ Dict<V> copy = d;
70
+ V value(std::forward<X>(v));
71
+ copy.set(k, value);
72
+ return value;
73
+ }
74
+ template <class V>
75
+ void assignEntries(Dict<V>& target, const Dict<V>& source) {
76
+ Array<String> ks = source.keys();
77
+ for (const auto& k : ks.items()) target.set(k, source.get(k).get());
78
+ }
79
+
80
+ /// `s[i]`: undefined when out of range (unlike `s.at(i)`, no negative indexes).
81
+ inline Opt<String> stringIndex(const String& s, double i) {
82
+ if (i >= 0 && i < static_cast<double>(s.length()) && std::trunc(i) == i) return String::fromCodeUnit(s.unit(static_cast<size_t>(i)));
83
+ return undefined;
84
+ }
85
+
86
+ // --- instanceof ---------------------------------------------------------------------------
87
+
88
+ template <class C, class V>
89
+ bool isInstance(const V& v) {
90
+ if constexpr (IsRef<V>::value) {
91
+ return std::dynamic_pointer_cast<C>(v) != nullptr;
92
+ } else if constexpr (IsOpt<V>::value) {
93
+ return v.has() && isInstance<C>(v.get());
94
+ } else if constexpr (IsVariant<V>::value) {
95
+ return std::visit([](const auto& x) { return isInstance<C>(x); }, v);
96
+ } else {
97
+ return false;
98
+ }
99
+ }
100
+
101
+ /// `e instanceof Error` / `TypeError` / `RangeError` (kind null = any error).
102
+ template <class V>
103
+ bool isErrorOf(const V& v, const char* kind) {
104
+ if constexpr (std::is_same_v<V, Error>) {
105
+ return v && (kind == nullptr || v->name == String::fromLatin1(kind));
106
+ } else if constexpr (IsRef<V>::value) {
107
+ auto e = std::dynamic_pointer_cast<ErrorObject>(v);
108
+ return e && (kind == nullptr || e->name == String::fromLatin1(kind));
109
+ } else if constexpr (IsOpt<V>::value) {
110
+ return v.has() && isErrorOf(v.get(), kind);
111
+ } else if constexpr (IsVariant<V>::value) {
112
+ return std::visit([kind](const auto& x) { return isErrorOf(x, kind); }, v);
113
+ } else {
114
+ return false;
115
+ }
116
+ }
117
+
118
+ /// Checked downcast after `instanceof` narrowing.
119
+ template <class C, class V>
120
+ Ref<C> downcast(const Ref<V>& v) {
121
+ auto r = std::dynamic_pointer_cast<C>(v);
122
+ if (!r) throwTypeError("Value is not an instance of the expected class");
123
+ return r;
124
+ }
125
+
126
+ inline Error errorWithCode(const String& code, const String& message) {
127
+ Error e = makeError(message);
128
+ e->code = code;
129
+ return e;
130
+ }
131
+
132
+ // --- time ------------------------------------------------------------------------------------
133
+
134
+ inline double dateNow() {
135
+ return static_cast<double>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
136
+ }
137
+ inline double monotonicNow() {
138
+ return static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch()).count()) / 1000.0;
139
+ }
140
+
141
+ // --- strings ----------------------------------------------------------------------------------
142
+
143
+ inline String stringFromCharCodes(std::initializer_list<double> codes) {
144
+ if (codes.size() == 1) return String::fromCodeUnit(static_cast<char16_t>(toUint32(*codes.begin()) & 0xFFFF));
145
+ std::u16string out;
146
+ for (double c : codes) out.push_back(static_cast<char16_t>(toUint32(c) & 0xFFFF));
147
+ return String::fromUtf16(out);
148
+ }
149
+ inline String stringFromCodePoints(std::initializer_list<double> cps) {
150
+ String out;
151
+ for (double c : cps) out += String::fromCodePoint(c);
152
+ return out;
153
+ }
154
+
155
+ // --- Math.min(...xs) ------------------------------------------------------------------------
156
+
157
+ namespace math {
158
+ inline double minOf(const Array<double>& xs) {
159
+ double r = kInfinity;
160
+ for (double v : xs.items()) r = min(r, v);
161
+ return r;
162
+ }
163
+ inline double maxOf(const Array<double>& xs) {
164
+ double r = -kInfinity;
165
+ for (double v : xs.items()) r = max(r, v);
166
+ return r;
167
+ }
168
+ } // namespace math
169
+
170
+ // --- entries --------------------------------------------------------------------------------
171
+
172
+ template <class V>
173
+ Array<std::tuple<String, V>> dictEntries(const Dict<V>& d) {
174
+ Array<std::tuple<String, V>> out;
175
+ Array<String> ks = d.keys();
176
+ for (const auto& k : ks.items()) out.push(std::tuple<String, V>(k, d.get(k).get()));
177
+ return out;
178
+ }
179
+ template <class V>
180
+ Dict<V> dictFromEntries(const Array<std::tuple<String, V>>& entries) {
181
+ Dict<V> out;
182
+ for (const auto& e : entries.items()) out.set(std::get<0>(e), std::get<1>(e));
183
+ return out;
184
+ }
185
+ template <class K, class V>
186
+ Array<std::tuple<K, V>> mapEntries(const Map<K, V>& m) {
187
+ Array<std::tuple<K, V>> out;
188
+ auto& t = m.table();
189
+ for (size_t i = 0; i < t.slotCount(); i++) {
190
+ if (t.slotLive(i)) out.push(std::tuple<K, V>(t.slot(i).key, t.slot(i).value));
191
+ }
192
+ return out;
193
+ }
194
+ template <class K, class V>
195
+ Map<K, V> mapFromEntries(const Array<std::tuple<K, V>>& entries) {
196
+ Map<K, V> out;
197
+ for (const auto& e : entries.items()) out.set(std::get<0>(e), std::get<1>(e));
198
+ return out;
199
+ }
200
+ template <class T>
201
+ Array<std::tuple<double, T>> arrayEntries(const Array<T>& a) {
202
+ Array<std::tuple<double, T>> out;
203
+ for (size_t i = 0; i < a.size(); i++) out.push(std::tuple<double, T>(static_cast<double>(i), a.at(i)));
204
+ return out;
205
+ }
206
+
207
+ // --- tuples ---------------------------------------------------------------------------------------
208
+
209
+ template <class... Ts>
210
+ String toJsString(const std::tuple<Ts...>& t) {
211
+ String out;
212
+ size_t i = 0;
213
+ std::apply(
214
+ [&](const auto&... x) {
215
+ ((out += (i++ ? String::fromLatin1(",") : String()), out += toJsString(x)), ...);
216
+ },
217
+ t);
218
+ return out;
219
+ }
220
+ template <class... Ts>
221
+ bool strictEquals(const std::tuple<Ts...>& a, const std::tuple<Ts...>& b) {
222
+ // Tuples are values in Lucent; compare element-wise.
223
+ return std::apply([&](const auto&... x) { return std::apply([&](const auto&... y) { return (strictEquals(x, y) && ...); }, b); }, a);
224
+ }
225
+
226
+ } // namespace lucent
@@ -0,0 +1,51 @@
1
+ #include "jserror.h"
2
+
3
+ #include <new>
4
+ #include <stdexcept>
5
+
6
+ namespace lucent {
7
+
8
+ Error makeError(const String& name, const String& message) {
9
+ auto e = std::make_shared<ErrorObject>();
10
+ e->name = name;
11
+ e->message = message;
12
+ return e;
13
+ }
14
+
15
+ Exception::Exception(Error error) : error_(std::move(error)) {
16
+ what_ = error_->name.toUtf8() + ": " + error_->message.toUtf8();
17
+ }
18
+
19
+ void throwError(const Error& error) { throw Exception(error); }
20
+
21
+ void throwError(const String& name, const String& message) { throw Exception(makeError(name, message)); }
22
+
23
+ void throwTypeError(const char* message) {
24
+ throwError(String::fromLatin1("TypeError"), String::fromUtf8(message));
25
+ }
26
+
27
+ void throwRangeError(const char* message) {
28
+ throwError(String::fromLatin1("RangeError"), String::fromUtf8(message));
29
+ }
30
+
31
+ Error currentError(std::exception_ptr ex) {
32
+ try {
33
+ std::rethrow_exception(ex);
34
+ } catch (const Exception& e) {
35
+ return e.error();
36
+ } catch (const std::bad_alloc&) {
37
+ return makeError(String::fromLatin1("RangeError"), String::fromLatin1("Out of memory"));
38
+ } catch (const std::exception& e) {
39
+ return makeError(String::fromLatin1("Error"), String::fromUtf8(e.what()));
40
+ } catch (...) {
41
+ return makeError(String::fromLatin1("Error"), String::fromLatin1("Unknown native exception"));
42
+ }
43
+ }
44
+
45
+ String errorToString(const Error& e) {
46
+ if (e->message.empty()) return e->name;
47
+ if (e->name.empty()) return e->message;
48
+ return e->name + String::fromLatin1(": ") + e->message;
49
+ }
50
+
51
+ } // namespace lucent
@@ -0,0 +1,66 @@
1
+ // Lucent runtime — Error objects and exceptions.
2
+ //
3
+ // `throw new Error("x")` in Lucent throws a C++ `lucent::Exception` holding
4
+ // an ErrorObject. At the JavaScript boundary it becomes a real JS Error with
5
+ // the same name, message and `code`.
6
+ #pragma once
7
+
8
+ #include <exception>
9
+ #include <string>
10
+
11
+ #include "core.h"
12
+ #include "jsstring.h"
13
+
14
+ namespace lucent {
15
+
16
+ struct ErrorObject : Object {
17
+ String name;
18
+ String message;
19
+ Opt<String> code;
20
+ /// For errors that came from JavaScript: the original stack.
21
+ Opt<String> stack;
22
+ /// Where Lucent code created the error: `fn (file.lucent.ts:line)`.
23
+ Opt<String> site;
24
+ /// Class name when a Lucent class extends Error, for `instanceof`.
25
+ const char* kind = "Error";
26
+ };
27
+ using Error = Ref<ErrorObject>;
28
+
29
+ Error makeError(const String& name, const String& message);
30
+ inline Error makeError(const String& message) { return makeError(String::fromLatin1("Error"), message); }
31
+
32
+ /// Records where Lucent code created `e` (generated code passes __FILE__ and
33
+ /// __LINE__, which #line directives point at the .lucent.ts source).
34
+ template <class E>
35
+ E withSite(E e, const char* file, int line, const char* function) {
36
+ if (e && !e->site.has()) e->site = String::fromUtf8(std::string(function) + " (" + file + ":" + std::to_string(line) + ")");
37
+ return e;
38
+ }
39
+
40
+ class Exception : public std::exception {
41
+ public:
42
+ explicit Exception(Error error);
43
+ const Error& error() const { return error_; }
44
+ const char* what() const noexcept override { return what_.c_str(); }
45
+
46
+ private:
47
+ Error error_;
48
+ std::string what_;
49
+ };
50
+
51
+ [[noreturn]] void throwError(const Error& error);
52
+ [[noreturn]] void throwError(const String& name, const String& message);
53
+ /// A platform branch (`if (PLATFORM === "ios")`) reached on a target that is
54
+ /// neither platform, the host; typed as the value it stands for.
55
+ template <class T = void>
56
+ [[noreturn]] T platformOnly(const String& message) {
57
+ throwError(String::fromLatin1("Error"), message);
58
+ }
59
+
60
+ /// Converts whatever is being caught into a Lucent Error, including C++
61
+ /// exceptions from the standard library.
62
+ Error currentError(std::exception_ptr ex);
63
+
64
+ String errorToString(const Error& e);
65
+
66
+ } // namespace lucent