├── .gitignore ├── LICENSE ├── README.md ├── arrays └── data-array.cpp ├── assert └── test-assert.cpp ├── console └── effect-console.cpp ├── effect ├── effect-uncurried.cpp └── effect.cpp ├── foldable-traversable ├── data-foldable.cpp ├── data-foldablewithindex.cpp └── data-traversable.cpp ├── functions └── data-functions-uncurried.cpp ├── integers └── data-int.cpp ├── math └── math.cpp ├── partial └── partial-unsafe.cpp ├── prelude ├── control-apply.cpp ├── data-bounded.cpp ├── data-eq.cpp ├── data-euclideanring.cpp ├── data-functor.cpp ├── data-heytingalgebra.cpp ├── data-ord.cpp ├── data-ring.cpp ├── data-semigroup.cpp ├── data-semiring.cpp ├── data-show.cpp └── data-unit.cpp ├── refs └── effect-ref.cpp ├── st └── control-monad-st-internal.cpp ├── strings ├── data-string-common.cpp ├── data-string-unsafe.cpp └── utf8.h └── unsafe_coerce └── unsafe-coerce.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.d 3 | *.o 4 | *.bak 5 | .vscode 6 | .DS_Store 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Andy Arvanitis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### C++ foreign export implementations for the standard library 2 | 3 | Note that many values are currently missing. Only a minimum set has been implemented – just beyond enough for the standard compiler tests to pass. Please feel free to contribute any that you have implemented yourself (via a pull request). 4 | -------------------------------------------------------------------------------- /arrays/data-array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "purescript.h" 5 | 6 | // Tested with package v5.0.0 7 | 8 | FOREIGN_BEGIN( Data_Array ) 9 | 10 | exports["range"] = [](const boxed& start_) -> boxed { 11 | const auto start = unbox(start_); 12 | return [=](const boxed& end_) -> boxed { 13 | const auto end = unbox(end_); 14 | const auto step = start > end ? -1 : 1; 15 | array_t ns; 16 | for (auto i = start; i != end; i += step) { 17 | ns.emplace_back(i); 18 | } 19 | ns.emplace_back(end); 20 | return ns; 21 | }; 22 | }; 23 | 24 | exports["replicate"] = [](const boxed& count_) -> boxed { 25 | const auto count = unbox(count_); 26 | return [=](const boxed& value) -> boxed { 27 | return array_t(count < 0 ? 0 : count, value); 28 | }; 29 | }; 30 | 31 | exports["length"] = [](const boxed& xs) -> boxed { 32 | const long long len = unbox(xs).size(); 33 | assert(len <= std::numeric_limits::max()); 34 | return static_cast(len); 35 | }; 36 | 37 | exports["cons"] = [](const boxed& e) -> boxed { 38 | return [=](const boxed& l_) -> boxed { 39 | const auto& l = unbox(l_); 40 | array_t result; 41 | result.reserve(l.size() + 1); 42 | result.insert(result.cend(), e); 43 | result.insert(result.cend(), l.cbegin(), l.cend()); 44 | return result; 45 | }; 46 | }; 47 | 48 | exports["snoc"] = [](const boxed& l_) -> boxed { 49 | return [=](const boxed& e) -> boxed { 50 | const auto& l = unbox(l_); 51 | array_t result; 52 | result.reserve(l.size() + 1); 53 | result.insert(result.cend(), l.cbegin(), l.cend()); 54 | result.insert(result.cend(), e); 55 | return result; 56 | }; 57 | }; 58 | 59 | exports["slice"] = [](const boxed& start_) -> boxed { 60 | const auto start = unbox(start_); 61 | return [=](const boxed& end_) -> boxed { 62 | const auto end = unbox(end_); 63 | return [=](const boxed& xs_) -> boxed { 64 | const auto& xs = unbox(xs_); 65 | const long long size = xs.size(); 66 | assert(size <= std::numeric_limits::max()); 67 | const auto length = static_cast(size); 68 | const auto _start = std::min(start, length); 69 | const auto _end = std::min(end, length); 70 | return array_t(xs.cbegin() + _start, xs.cbegin() + _end); 71 | }; 72 | }; 73 | }; 74 | 75 | exports["indexImpl"] = [](const boxed& just) -> boxed { 76 | return [=](const boxed& nothing) -> boxed { 77 | return [=](const boxed& xs_) -> boxed { 78 | return [=](const boxed& i_) -> boxed { 79 | const auto& xs = unbox(xs_); 80 | const auto i = unbox(i_); 81 | return i < 0 || i >= xs.size() ? nothing : just(xs[i]); 82 | }; 83 | }; 84 | }; 85 | }; 86 | 87 | exports["unsafeIndexImpl"] = [](const boxed& xs) -> boxed { 88 | return [=](const boxed& n) -> boxed { 89 | return unbox(xs)[unbox(n)]; 90 | }; 91 | }; 92 | 93 | FOREIGN_END 94 | -------------------------------------------------------------------------------- /assert/test-assert.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Test_Assert ) 6 | 7 | exports["assert'"] = [](const boxed& message) -> boxed { 8 | return [=](const boxed& success_) -> boxed { 9 | const auto success = unbox(success_); 10 | return [=]() -> boxed { 11 | if (!success) throw std::runtime_error(unbox(message)); 12 | return boxed(); 13 | }; 14 | }; 15 | }; 16 | 17 | FOREIGN_END 18 | -------------------------------------------------------------------------------- /console/effect-console.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "purescript.h" 3 | 4 | // Tested with package v4.1.0 5 | 6 | FOREIGN_BEGIN( Effect_Console ) 7 | 8 | exports["log"] = [](const boxed& s) -> boxed { 9 | return [=]() -> boxed { 10 | std::cout << unbox(s) << std::endl; 11 | return boxed(); 12 | }; 13 | }; 14 | 15 | exports["warn"] = [](const boxed& s) -> boxed { 16 | return [=]() -> boxed { 17 | std::cout << unbox(s) << std::endl; 18 | return boxed(); 19 | }; 20 | }; 21 | 22 | FOREIGN_END 23 | -------------------------------------------------------------------------------- /effect/effect-uncurried.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "purescript.h" 3 | 4 | // Tested with package v2.0.0 5 | 6 | FOREIGN_BEGIN( Effect_Uncurried ) 7 | 8 | exports["mkEffectFn1"] = [](const boxed& fn) -> boxed { 9 | return box>( 10 | [=](const boxed& a) -> boxed { 11 | return fn(a)(); 12 | } 13 | ); 14 | }; 15 | 16 | exports["mkEffectFn2"] = [](const boxed& fn) -> boxed { 17 | return box>( 18 | [=](const boxed& a, const boxed& b) -> boxed { 19 | return fn(a)(b)(); 20 | } 21 | ); 22 | }; 23 | 24 | exports["mkEffectFn3"] = [](const boxed& fn) -> boxed { 25 | return box>( 28 | [=](const boxed& a, 29 | const boxed& b, 30 | const boxed& c) -> boxed { 31 | return fn(a)(b)(c)(); 32 | } 33 | ); 34 | }; 35 | 36 | exports["mkEffectFn4"] = [](const boxed& fn) -> boxed { 37 | return box>( 41 | [=](const boxed& a, 42 | const boxed& b, 43 | const boxed& c, 44 | const boxed& d) -> boxed { 45 | return fn(a)(b)(c)(d)(); 46 | } 47 | ); 48 | }; 49 | 50 | exports["mkEffectFn5"] = [](const boxed& fn) -> boxed { 51 | return box>( 56 | [=](const boxed& a, 57 | const boxed& b, 58 | const boxed& c, 59 | const boxed& d, 60 | const boxed& e) -> boxed { 61 | return fn(a)(b)(c)(d)(e)(); 62 | } 63 | ); 64 | }; 65 | 66 | exports["mkEffectFn6"] = [](const boxed& fn) -> boxed { 67 | return box>( 73 | [=](const boxed& a, 74 | const boxed& b, 75 | const boxed& c, 76 | const boxed& d, 77 | const boxed& e, 78 | const boxed& f) -> boxed { 79 | return fn(a)(b)(c)(d)(e)(f)(); 80 | } 81 | ); 82 | }; 83 | 84 | exports["mkEffectFn7"] = [](const boxed& fn) -> boxed { 85 | return box>( 92 | [=](const boxed& a, 93 | const boxed& b, 94 | const boxed& c, 95 | const boxed& d, 96 | const boxed& e, 97 | const boxed& f, 98 | const boxed& g) -> boxed { 99 | return fn(a)(b)(c)(d)(e)(f)(g)(); 100 | } 101 | ); 102 | }; 103 | 104 | exports["mkEffectFn8"] = [](const boxed& fn) -> boxed { 105 | return box>( 113 | [=](const boxed& a, 114 | const boxed& b, 115 | const boxed& c, 116 | const boxed& d, 117 | const boxed& e, 118 | const boxed& f, 119 | const boxed& g, 120 | const boxed& h) -> boxed { 121 | return fn(a)(b)(c)(d)(e)(f)(g)(h)(); 122 | } 123 | ); 124 | }; 125 | 126 | exports["mkEffectFn9"] = [](const boxed& fn) -> boxed { 127 | return box>( 136 | [=](const boxed& a, 137 | const boxed& b, 138 | const boxed& c, 139 | const boxed& d, 140 | const boxed& e, 141 | const boxed& f, 142 | const boxed& g, 143 | const boxed& h, 144 | const boxed& i) -> boxed { 145 | return fn(a)(b)(c)(d)(e)(f)(g)(h)(i)(); 146 | } 147 | ); 148 | }; 149 | 150 | exports["mkEffectFn10"] = [](const boxed& fn) -> boxed { 151 | return box>( 161 | [=](const boxed& a, 162 | const boxed& b, 163 | const boxed& c, 164 | const boxed& d, 165 | const boxed& e, 166 | const boxed& f, 167 | const boxed& g, 168 | const boxed& h, 169 | const boxed& i, 170 | const boxed& j) -> boxed { 171 | return fn(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(); 172 | } 173 | ); 174 | }; 175 | 176 | // runEffectFn 177 | 178 | exports["runEffectFn1"] = [](const boxed& fn) -> boxed { 179 | return [=](const boxed& a) -> boxed { 180 | return [=]() -> boxed { 181 | return unbox>(fn)(a); 182 | }; 183 | }; 184 | }; 185 | 186 | exports["runEffectFn2"] = [](const boxed& fn) -> boxed { 187 | return [=](const boxed& a) -> boxed { 188 | return [=](const boxed& b) -> boxed { 189 | return [=]() -> boxed { 190 | return unbox>(fn)(a, b); 191 | }; 192 | }; 193 | }; 194 | }; 195 | 196 | exports["runEffectFn3"] = [](const boxed& fn) -> boxed { 197 | return [=](const boxed& a) -> boxed { 198 | return [=](const boxed& b) -> boxed { 199 | return [=](const boxed& c) -> boxed { 200 | return [=]() -> boxed { 201 | return unbox>(fn)(a, b, c); 204 | }; 205 | }; 206 | }; 207 | }; 208 | }; 209 | 210 | exports["runEffectFn4"] = [](const boxed& fn) -> boxed { 211 | return [=](const boxed& a) -> boxed { 212 | return [=](const boxed& b) -> boxed { 213 | return [=](const boxed& c) -> boxed { 214 | return [=](const boxed& d) -> boxed { 215 | return [=]() -> boxed { 216 | return unbox>(fn)(a, b, c, d); 220 | }; 221 | }; 222 | }; 223 | }; 224 | }; 225 | }; 226 | 227 | exports["runEffectFn5"] = [](const boxed& fn) -> boxed { 228 | return [=](const boxed& a) -> boxed { 229 | return [=](const boxed& b) -> boxed { 230 | return [=](const boxed& c) -> boxed { 231 | return [=](const boxed& d) -> boxed { 232 | return [=](const boxed& e) -> boxed { 233 | return [=]() -> boxed { 234 | return unbox>(fn)(a, b, c, d, e); 239 | }; 240 | }; 241 | }; 242 | }; 243 | }; 244 | }; 245 | }; 246 | 247 | exports["runEffectFn6"] = [](const boxed& fn) -> boxed { 248 | return [=](const boxed& a) -> boxed { 249 | return [=](const boxed& b) -> boxed { 250 | return [=](const boxed& c) -> boxed { 251 | return [=](const boxed& d) -> boxed { 252 | return [=](const boxed& e) -> boxed { 253 | return [=](const boxed& f) -> boxed { 254 | return [=]() -> boxed { 255 | return fn(a)(b)(c)(d)(e)(f); 256 | return unbox>(fn)(a, b, c, d, e, f); 262 | }; 263 | }; 264 | }; 265 | }; 266 | }; 267 | }; 268 | }; 269 | }; 270 | 271 | exports["runEffectFn7"] = [](const boxed& fn) -> boxed { 272 | return [=](const boxed& a) -> boxed { 273 | return [=](const boxed& b) -> boxed { 274 | return [=](const boxed& c) -> boxed { 275 | return [=](const boxed& d) -> boxed { 276 | return [=](const boxed& e) -> boxed { 277 | return [=](const boxed& f) -> boxed { 278 | return [=](const boxed& g) -> boxed { 279 | return [=]() -> boxed { 280 | return unbox>(fn)(a, b, c, d, e, f, g); 287 | }; 288 | }; 289 | }; 290 | }; 291 | }; 292 | }; 293 | }; 294 | }; 295 | }; 296 | 297 | exports["runEffectFn8"] = [](const boxed& fn) -> boxed { 298 | return [=](const boxed& a) -> boxed { 299 | return [=](const boxed& b) -> boxed { 300 | return [=](const boxed& c) -> boxed { 301 | return [=](const boxed& d) -> boxed { 302 | return [=](const boxed& e) -> boxed { 303 | return [=](const boxed& f) -> boxed { 304 | return [=](const boxed& g) -> boxed { 305 | return [=](const boxed& h) -> boxed { 306 | return [=]() -> boxed { 307 | return unbox>(fn)(a, b, c, d, e, f, g, h); 315 | }; 316 | }; 317 | }; 318 | }; 319 | }; 320 | }; 321 | }; 322 | }; 323 | }; 324 | }; 325 | 326 | exports["runEffectFn9"] = [](const boxed& fn) -> boxed { 327 | return [=](const boxed& a) -> boxed { 328 | return [=](const boxed& b) -> boxed { 329 | return [=](const boxed& c) -> boxed { 330 | return [=](const boxed& d) -> boxed { 331 | return [=](const boxed& e) -> boxed { 332 | return [=](const boxed& f) -> boxed { 333 | return [=](const boxed& g) -> boxed { 334 | return [=](const boxed& h) -> boxed { 335 | return [=](const boxed& i) -> boxed { 336 | return [=]() -> boxed { 337 | return unbox>(fn)(a, b, c, d, e, f, g, h, i); 346 | }; 347 | }; 348 | }; 349 | }; 350 | }; 351 | }; 352 | }; 353 | }; 354 | }; 355 | }; 356 | }; 357 | 358 | exports["runEffectFn10"] = [](const boxed& fn) -> boxed { 359 | return [=](const boxed& a) -> boxed { 360 | return [=](const boxed& b) -> boxed { 361 | return [=](const boxed& c) -> boxed { 362 | return [=](const boxed& d) -> boxed { 363 | return [=](const boxed& e) -> boxed { 364 | return [=](const boxed& f) -> boxed { 365 | return [=](const boxed& g) -> boxed { 366 | return [=](const boxed& h) -> boxed { 367 | return [=](const boxed& i) -> boxed { 368 | return [=](const boxed& j) -> boxed { 369 | return [=]() -> boxed { 370 | return unbox>(fn)(a, b, c, d, e, f, g, h, i, j); 380 | }; 381 | }; 382 | }; 383 | }; 384 | }; 385 | }; 386 | }; 387 | }; 388 | }; 389 | }; 390 | }; 391 | }; 392 | 393 | FOREIGN_END 394 | -------------------------------------------------------------------------------- /effect/effect.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v2.0.0 4 | 5 | FOREIGN_BEGIN( Effect ) 6 | 7 | exports["pureE"] = [](const boxed& a) -> boxed { 8 | return [=]() -> boxed { 9 | return a; 10 | }; 11 | }; 12 | 13 | exports["bindE"] = [](const boxed& a) -> boxed { 14 | return [=](const boxed& f) -> boxed { 15 | return [=]() -> boxed { 16 | return f(a())(); 17 | }; 18 | }; 19 | }; 20 | 21 | exports["foreachE"] = [](const boxed& as_) -> boxed { 22 | return [=](const boxed& f) -> boxed { 23 | return [=]() -> boxed { 24 | const auto& as = unbox(as_); 25 | for (auto it = as.cbegin(), end = as.cend(); it != end ; it++) { 26 | f(*it)(); 27 | } 28 | return boxed(); 29 | }; 30 | }; 31 | }; 32 | 33 | FOREIGN_END 34 | -------------------------------------------------------------------------------- /foldable-traversable/data-foldable.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Data_Foldable ) 6 | 7 | 8 | exports["foldrArray"] = [](const boxed& f) -> boxed { 9 | return [=](const boxed& init) -> boxed { 10 | return [=](const boxed& xs_) -> boxed { 11 | auto acc = init; 12 | const auto& xs = unbox(xs_); 13 | for (auto it = xs.crbegin(), end = xs.crend(); it != end ; it++) { 14 | acc = f(*it)(acc); 15 | } 16 | return acc; 17 | }; 18 | }; 19 | }; 20 | 21 | exports["foldlArray"] = [](const boxed& f) -> boxed { 22 | return [=](const boxed& init) -> boxed { 23 | return [=](const boxed& xs_) -> boxed { 24 | auto acc = init; 25 | const auto& xs = unbox(xs_); 26 | for (auto it = xs.cbegin(), end = xs.cend(); it != end ; it++) { 27 | acc = f(acc)(*it); 28 | } 29 | return acc; 30 | }; 31 | }; 32 | }; 33 | 34 | FOREIGN_END 35 | -------------------------------------------------------------------------------- /foldable-traversable/data-foldablewithindex.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Data_FunctorWithIndex ) 6 | 7 | exports["mapWithIndexArray"] = [](const boxed& f) -> boxed { 8 | return [=](const boxed& xs_) -> boxed { 9 | const auto& xs = unbox(xs_); 10 | array_t result; 11 | int i = 0; 12 | for (auto it = xs.cbegin(), end = xs.cend(); it != end ; it++, i++) { 13 | result.push_back(f(i)(*it)); 14 | } 15 | return result; 16 | }; 17 | }; 18 | 19 | FOREIGN_END 20 | -------------------------------------------------------------------------------- /foldable-traversable/data-traversable.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "purescript.h" 3 | 4 | // Tested with package v4.0.0 5 | 6 | using namespace purescript; 7 | 8 | static auto array1(const boxed& a) -> boxed { 9 | return array_t{ a }; 10 | } 11 | 12 | static auto array2(const boxed& a) -> boxed { 13 | return [=](const boxed& b) -> boxed { 14 | return array_t{ a, b }; 15 | }; 16 | } 17 | 18 | static auto array3(const boxed& a) -> boxed { 19 | return [=](const boxed& b) -> boxed { 20 | return [=](const boxed& c) -> boxed { 21 | return array_t{ a, b, c }; 22 | }; 23 | }; 24 | } 25 | 26 | static auto concat2(const boxed& xs) -> boxed { 27 | return [=](const boxed& ys_) -> boxed { 28 | array_t result(unbox(xs)); 29 | const auto& ys = unbox(ys_); 30 | result.insert(result.end(), ys.cbegin(), ys.cend()); 31 | return result; 32 | }; 33 | } 34 | 35 | static auto go(const long bot, 36 | const long top, 37 | const boxed& apply, 38 | const boxed& map, 39 | const boxed& pure, 40 | const boxed& f, 41 | const array_t& array) -> boxed { 42 | switch (top - bot) { 43 | case 0: return pure(array_t{}); 44 | case 1: return map(array1)(f(array[bot])); 45 | case 2: return apply(map(array2)(f(array[bot])))(f(array[bot + 1])); 46 | case 3: return apply(apply(map(array3)(f(array[bot])))(f(array[bot + 1])))(f(array[bot + 2])); 47 | default: 48 | // This slightly tricky pivot selection aims to produce two 49 | // even-length partitions where possible. 50 | long pivot = bot + static_cast(std::floor((top - bot) / 4)) * 2; 51 | return apply(map(concat2)(go(bot, pivot, apply, map, pure, f, array)))(go(pivot, top, apply, map, pure, f, array)); 52 | } 53 | } 54 | 55 | FOREIGN_BEGIN( Data_Traversable ) 56 | 57 | exports["traverseArrayImpl"] = [](const boxed& apply) -> boxed { 58 | return [=](const boxed& map) -> boxed { 59 | return [=](const boxed& pure) -> boxed { 60 | return [=](const boxed& f) -> boxed { 61 | return [=](const boxed& array_) -> boxed { 62 | const auto& array = unbox(array_); 63 | return go(0, 64 | array.size(), 65 | apply, 66 | map, 67 | pure, 68 | f, 69 | array); 70 | }; 71 | }; 72 | }; 73 | }; 74 | }; 75 | 76 | FOREIGN_END 77 | -------------------------------------------------------------------------------- /functions/data-functions-uncurried.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "purescript.h" 3 | 4 | // Tested with package v4.0.0 5 | 6 | FOREIGN_BEGIN( Data_Function_Uncurried ) 7 | 8 | exports["mkFn0"] = [](const boxed& f) -> boxed { 9 | return [=]() -> boxed { 10 | return f(boxed()); 11 | }; 12 | }; 13 | 14 | exports["mkFn2"] = [](const boxed& fn) -> boxed { 15 | return box>( 16 | [=](const boxed& a, const boxed& b) -> boxed { 17 | return fn(a)(b); 18 | } 19 | ); 20 | }; 21 | 22 | exports["mkFn3"] = [](const boxed& fn) -> boxed { 23 | return box>( 26 | [=](const boxed& a, 27 | const boxed& b, 28 | const boxed& c) -> boxed { 29 | return fn(a)(b)(c); 30 | } 31 | ); 32 | }; 33 | 34 | exports["mkFn4"] = [](const boxed& fn) -> boxed { 35 | return box>( 39 | [=](const boxed& a, 40 | const boxed& b, 41 | const boxed& c, 42 | const boxed& d) -> boxed { 43 | return fn(a)(b)(c)(d); 44 | } 45 | ); 46 | }; 47 | 48 | exports["mkFn5"] = [](const boxed& fn) -> boxed { 49 | return box>( 54 | [=](const boxed& a, 55 | const boxed& b, 56 | const boxed& c, 57 | const boxed& d, 58 | const boxed& e) -> boxed { 59 | return fn(a)(b)(c)(d)(e); 60 | } 61 | ); 62 | }; 63 | 64 | exports["mkFn6"] = [](const boxed& fn) -> boxed { 65 | return box>( 71 | [=](const boxed& a, 72 | const boxed& b, 73 | const boxed& c, 74 | const boxed& d, 75 | const boxed& e, 76 | const boxed& f) -> boxed { 77 | return fn(a)(b)(c)(d)(e)(f); 78 | } 79 | ); 80 | }; 81 | 82 | exports["mkFn7"] = [](const boxed& fn) -> boxed { 83 | return box>( 90 | [=](const boxed& a, 91 | const boxed& b, 92 | const boxed& c, 93 | const boxed& d, 94 | const boxed& e, 95 | const boxed& f, 96 | const boxed& g) -> boxed { 97 | return fn(a)(b)(c)(d)(e)(f)(g); 98 | } 99 | ); 100 | }; 101 | 102 | exports["mkFn8"] = [](const boxed& fn) -> boxed { 103 | return box>( 111 | [=](const boxed& a, 112 | const boxed& b, 113 | const boxed& c, 114 | const boxed& d, 115 | const boxed& e, 116 | const boxed& f, 117 | const boxed& g, 118 | const boxed& h) -> boxed { 119 | return fn(a)(b)(c)(d)(e)(f)(g)(h); 120 | } 121 | ); 122 | }; 123 | 124 | exports["mkFn9"] = [](const boxed& fn) -> boxed { 125 | return box>( 134 | [=](const boxed& a, 135 | const boxed& b, 136 | const boxed& c, 137 | const boxed& d, 138 | const boxed& e, 139 | const boxed& f, 140 | const boxed& g, 141 | const boxed& h, 142 | const boxed& i) -> boxed { 143 | return fn(a)(b)(c)(d)(e)(f)(g)(h)(i); 144 | } 145 | ); 146 | }; 147 | 148 | exports["mkFn10"] = [](const boxed& fn) -> boxed { 149 | return box>( 159 | [=](const boxed& a, 160 | const boxed& b, 161 | const boxed& c, 162 | const boxed& d, 163 | const boxed& e, 164 | const boxed& f, 165 | const boxed& g, 166 | const boxed& h, 167 | const boxed& i, 168 | const boxed& j) -> boxed { 169 | return fn(a)(b)(c)(d)(e)(f)(g)(h)(i)(j); 170 | } 171 | ); 172 | }; 173 | 174 | //--------------------------------- runFn -----------------------------------// 175 | 176 | exports["runFn0"] = [](const boxed& fn) -> boxed { 177 | return fn(); 178 | }; 179 | 180 | exports["runFn2"] = [](const boxed& fn) -> boxed { 181 | return [=](const boxed& a) -> boxed { 182 | return [=](const boxed& b) -> boxed { 183 | return unbox>(fn)(a, b); 184 | }; 185 | }; 186 | }; 187 | 188 | exports["runFn3"] = [](const boxed& fn) -> boxed { 189 | return [=](const boxed& a) -> boxed { 190 | return [=](const boxed& b) -> boxed { 191 | return [=](const boxed& c) -> boxed { 192 | return unbox>(fn)(a, b, c); 195 | }; 196 | }; 197 | }; 198 | }; 199 | 200 | exports["runFn4"] = [](const boxed& fn) -> boxed { 201 | return [=](const boxed& a) -> boxed { 202 | return [=](const boxed& b) -> boxed { 203 | return [=](const boxed& c) -> boxed { 204 | return [=](const boxed& d) -> boxed { 205 | return unbox>(fn)(a, b, c, d); 209 | }; 210 | }; 211 | }; 212 | }; 213 | }; 214 | 215 | exports["runFn5"] = [](const boxed& fn) -> boxed { 216 | return [=](const boxed& a) -> boxed { 217 | return [=](const boxed& b) -> boxed { 218 | return [=](const boxed& c) -> boxed { 219 | return [=](const boxed& d) -> boxed { 220 | return [=](const boxed& e) -> boxed { 221 | return unbox>(fn)(a, b, c, d, e); 226 | }; 227 | }; 228 | }; 229 | }; 230 | }; 231 | }; 232 | 233 | exports["runFn6"] = [](const boxed& fn) -> boxed { 234 | return [=](const boxed& a) -> boxed { 235 | return [=](const boxed& b) -> boxed { 236 | return [=](const boxed& c) -> boxed { 237 | return [=](const boxed& d) -> boxed { 238 | return [=](const boxed& e) -> boxed { 239 | return [=](const boxed& f) -> boxed { 240 | return unbox>(fn)(a, b, c, d, e, f); 246 | }; 247 | }; 248 | }; 249 | }; 250 | }; 251 | }; 252 | }; 253 | 254 | exports["runFn7"] = [](const boxed& fn) -> boxed { 255 | return [=](const boxed& a) -> boxed { 256 | return [=](const boxed& b) -> boxed { 257 | return [=](const boxed& c) -> boxed { 258 | return [=](const boxed& d) -> boxed { 259 | return [=](const boxed& e) -> boxed { 260 | return [=](const boxed& f) -> boxed { 261 | return [=](const boxed& g) -> boxed { 262 | return unbox>(fn)(a, b, c, d, e, f, g); 269 | }; 270 | }; 271 | }; 272 | }; 273 | }; 274 | }; 275 | }; 276 | }; 277 | 278 | exports["runFn8"] = [](const boxed& fn) -> boxed { 279 | return [=](const boxed& a) -> boxed { 280 | return [=](const boxed& b) -> boxed { 281 | return [=](const boxed& c) -> boxed { 282 | return [=](const boxed& d) -> boxed { 283 | return [=](const boxed& e) -> boxed { 284 | return [=](const boxed& f) -> boxed { 285 | return [=](const boxed& g) -> boxed { 286 | return [=](const boxed& h) -> boxed { 287 | return unbox>(fn)(a, b, c, d, e, f, g, h); 295 | }; 296 | }; 297 | }; 298 | }; 299 | }; 300 | }; 301 | }; 302 | }; 303 | }; 304 | 305 | exports["runFn9"] = [](const boxed& fn) -> boxed { 306 | return [=](const boxed& a) -> boxed { 307 | return [=](const boxed& b) -> boxed { 308 | return [=](const boxed& c) -> boxed { 309 | return [=](const boxed& d) -> boxed { 310 | return [=](const boxed& e) -> boxed { 311 | return [=](const boxed& f) -> boxed { 312 | return [=](const boxed& g) -> boxed { 313 | return [=](const boxed& h) -> boxed { 314 | return [=](const boxed& i) -> boxed { 315 | return unbox>(fn)(a, b, c, d, e, f, g, h, i); 324 | }; 325 | }; 326 | }; 327 | }; 328 | }; 329 | }; 330 | }; 331 | }; 332 | }; 333 | }; 334 | 335 | exports["runFn10"] = [](const boxed& fn) -> boxed { 336 | return [=](const boxed& a) -> boxed { 337 | return [=](const boxed& b) -> boxed { 338 | return [=](const boxed& c) -> boxed { 339 | return [=](const boxed& d) -> boxed { 340 | return [=](const boxed& e) -> boxed { 341 | return [=](const boxed& f) -> boxed { 342 | return [=](const boxed& g) -> boxed { 343 | return [=](const boxed& h) -> boxed { 344 | return [=](const boxed& i) -> boxed { 345 | return [=](const boxed& j) -> boxed { 346 | return unbox>(fn)(a, b, c, d, e, f, g, h, i, j); 356 | }; 357 | }; 358 | }; 359 | }; 360 | }; 361 | }; 362 | }; 363 | }; 364 | }; 365 | }; 366 | }; 367 | 368 | FOREIGN_END 369 | -------------------------------------------------------------------------------- /integers/data-int.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "purescript.h" 5 | 6 | // Tested with package v4.0.0 7 | 8 | FOREIGN_BEGIN( Data_Int ) 9 | 10 | exports["toNumber"] = [](const boxed& n) -> boxed { 11 | return static_cast(unbox(n)); 12 | }; 13 | 14 | exports["pow"] = [](const boxed& n_) -> boxed { 15 | const auto n = unbox(n_); 16 | return [=](const boxed& p) -> boxed { 17 | const auto r = std::lround(std::pow(n, unbox(p))); 18 | assert(r >= std::numeric_limits::min() && 19 | r <= std::numeric_limits::max()); 20 | return static_cast(r); 21 | }; 22 | }; 23 | 24 | FOREIGN_END 25 | -------------------------------------------------------------------------------- /math/math.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "purescript.h" 3 | 4 | // Tested with package v2.1.1 5 | 6 | FOREIGN_BEGIN( Math ) 7 | 8 | exports["abs"] = [](const boxed& x) -> boxed { 9 | return std::fabs(unbox(x)); 10 | }; 11 | 12 | exports["pow"] = [](const boxed& n_) -> boxed { 13 | const auto n = unbox(n_); 14 | return [=](const boxed& p) -> boxed { 15 | return std::pow(n, unbox(p)); 16 | }; 17 | }; 18 | 19 | FOREIGN_END 20 | -------------------------------------------------------------------------------- /partial/partial-unsafe.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v2.0.0 4 | 5 | FOREIGN_BEGIN( Partial_Unsafe ) 6 | 7 | exports["unsafePartial"] = [](const boxed& f) -> boxed { 8 | return f(boxed()); 9 | }; 10 | 11 | FOREIGN_END 12 | -------------------------------------------------------------------------------- /prelude/control-apply.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Control_Apply ) 6 | 7 | 8 | exports["arrayApply"] = [](const boxed& fs_) -> boxed { 9 | return [=](const boxed& xs_) -> boxed { 10 | const auto& fs = unbox(fs_); 11 | const auto& xs = unbox(xs_); 12 | array_t result; 13 | for (auto f = fs.cbegin(), fend = fs.cend(); f != fend; f++) { 14 | for (auto x = xs.cbegin(), xend = xs.cend(); x != xend; x++) { 15 | result.emplace_back((*f)(*x)); 16 | } 17 | } 18 | return result; 19 | }; 20 | }; 21 | 22 | FOREIGN_END 23 | -------------------------------------------------------------------------------- /prelude/data-bounded.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "purescript.h" 3 | 4 | // Tested with package v4.0.0 5 | 6 | FOREIGN_BEGIN( Data_Bounded ) 7 | 8 | exports["topInt"] = std::numeric_limits::max(); 9 | exports["bottomInt"] = std::numeric_limits::min(); 10 | 11 | exports["topChar"] = u8"\U0010FFFF"; // unicode limit 12 | exports["bottomChar"] = u8"\0"; 13 | 14 | exports["topNumber"] = std::numeric_limits::max(); 15 | exports["bottomNumber"] = std::numeric_limits::min(); 16 | 17 | FOREIGN_END 18 | -------------------------------------------------------------------------------- /prelude/data-eq.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "purescript.h" 4 | 5 | // Tested with package v4.?.? 6 | 7 | FOREIGN_BEGIN( Data_Eq ) 8 | 9 | exports["eqBooleanImpl"] = [](const boxed& b1_) -> boxed { 10 | const auto b1 = unbox(b1_); 11 | return [=](const boxed& b2) -> boxed { 12 | return b1 == unbox(b2); 13 | }; 14 | }; 15 | 16 | exports["eqIntImpl"] = [](const boxed& n1_) -> boxed { 17 | const auto n1 = unbox(n1_); 18 | return [=](const boxed& n2) -> boxed { 19 | return n1 == unbox(n2); 20 | }; 21 | }; 22 | 23 | exports["eqNumberImpl"] = [](const boxed& x_) -> boxed { 24 | const auto x = unbox(x_); 25 | return [=](const boxed& y_) -> boxed { 26 | const auto y = unbox(y_); 27 | if (x == y) { 28 | return true; 29 | } 30 | if (std::isfinite(x) && std::isfinite(y)) { 31 | const auto diff = std::abs(x-y); 32 | return diff <= std::numeric_limits::epsilon() * std::abs(x+y) || 33 | diff < std::numeric_limits::min(); 34 | } else { 35 | return false; 36 | } 37 | }; 38 | }; 39 | 40 | exports["eqCharImpl"] = [](const boxed& c1) -> boxed { 41 | return [=](const boxed& c2) -> boxed { 42 | return unbox(c1) == unbox(c2); 43 | }; 44 | }; 45 | 46 | exports["eqStringImpl"] = [](const boxed& s1) -> boxed { 47 | return [=](const boxed& s2) -> boxed { 48 | return unbox(s1) == unbox(s2); 49 | }; 50 | }; 51 | 52 | exports["eqArrayImpl"] = [](const boxed& f) -> boxed { 53 | return [=](const boxed& xs_) -> boxed { 54 | return [=](const boxed& ys_) -> boxed { 55 | const auto& xs = unbox(xs_); 56 | const auto& ys = unbox(ys_); 57 | if (xs.size() != ys.size()) { 58 | return false; 59 | } 60 | for (auto itx = xs.cbegin(), end = xs.cend(), ity = ys.cbegin(); 61 | itx != end; 62 | itx++, ity++) { 63 | const auto equal = f(*itx)(*ity); 64 | if (!unbox(equal)) { 65 | return false; 66 | } 67 | } 68 | return true; 69 | }; 70 | }; 71 | }; 72 | 73 | FOREIGN_END 74 | -------------------------------------------------------------------------------- /prelude/data-euclideanring.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "purescript.h" 4 | 5 | // Tested with package v4.0.0 6 | 7 | FOREIGN_BEGIN( Data_EuclideanRing ) 8 | 9 | exports["intDegree"] = [](const boxed& x) -> boxed { 10 | return std::min(std::abs(unbox(x)), 2147483647); 11 | }; 12 | 13 | // See the Euclidean definition in 14 | // https://en.m.wikipedia.org/wiki/Modulo_operation. 15 | exports["intDiv"] = [](const boxed& x_) -> boxed { 16 | const auto x = unbox(x_); 17 | return [=](const boxed& y_) -> boxed { 18 | const auto y = unbox(y_); 19 | if (y == 0) return 0; 20 | return int( y > 0 ? std::floor(x / y) : -std::floor(x / -y) ); 21 | }; 22 | }; 23 | 24 | 25 | exports["intMod"] = [](const boxed& x_) -> boxed { 26 | const auto x = unbox(x_); 27 | return [=](const boxed& y_) -> boxed { 28 | const auto y = unbox(y_); 29 | if (y == 0) return 0; 30 | const int yy = std::abs(y); 31 | return ((x % yy) + yy) % yy; 32 | }; 33 | }; 34 | 35 | 36 | FOREIGN_END 37 | -------------------------------------------------------------------------------- /prelude/data-functor.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Data_Functor ) 6 | 7 | 8 | exports["arrayMap"] = [](const boxed& f) -> boxed { 9 | return [=](const boxed& arr_) -> boxed { 10 | const auto& arr = unbox(arr_); 11 | array_t result; 12 | for (auto it = arr.cbegin(), end = arr.cend(); it != end; it++) { 13 | result.emplace_back(f(*it)); 14 | } 15 | return result; 16 | }; 17 | }; 18 | 19 | FOREIGN_END 20 | -------------------------------------------------------------------------------- /prelude/data-heytingalgebra.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Data_HeytingAlgebra ) 6 | 7 | exports["boolConj"] = [](const boxed& b1_) -> boxed { 8 | const auto b1 = unbox(b1_); 9 | return [=](const boxed& b2) -> boxed { 10 | return b1 && unbox(b2); 11 | }; 12 | }; 13 | 14 | exports["boolDisj"] = [](const boxed& b1_) -> boxed { 15 | const auto b1 = unbox(b1_); 16 | return [=](const boxed& b2) -> boxed { 17 | return b1 || unbox(b2); 18 | }; 19 | }; 20 | 21 | exports["boolNot"] = [](const boxed& b) -> boxed { 22 | return !unbox(b); 23 | }; 24 | 25 | FOREIGN_END 26 | -------------------------------------------------------------------------------- /prelude/data-ord.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.?.? 4 | 5 | namespace Data_Ord { 6 | using namespace purescript; 7 | template 8 | static auto ordImpl(const boxed& lt) -> boxed { 9 | return [=](const boxed& eq) -> boxed { 10 | return [=](const boxed& gt) -> boxed { 11 | return [=](const boxed& x_) -> boxed { 12 | const auto x = unbox(x_); 13 | return [=](const boxed& y_) -> boxed { 14 | const auto y = unbox(y_); 15 | return x < y ? lt : x == y ? eq : gt; 16 | }; 17 | }; 18 | }; 19 | }; 20 | } 21 | } 22 | 23 | FOREIGN_BEGIN( Data_Ord ) 24 | 25 | exports["ordBooleanImpl"] = ordImpl; 26 | exports["ordIntImpl"] = ordImpl; 27 | exports["ordNumberImpl"] = ordImpl; 28 | exports["ordStringImpl"] = ordImpl; 29 | exports["ordCharImpl"] = ordImpl; 30 | 31 | FOREIGN_END 32 | -------------------------------------------------------------------------------- /prelude/data-ring.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Data_Ring ) 6 | 7 | exports["intSub"] = [](const boxed& x_) -> boxed { 8 | const auto x = unbox(x_); 9 | return [=](const boxed& y_) -> boxed { 10 | const auto y = unbox(y_); 11 | return x - y; 12 | }; 13 | }; 14 | 15 | exports["numSub"] = [](const boxed& x_) -> boxed { 16 | const auto x = unbox(x_); 17 | return [=](const boxed& y_) -> boxed { 18 | const auto y = unbox(y_); 19 | return x - y; 20 | }; 21 | }; 22 | 23 | 24 | FOREIGN_END 25 | -------------------------------------------------------------------------------- /prelude/data-semigroup.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Data_Semigroup ) 6 | 7 | exports["concatString"] = [](const boxed& s1) -> boxed { 8 | return [=](const boxed& s2) -> boxed { 9 | return unbox(s1) + unbox(s2); 10 | }; 11 | }; 12 | 13 | exports["concatArray"] = [](const boxed& xs) -> boxed { 14 | return [=](const boxed& ys_) -> boxed { 15 | array_t result(unbox(xs)); // makes a copy 16 | const auto& ys = unbox(ys_); 17 | result.insert(result.end(), ys.cbegin(), ys.cend()); 18 | return result; 19 | }; 20 | }; 21 | 22 | FOREIGN_END 23 | -------------------------------------------------------------------------------- /prelude/data-semiring.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Data_Semiring ) 6 | 7 | exports["intAdd"] = [](const boxed& x_) -> boxed { 8 | const auto x = unbox(x_); 9 | return [=](const boxed& y_) -> boxed { 10 | const auto y = unbox(y_); 11 | return x + y; 12 | }; 13 | }; 14 | 15 | exports["intMul"] = [](const boxed& x_) -> boxed { 16 | const auto x = unbox(x_); 17 | return [=](const boxed& y_) -> boxed { 18 | const auto y = unbox(y_); 19 | return x * y; 20 | }; 21 | }; 22 | 23 | exports["numAdd"] = [](const boxed& x_) -> boxed { 24 | const auto x = unbox(x_); 25 | return [=](const boxed& y_) -> boxed { 26 | const auto y = unbox(y_); 27 | return x + y; 28 | }; 29 | }; 30 | 31 | exports["numMul"] = [](const boxed& x_) -> boxed { 32 | const auto x = unbox(x_); 33 | return [=](const boxed& y_) -> boxed { 34 | const auto y = unbox(y_); 35 | return x * y; 36 | }; 37 | }; 38 | 39 | FOREIGN_END 40 | -------------------------------------------------------------------------------- /prelude/data-show.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Data_Show ) 6 | 7 | exports["showIntImpl"] = [](const boxed& n) -> boxed { 8 | return std::to_string(unbox(n)); 9 | }; 10 | 11 | exports["showNumberImpl"] = [](const boxed& n) -> boxed { 12 | return std::to_string(unbox(n)); 13 | }; 14 | 15 | exports["showStringImpl"] = [](const boxed& s) -> boxed { 16 | return "\"" + unbox(s) + "\""; 17 | }; 18 | 19 | exports["showArrayImpl"] = [](const boxed& f) -> boxed { 20 | return [=](const boxed& xs_) -> boxed { 21 | const auto& xs = unbox(xs_); 22 | string s("["); 23 | auto count = xs.size(); 24 | for (auto it = xs.cbegin(), end = xs.cend(); it != end; it++) { 25 | s.append(unbox(f(*it))); 26 | if (--count > 0) { 27 | s.push_back(','); 28 | } 29 | } 30 | s.push_back(']'); 31 | return s; 32 | }; 33 | }; 34 | 35 | FOREIGN_END 36 | -------------------------------------------------------------------------------- /prelude/data-unit.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Data_Unit ) 6 | 7 | exports["unit"] = boxed(); 8 | 9 | FOREIGN_END 10 | -------------------------------------------------------------------------------- /refs/effect-ref.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.1.0 4 | 5 | FOREIGN_BEGIN( Effect_Ref ) 6 | 7 | exports["new"] = [](const boxed& val) -> boxed { 8 | return [=]() -> boxed { 9 | return dict_t{ {"value", val} }; 10 | }; 11 | }; 12 | 13 | exports["read"] = [](const boxed& ref) -> boxed { 14 | return [=]() -> boxed { 15 | return ref["value"]; 16 | }; 17 | }; 18 | 19 | exports["modify'"] = [](const boxed& f) -> boxed { 20 | return [=](const boxed& ref) -> boxed { 21 | return [=]() -> boxed { 22 | boxed t = f(ref["value"]); 23 | dict_t& mutableRef = *static_cast(ref.get()); 24 | mutableRef["value"] = t["state"]; 25 | return t["value"]; 26 | }; 27 | }; 28 | }; 29 | 30 | exports["write"] = [](const boxed& val) -> boxed { 31 | return [=](const boxed& ref) -> boxed { 32 | return [=]() -> boxed { 33 | dict_t& mutableRef = *static_cast(ref.get()); 34 | return mutableRef["value"] = val; 35 | }; 36 | }; 37 | }; 38 | 39 | FOREIGN_END 40 | -------------------------------------------------------------------------------- /st/control-monad-st-internal.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Control_Monad_ST_Internal ) 6 | 7 | exports["map_"] = [](const boxed& f) -> boxed { 8 | return [=](const boxed& a) -> boxed { 9 | return [=]() -> boxed { 10 | return f(a()); 11 | }; 12 | }; 13 | }; 14 | 15 | exports["bind_"] = [](const boxed& a) -> boxed { 16 | return [=](const boxed& f) -> boxed { 17 | return [=]() -> boxed { 18 | return f(a())(); 19 | }; 20 | }; 21 | }; 22 | 23 | exports["run"] = [](const boxed& f) -> boxed { 24 | return f(); 25 | }; 26 | 27 | exports["while"] = [](const boxed& f) -> boxed { 28 | return [=](const boxed& a) -> boxed { 29 | return [=]() -> boxed { 30 | while (unbox(f())) { 31 | a(); 32 | } 33 | return boxed(); 34 | }; 35 | }; 36 | }; 37 | 38 | exports["new"] = [](const boxed& val) -> boxed { 39 | return [=]() -> boxed { 40 | return dict_t{{ "value", val }}; 41 | }; 42 | }; 43 | 44 | exports["read"] = [](const boxed& ref) -> boxed { 45 | return [=]() -> boxed { 46 | return ref["value"]; 47 | }; 48 | }; 49 | 50 | exports["modify'"] = [](const boxed& f) -> boxed { 51 | return [=](const boxed& ref) -> boxed { 52 | return [=]() -> boxed { 53 | boxed t = f(ref["value"]); 54 | dict_t& mutableRef = *static_cast(ref.get()); 55 | mutableRef["value"] = t["state"]; 56 | return t["value"]; 57 | }; 58 | }; 59 | }; 60 | 61 | exports["write"] = [](const boxed& a) -> boxed { 62 | return [=](const boxed& ref) -> boxed { 63 | return [=]() -> boxed { 64 | dict_t& mutableRef = *static_cast(ref.get()); 65 | return mutableRef["value"] = a; 66 | }; 67 | }; 68 | }; 69 | 70 | FOREIGN_END 71 | -------------------------------------------------------------------------------- /strings/data-string-common.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "utf8.h" 4 | 5 | #include "purescript.h" 6 | 7 | // Tested with package v4.0.1 8 | 9 | static constexpr auto kRegexOpts = 10 | std::regex_constants::ECMAScript | std::regex_constants::collate; 11 | 12 | 13 | FOREIGN_BEGIN( Data_String_Common ) 14 | 15 | exports["_localeCompare"] = [](const boxed& lt) -> boxed { 16 | return [=](const boxed& eq) -> boxed { 17 | return [=](const boxed& gt) -> boxed { 18 | return [=](const boxed& s1_) -> boxed { 19 | return [=](const boxed& s2_) -> boxed { 20 | const auto& s1 = unbox(s1_); 21 | const auto& s2 = unbox(s2_); 22 | // TODO: more testing needed 23 | const auto& collate = std::use_facet>(std::locale()); 24 | const auto result = collate.compare(s1.c_str(), s1.c_str() + s1.size(), 25 | s2.c_str(), s2.c_str() + s2.size()); 26 | return result < 0 ? lt : result > 0 ? gt : eq; 27 | }; 28 | }; 29 | }; 30 | }; 31 | }; 32 | 33 | exports["replace"] = [](const boxed& s1_) -> boxed { 34 | return [=](const boxed& s2_) -> boxed { 35 | return [=](const boxed& s3_) -> boxed { 36 | const auto& s1 = unbox(s1_); 37 | const auto& s2 = unbox(s2_); 38 | const auto& s3 = unbox(s3_); 39 | string s(s3); 40 | const auto found = s.find(s1); 41 | return found == string::npos ? s : s.replace(found, s1.size(), s2); 42 | }; 43 | }; 44 | }; 45 | 46 | exports["replaceAll"] = [](const boxed& s1_) -> boxed { 47 | return [=](const boxed& s2_) -> boxed { 48 | return [=](const boxed& s3_) -> boxed { 49 | const auto& s1 = unbox(s1_); 50 | const auto& s2 = unbox(s2_); 51 | const auto& s3 = unbox(s3_); 52 | string s(s3); 53 | for (string::size_type pos = 0, found = string::npos; 54 | (found = s.find(s1, pos)) != string::npos; 55 | pos += s2.size()) { 56 | s.replace(found, s1.size(), s2); 57 | } 58 | return s; 59 | }; 60 | }; 61 | }; 62 | 63 | exports["split"] = [](const boxed& sep_) -> boxed { 64 | return [=](const boxed& str_) -> boxed { 65 | const auto& sep = unbox(sep_); 66 | const auto& str = unbox(str_); 67 | const char * strc = str.c_str(); 68 | array_t result; 69 | if (not sep.empty()) { 70 | const auto sepsz = sep.size(); 71 | const char * sepc = sep.c_str(); 72 | for (const char * subc = strstr(strc, sepc); 73 | subc != nullptr; 74 | strc = subc + sepsz, subc = strstr(strc, sepc)) { 75 | result.emplace_back(string(strc, subc - strc)); 76 | } 77 | result.emplace_back(string(strc)); 78 | } else { 79 | utf8_int32_t n = 0; 80 | for (const char * subc = (char *)utf8codepoint(strc, &n); 81 | subc != nullptr and n != 0; 82 | strc = subc, subc = (char *)utf8codepoint(strc, &n)) { 83 | result.emplace_back(string(strc, subc - strc)); 84 | } 85 | } 86 | return result; 87 | }; 88 | }; 89 | 90 | exports["toLower"] = [](const boxed& s) -> boxed { 91 | char * buf = strdup(unbox(s).c_str()); 92 | utf8lwr(buf); 93 | string result(buf); 94 | free(buf); 95 | return result; 96 | }; 97 | 98 | exports["toUpper"] = [](const boxed& s) -> boxed { 99 | char * buf = strdup(unbox(s).c_str()); 100 | utf8upr(buf); 101 | string result(buf); 102 | free(buf); 103 | return result; 104 | }; 105 | 106 | exports["trim"] = [](const boxed& s) -> boxed { 107 | static const auto expr = std::regex("^\\s+|\\s+$", kRegexOpts); 108 | return std::regex_replace(unbox(s), expr, ""); 109 | }; 110 | 111 | FOREIGN_END 112 | -------------------------------------------------------------------------------- /strings/data-string-unsafe.cpp: -------------------------------------------------------------------------------- 1 | #include "utf8.h" 2 | #include "purescript.h" 3 | 4 | // Tested with package v4.0.1 5 | 6 | FOREIGN_BEGIN( Data_String_Unsafe ) 7 | 8 | exports["charAt"] = [](const boxed& i_) -> boxed { 9 | const auto i = unbox(i_); 10 | return [=](const boxed& s_) -> boxed { 11 | const char * s = unbox(s_).c_str(); 12 | const auto len = utf8len(s); 13 | if (i >= 0 && i < len) { 14 | utf8_int32_t n = 0; 15 | const char * codepoint = (char *)utf8codepoint(s, &n); 16 | for (int count = 0; codepoint != nullptr and n != 0; count++) { 17 | if (count == i) { 18 | return string(s, codepoint - s); 19 | } 20 | s = codepoint; 21 | codepoint = (char *)utf8codepoint(s, &n); 22 | } 23 | } 24 | THROW_("Data.String.Unsafe.charAt: Invalid index."); 25 | }; 26 | }; 27 | 28 | exports["char"] = [](const boxed& s_) -> boxed { 29 | const auto& s = unbox(s_); 30 | const auto len = utf8len(s.c_str()); 31 | if (len == 1) { 32 | return s; 33 | } 34 | THROW_("Data.String.Unsafe.char: Expected string of length 1."); 35 | }; 36 | 37 | FOREIGN_END 38 | -------------------------------------------------------------------------------- /strings/utf8.h: -------------------------------------------------------------------------------- 1 | // The latest version of this library is available on GitHub; 2 | // https://github.com/sheredom/utf8.h 3 | 4 | // This is free and unencumbered software released into the public domain. 5 | // 6 | // Anyone is free to copy, modify, publish, use, compile, sell, or 7 | // distribute this software, either in source code form or as a compiled 8 | // binary, for any purpose, commercial or non-commercial, and by any 9 | // means. 10 | // 11 | // In jurisdictions that recognize copyright laws, the author or authors 12 | // of this software dedicate any and all copyright interest in the 13 | // software to the public domain. We make this dedication for the benefit 14 | // of the public at large and to the detriment of our heirs and 15 | // successors. We intend this dedication to be an overt act of 16 | // relinquishment in perpetuity of all present and future rights to this 17 | // software under copyright law. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 | // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 23 | // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 24 | // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | // OTHER DEALINGS IN THE SOFTWARE. 26 | // 27 | // For more information, please refer to 28 | 29 | #ifndef SHEREDOM_UTF8_H_INCLUDED 30 | #define SHEREDOM_UTF8_H_INCLUDED 31 | 32 | #if defined(_MSC_VER) 33 | #pragma warning(push) 34 | 35 | // disable 'bytes padding added after construct' warning 36 | #pragma warning(disable : 4820) 37 | #endif 38 | 39 | #include 40 | #include 41 | 42 | #if defined(_MSC_VER) 43 | #pragma warning(pop) 44 | #endif 45 | 46 | #if defined(_MSC_VER) 47 | typedef __int32 utf8_int32_t; 48 | #else 49 | #include 50 | typedef int32_t utf8_int32_t; 51 | #endif 52 | 53 | #if defined(__clang__) 54 | #pragma clang diagnostic push 55 | #pragma clang diagnostic ignored "-Wold-style-cast" 56 | #pragma clang diagnostic ignored "-Wcast-qual" 57 | #endif 58 | 59 | #ifdef __cplusplus 60 | extern "C" { 61 | #endif 62 | 63 | #if defined(__clang__) || defined(__GNUC__) 64 | #define utf8_nonnull __attribute__((nonnull)) 65 | #define utf8_pure __attribute__((pure)) 66 | #define utf8_restrict __restrict__ 67 | #define utf8_weak __attribute__((weak)) 68 | #elif defined(_MSC_VER) 69 | #define utf8_nonnull 70 | #define utf8_pure 71 | #define utf8_restrict __restrict 72 | #define utf8_weak __inline 73 | #else 74 | #error Non clang, non gcc, non MSVC compiler found! 75 | #endif 76 | 77 | #ifdef __cplusplus 78 | #define utf8_null NULL 79 | #else 80 | #define utf8_null 0 81 | #endif 82 | 83 | // Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > 84 | // src2 respectively, case insensitive. 85 | utf8_nonnull utf8_pure utf8_weak int utf8casecmp(const void *src1, 86 | const void *src2); 87 | 88 | // Append the utf8 string src onto the utf8 string dst. 89 | utf8_nonnull utf8_weak void *utf8cat(void *utf8_restrict dst, 90 | const void *utf8_restrict src); 91 | 92 | // Find the first match of the utf8 codepoint chr in the utf8 string src. 93 | utf8_nonnull utf8_pure utf8_weak void *utf8chr(const void *src, 94 | utf8_int32_t chr); 95 | 96 | // Return less than 0, 0, greater than 0 if src1 < src2, 97 | // src1 == src2, src1 > src2 respectively. 98 | utf8_nonnull utf8_pure utf8_weak int utf8cmp(const void *src1, 99 | const void *src2); 100 | 101 | // Copy the utf8 string src onto the memory allocated in dst. 102 | utf8_nonnull utf8_weak void *utf8cpy(void *utf8_restrict dst, 103 | const void *utf8_restrict src); 104 | 105 | // Number of utf8 codepoints in the utf8 string src that consists entirely 106 | // of utf8 codepoints not from the utf8 string reject. 107 | utf8_nonnull utf8_pure utf8_weak size_t utf8cspn(const void *src, 108 | const void *reject); 109 | 110 | // Duplicate the utf8 string src by getting its size, malloc'ing a new buffer 111 | // copying over the data, and returning that. Or 0 if malloc failed. 112 | utf8_nonnull utf8_weak void *utf8dup(const void *src); 113 | 114 | // Number of utf8 codepoints in the utf8 string str, 115 | // excluding the null terminating byte. 116 | utf8_nonnull utf8_pure utf8_weak size_t utf8len(const void *str); 117 | 118 | // Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > 119 | // src2 respectively, case insensitive. Checking at most n bytes of each utf8 120 | // string. 121 | utf8_nonnull utf8_pure utf8_weak int utf8ncasecmp(const void *src1, 122 | const void *src2, size_t n); 123 | 124 | // Append the utf8 string src onto the utf8 string dst, 125 | // writing at most n+1 bytes. Can produce an invalid utf8 126 | // string if n falls partway through a utf8 codepoint. 127 | utf8_nonnull utf8_weak void *utf8ncat(void *utf8_restrict dst, 128 | const void *utf8_restrict src, size_t n); 129 | 130 | // Return less than 0, 0, greater than 0 if src1 < src2, 131 | // src1 == src2, src1 > src2 respectively. Checking at most n 132 | // bytes of each utf8 string. 133 | utf8_nonnull utf8_pure utf8_weak int utf8ncmp(const void *src1, 134 | const void *src2, size_t n); 135 | 136 | // Copy the utf8 string src onto the memory allocated in dst. 137 | // Copies at most n bytes. If there is no terminating null byte in 138 | // the first n bytes of src, the string placed into dst will not be 139 | // null-terminated. If the size (in bytes) of src is less than n, 140 | // extra null terminating bytes are appended to dst such that at 141 | // total of n bytes are written. Can produce an invalid utf8 142 | // string if n falls partway through a utf8 codepoint. 143 | utf8_nonnull utf8_weak void *utf8ncpy(void *utf8_restrict dst, 144 | const void *utf8_restrict src, size_t n); 145 | 146 | // Similar to utf8dup, except that at most n bytes of src are copied. If src is 147 | // longer than n, only n bytes are copied and a null byte is added. 148 | // 149 | // Returns a new string if successful, 0 otherwise 150 | utf8_nonnull utf8_weak void *utf8ndup(const void *src, size_t n); 151 | 152 | // Locates the first occurence in the utf8 string str of any byte in the 153 | // utf8 string accept, or 0 if no match was found. 154 | utf8_nonnull utf8_pure utf8_weak void *utf8pbrk(const void *str, 155 | const void *accept); 156 | 157 | // Find the last match of the utf8 codepoint chr in the utf8 string src. 158 | utf8_nonnull utf8_pure utf8_weak void *utf8rchr(const void *src, int chr); 159 | 160 | // Number of bytes in the utf8 string str, 161 | // including the null terminating byte. 162 | utf8_nonnull utf8_pure utf8_weak size_t utf8size(const void *str); 163 | 164 | // Number of utf8 codepoints in the utf8 string src that consists entirely 165 | // of utf8 codepoints from the utf8 string accept. 166 | utf8_nonnull utf8_pure utf8_weak size_t utf8spn(const void *src, 167 | const void *accept); 168 | 169 | // The position of the utf8 string needle in the utf8 string haystack. 170 | utf8_nonnull utf8_pure utf8_weak void *utf8str(const void *haystack, 171 | const void *needle); 172 | 173 | // The position of the utf8 string needle in the utf8 string haystack, case 174 | // insensitive. 175 | utf8_nonnull utf8_pure utf8_weak void *utf8casestr(const void *haystack, 176 | const void *needle); 177 | 178 | // Return 0 on success, or the position of the invalid 179 | // utf8 codepoint on failure. 180 | utf8_nonnull utf8_pure utf8_weak void *utf8valid(const void *str); 181 | 182 | // Sets out_codepoint to the next utf8 codepoint in str, and returns the address 183 | // of the utf8 codepoint after the current one in str. 184 | utf8_nonnull utf8_weak void * 185 | utf8codepoint(const void *utf8_restrict str, 186 | utf8_int32_t *utf8_restrict out_codepoint); 187 | 188 | // Returns the size of the given codepoint in bytes. 189 | utf8_weak size_t utf8codepointsize(utf8_int32_t chr); 190 | 191 | // Write a codepoint to the given string, and return the address to the next 192 | // place after the written codepoint. Pass how many bytes left in the buffer to 193 | // n. If there is not enough space for the codepoint, this function returns 194 | // null. 195 | utf8_nonnull utf8_weak void *utf8catcodepoint(void *utf8_restrict str, 196 | utf8_int32_t chr, size_t n); 197 | 198 | // Returns 1 if the given character is lowercase, or 0 if it is not. 199 | utf8_weak int utf8islower(utf8_int32_t chr); 200 | 201 | // Returns 1 if the given character is uppercase, or 0 if it is not. 202 | utf8_weak int utf8isupper(utf8_int32_t chr); 203 | 204 | // Transform the given string into all lowercase codepoints. 205 | utf8_nonnull utf8_weak void utf8lwr(void *utf8_restrict str); 206 | 207 | // Transform the given string into all uppercase codepoints. 208 | utf8_nonnull utf8_weak void utf8upr(void *utf8_restrict str); 209 | 210 | // Make a codepoint lower case if possible. 211 | utf8_weak utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp); 212 | 213 | // Make a codepoint upper case if possible. 214 | utf8_weak utf8_int32_t utf8uprcodepoint(utf8_int32_t cp); 215 | 216 | #undef utf8_weak 217 | #undef utf8_pure 218 | #undef utf8_nonnull 219 | 220 | int utf8casecmp(const void *src1, const void *src2) { 221 | utf8_int32_t src1_cp, src2_cp, src1_orig_cp, src2_orig_cp; 222 | 223 | for (;;) { 224 | src1 = utf8codepoint(src1, &src1_cp); 225 | src2 = utf8codepoint(src2, &src2_cp); 226 | 227 | // Take a copy of src1 & src2 228 | src1_orig_cp = src1_cp; 229 | src2_orig_cp = src2_cp; 230 | 231 | // Lower the srcs if required 232 | src1_cp = utf8lwrcodepoint(src1_cp); 233 | src2_cp = utf8lwrcodepoint(src2_cp); 234 | 235 | // Check if the lowered codepoints match 236 | if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) { 237 | return 0; 238 | } else if (src1_cp == src2_cp) { 239 | continue; 240 | } 241 | 242 | // If they don't match, then we return which of the original's are less 243 | if (src1_orig_cp < src2_orig_cp) { 244 | return -1; 245 | } else if (src1_orig_cp > src2_orig_cp) { 246 | return 1; 247 | } 248 | } 249 | } 250 | 251 | void *utf8cat(void *utf8_restrict dst, const void *utf8_restrict src) { 252 | char *d = (char *)dst; 253 | const char *s = (const char *)src; 254 | 255 | // find the null terminating byte in dst 256 | while ('\0' != *d) { 257 | d++; 258 | } 259 | 260 | // overwriting the null terminating byte in dst, append src byte-by-byte 261 | while ('\0' != *s) { 262 | *d++ = *s++; 263 | } 264 | 265 | // write out a new null terminating byte into dst 266 | *d = '\0'; 267 | 268 | return dst; 269 | } 270 | 271 | void *utf8chr(const void *src, utf8_int32_t chr) { 272 | char c[5] = {'\0', '\0', '\0', '\0', '\0'}; 273 | 274 | if (0 == chr) { 275 | // being asked to return position of null terminating byte, so 276 | // just run s to the end, and return! 277 | const char *s = (const char *)src; 278 | while ('\0' != *s) { 279 | s++; 280 | } 281 | return (void *)s; 282 | } else if (0 == ((utf8_int32_t)0xffffff80 & chr)) { 283 | // 1-byte/7-bit ascii 284 | // (0b0xxxxxxx) 285 | c[0] = (char)chr; 286 | } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { 287 | // 2-byte/11-bit utf8 code point 288 | // (0b110xxxxx 0b10xxxxxx) 289 | c[0] = 0xc0 | (char)(chr >> 6); 290 | c[1] = 0x80 | (char)(chr & 0x3f); 291 | } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { 292 | // 3-byte/16-bit utf8 code point 293 | // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) 294 | c[0] = 0xe0 | (char)(chr >> 12); 295 | c[1] = 0x80 | (char)((chr >> 6) & 0x3f); 296 | c[2] = 0x80 | (char)(chr & 0x3f); 297 | } else { // if (0 == ((int)0xffe00000 & chr)) { 298 | // 4-byte/21-bit utf8 code point 299 | // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) 300 | c[0] = 0xf0 | (char)(chr >> 18); 301 | c[1] = 0x80 | (char)((chr >> 12) & 0x3f); 302 | c[2] = 0x80 | (char)((chr >> 6) & 0x3f); 303 | c[3] = 0x80 | (char)(chr & 0x3f); 304 | } 305 | 306 | // we've made c into a 2 utf8 codepoint string, one for the chr we are 307 | // seeking, another for the null terminating byte. Now use utf8str to 308 | // search 309 | return utf8str(src, c); 310 | } 311 | 312 | int utf8cmp(const void *src1, const void *src2) { 313 | const unsigned char *s1 = (const unsigned char *)src1; 314 | const unsigned char *s2 = (const unsigned char *)src2; 315 | 316 | while (('\0' != *s1) || ('\0' != *s2)) { 317 | if (*s1 < *s2) { 318 | return -1; 319 | } else if (*s1 > *s2) { 320 | return 1; 321 | } 322 | 323 | s1++; 324 | s2++; 325 | } 326 | 327 | // both utf8 strings matched 328 | return 0; 329 | } 330 | 331 | int utf8coll(const void *src1, const void *src2); 332 | 333 | void *utf8cpy(void *utf8_restrict dst, const void *utf8_restrict src) { 334 | char *d = (char *)dst; 335 | const char *s = (const char *)src; 336 | 337 | // overwriting anything previously in dst, write byte-by-byte 338 | // from src 339 | while ('\0' != *s) { 340 | *d++ = *s++; 341 | } 342 | 343 | // append null terminating byte 344 | *d = '\0'; 345 | 346 | return dst; 347 | } 348 | 349 | size_t utf8cspn(const void *src, const void *reject) { 350 | const char *s = (const char *)src; 351 | size_t chars = 0; 352 | 353 | while ('\0' != *s) { 354 | const char *r = (const char *)reject; 355 | size_t offset = 0; 356 | 357 | while ('\0' != *r) { 358 | // checking that if *r is the start of a utf8 codepoint 359 | // (it is not 0b10xxxxxx) and we have successfully matched 360 | // a previous character (0 < offset) - we found a match 361 | if ((0x80 != (0xc0 & *r)) && (0 < offset)) { 362 | return chars; 363 | } else { 364 | if (*r == s[offset]) { 365 | // part of a utf8 codepoint matched, so move our checking 366 | // onwards to the next byte 367 | offset++; 368 | r++; 369 | } else { 370 | // r could be in the middle of an unmatching utf8 code point, 371 | // so we need to march it on to the next character beginning, 372 | 373 | do { 374 | r++; 375 | } while (0x80 == (0xc0 & *r)); 376 | 377 | // reset offset too as we found a mismatch 378 | offset = 0; 379 | } 380 | } 381 | } 382 | 383 | // the current utf8 codepoint in src did not match reject, but src 384 | // could have been partway through a utf8 codepoint, so we need to 385 | // march it onto the next utf8 codepoint starting byte 386 | do { 387 | s++; 388 | } while ((0x80 == (0xc0 & *s))); 389 | chars++; 390 | } 391 | 392 | return chars; 393 | } 394 | 395 | size_t utf8size(const void *str); 396 | 397 | void *utf8dup(const void *src) { 398 | const char *s = (const char *)src; 399 | char *n = utf8_null; 400 | 401 | // figure out how many bytes (including the terminator) we need to copy first 402 | size_t bytes = utf8size(src); 403 | 404 | n = (char *)malloc(bytes); 405 | 406 | if (utf8_null == n) { 407 | // out of memory so we bail 408 | return utf8_null; 409 | } else { 410 | bytes = 0; 411 | 412 | // copy src byte-by-byte into our new utf8 string 413 | while ('\0' != s[bytes]) { 414 | n[bytes] = s[bytes]; 415 | bytes++; 416 | } 417 | 418 | // append null terminating byte 419 | n[bytes] = '\0'; 420 | return n; 421 | } 422 | } 423 | 424 | void *utf8fry(const void *str); 425 | 426 | size_t utf8len(const void *str) { 427 | const unsigned char *s = (const unsigned char *)str; 428 | size_t length = 0; 429 | 430 | while ('\0' != *s) { 431 | if (0xf0 == (0xf8 & *s)) { 432 | // 4-byte utf8 code point (began with 0b11110xxx) 433 | s += 4; 434 | } else if (0xe0 == (0xf0 & *s)) { 435 | // 3-byte utf8 code point (began with 0b1110xxxx) 436 | s += 3; 437 | } else if (0xc0 == (0xe0 & *s)) { 438 | // 2-byte utf8 code point (began with 0b110xxxxx) 439 | s += 2; 440 | } else { // if (0x00 == (0x80 & *s)) { 441 | // 1-byte ascii (began with 0b0xxxxxxx) 442 | s += 1; 443 | } 444 | 445 | // no matter the bytes we marched s forward by, it was 446 | // only 1 utf8 codepoint 447 | length++; 448 | } 449 | 450 | return length; 451 | } 452 | 453 | int utf8ncasecmp(const void *src1, const void *src2, size_t n) { 454 | utf8_int32_t src1_cp, src2_cp, src1_orig_cp, src2_orig_cp; 455 | 456 | do { 457 | const unsigned char *const s1 = (const unsigned char *)src1; 458 | const unsigned char *const s2 = (const unsigned char *)src2; 459 | 460 | // first check that we have enough bytes left in n to contain an entire 461 | // codepoint 462 | if (0 == n) { 463 | return 0; 464 | } 465 | 466 | if ((1 == n) && ((0xc0 == (0xe0 & *s1)) || (0xc0 == (0xe0 & *s2)))) { 467 | const utf8_int32_t c1 = (0xe0 & *s1); 468 | const utf8_int32_t c2 = (0xe0 & *s2); 469 | 470 | if (c1 < c2) { 471 | return -1; 472 | } else if (c1 > c2) { 473 | return 1; 474 | } else { 475 | return 0; 476 | } 477 | } 478 | 479 | if ((2 >= n) && ((0xe0 == (0xf0 & *s1)) || (0xe0 == (0xf0 & *s2)))) { 480 | const utf8_int32_t c1 = (0xf0 & *s1); 481 | const utf8_int32_t c2 = (0xf0 & *s2); 482 | 483 | if (c1 < c2) { 484 | return -1; 485 | } else if (c1 > c2) { 486 | return 1; 487 | } else { 488 | return 0; 489 | } 490 | } 491 | 492 | if ((3 >= n) && ((0xf0 == (0xf8 & *s1)) || (0xf0 == (0xf8 & *s2)))) { 493 | const utf8_int32_t c1 = (0xf8 & *s1); 494 | const utf8_int32_t c2 = (0xf8 & *s2); 495 | 496 | if (c1 < c2) { 497 | return -1; 498 | } else if (c1 > c2) { 499 | return 1; 500 | } else { 501 | return 0; 502 | } 503 | } 504 | 505 | src1 = utf8codepoint(src1, &src1_cp); 506 | src2 = utf8codepoint(src2, &src2_cp); 507 | n -= utf8codepointsize(src1_cp); 508 | 509 | // Take a copy of src1 & src2 510 | src1_orig_cp = src1_cp; 511 | src2_orig_cp = src2_cp; 512 | 513 | // Lower srcs if required 514 | src1_cp = utf8lwrcodepoint(src1_cp); 515 | src2_cp = utf8lwrcodepoint(src2_cp); 516 | 517 | // Check if the lowered codepoints match 518 | if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) { 519 | return 0; 520 | } else if (src1_cp == src2_cp) { 521 | continue; 522 | } 523 | 524 | // If they don't match, then we return which of the original's are less 525 | if (src1_orig_cp < src2_orig_cp) { 526 | return -1; 527 | } else if (src1_orig_cp > src2_orig_cp) { 528 | return 1; 529 | } 530 | } while (0 < n); 531 | 532 | // both utf8 strings matched 533 | return 0; 534 | } 535 | 536 | void *utf8ncat(void *utf8_restrict dst, const void *utf8_restrict src, 537 | size_t n) { 538 | char *d = (char *)dst; 539 | const char *s = (const char *)src; 540 | 541 | // find the null terminating byte in dst 542 | while ('\0' != *d) { 543 | d++; 544 | } 545 | 546 | // overwriting the null terminating byte in dst, append src byte-by-byte 547 | // stopping if we run out of space 548 | do { 549 | *d++ = *s++; 550 | } while (('\0' != *s) && (0 != --n)); 551 | 552 | // write out a new null terminating byte into dst 553 | *d = '\0'; 554 | 555 | return dst; 556 | } 557 | 558 | int utf8ncmp(const void *src1, const void *src2, size_t n) { 559 | const unsigned char *s1 = (const unsigned char *)src1; 560 | const unsigned char *s2 = (const unsigned char *)src2; 561 | 562 | while ((0 != n--) && (('\0' != *s1) || ('\0' != *s2))) { 563 | if (*s1 < *s2) { 564 | return -1; 565 | } else if (*s1 > *s2) { 566 | return 1; 567 | } 568 | 569 | s1++; 570 | s2++; 571 | } 572 | 573 | // both utf8 strings matched 574 | return 0; 575 | } 576 | 577 | void *utf8ncpy(void *utf8_restrict dst, const void *utf8_restrict src, 578 | size_t n) { 579 | char *d = (char *)dst; 580 | const char *s = (const char *)src; 581 | size_t index; 582 | 583 | // overwriting anything previously in dst, write byte-by-byte 584 | // from src 585 | for (index = 0; index < n; index++) { 586 | d[index] = s[index]; 587 | if ('\0' == s[index]) { 588 | break; 589 | } 590 | } 591 | 592 | // append null terminating byte 593 | for (; index < n; index++) { 594 | d[index] = 0; 595 | } 596 | 597 | return dst; 598 | } 599 | 600 | void *utf8ndup(const void *src, size_t n) { 601 | const char *s = (const char *)src; 602 | char *c = utf8_null; 603 | size_t bytes = 0; 604 | 605 | // Find the end of the string or stop when n is reached 606 | while ('\0' != s[bytes] && bytes < n) { 607 | bytes++; 608 | } 609 | 610 | // In case bytes is actually less than n, we need to set it 611 | // to be used later in the copy byte by byte. 612 | n = bytes; 613 | 614 | c = (char *)malloc(bytes + 1); 615 | if (utf8_null == c) { 616 | // out of memory so we bail 617 | return utf8_null; 618 | } 619 | 620 | bytes = 0; 621 | 622 | // copy src byte-by-byte into our new utf8 string 623 | while ('\0' != s[bytes] && bytes < n) { 624 | c[bytes] = s[bytes]; 625 | bytes++; 626 | } 627 | 628 | // append null terminating byte 629 | c[bytes] = '\0'; 630 | return c; 631 | } 632 | 633 | void *utf8rchr(const void *src, int chr) { 634 | const char *s = (const char *)src; 635 | const char *match = utf8_null; 636 | char c[5] = {'\0', '\0', '\0', '\0', '\0'}; 637 | 638 | if (0 == chr) { 639 | // being asked to return position of null terminating byte, so 640 | // just run s to the end, and return! 641 | while ('\0' != *s) { 642 | s++; 643 | } 644 | return (void *)s; 645 | } else if (0 == ((int)0xffffff80 & chr)) { 646 | // 1-byte/7-bit ascii 647 | // (0b0xxxxxxx) 648 | c[0] = (char)chr; 649 | } else if (0 == ((int)0xfffff800 & chr)) { 650 | // 2-byte/11-bit utf8 code point 651 | // (0b110xxxxx 0b10xxxxxx) 652 | c[0] = 0xc0 | (char)(chr >> 6); 653 | c[1] = 0x80 | (char)(chr & 0x3f); 654 | } else if (0 == ((int)0xffff0000 & chr)) { 655 | // 3-byte/16-bit utf8 code point 656 | // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) 657 | c[0] = 0xe0 | (char)(chr >> 12); 658 | c[1] = 0x80 | (char)((chr >> 6) & 0x3f); 659 | c[2] = 0x80 | (char)(chr & 0x3f); 660 | } else { // if (0 == ((int)0xffe00000 & chr)) { 661 | // 4-byte/21-bit utf8 code point 662 | // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) 663 | c[0] = 0xf0 | (char)(chr >> 18); 664 | c[1] = 0x80 | (char)((chr >> 12) & 0x3f); 665 | c[2] = 0x80 | (char)((chr >> 6) & 0x3f); 666 | c[3] = 0x80 | (char)(chr & 0x3f); 667 | } 668 | 669 | // we've created a 2 utf8 codepoint string in c that is 670 | // the utf8 character asked for by chr, and a null 671 | // terminating byte 672 | 673 | while ('\0' != *s) { 674 | size_t offset = 0; 675 | 676 | while (s[offset] == c[offset]) { 677 | offset++; 678 | } 679 | 680 | if ('\0' == c[offset]) { 681 | // we found a matching utf8 code point 682 | match = s; 683 | s += offset; 684 | } else { 685 | s += offset; 686 | 687 | // need to march s along to next utf8 codepoint start 688 | // (the next byte that doesn't match 0b10xxxxxx) 689 | if ('\0' != *s) { 690 | do { 691 | s++; 692 | } while (0x80 == (0xc0 & *s)); 693 | } 694 | } 695 | } 696 | 697 | // return the last match we found (or 0 if no match was found) 698 | return (void *)match; 699 | } 700 | 701 | void *utf8pbrk(const void *str, const void *accept) { 702 | const char *s = (const char *)str; 703 | 704 | while ('\0' != *s) { 705 | const char *a = (const char *)accept; 706 | size_t offset = 0; 707 | 708 | while ('\0' != *a) { 709 | // checking that if *a is the start of a utf8 codepoint 710 | // (it is not 0b10xxxxxx) and we have successfully matched 711 | // a previous character (0 < offset) - we found a match 712 | if ((0x80 != (0xc0 & *a)) && (0 < offset)) { 713 | return (void *)s; 714 | } else { 715 | if (*a == s[offset]) { 716 | // part of a utf8 codepoint matched, so move our checking 717 | // onwards to the next byte 718 | offset++; 719 | a++; 720 | } else { 721 | // r could be in the middle of an unmatching utf8 code point, 722 | // so we need to march it on to the next character beginning, 723 | 724 | do { 725 | a++; 726 | } while (0x80 == (0xc0 & *a)); 727 | 728 | // reset offset too as we found a mismatch 729 | offset = 0; 730 | } 731 | } 732 | } 733 | 734 | // we found a match on the last utf8 codepoint 735 | if (0 < offset) { 736 | return (void *)s; 737 | } 738 | 739 | // the current utf8 codepoint in src did not match accept, but src 740 | // could have been partway through a utf8 codepoint, so we need to 741 | // march it onto the next utf8 codepoint starting byte 742 | do { 743 | s++; 744 | } while ((0x80 == (0xc0 & *s))); 745 | } 746 | 747 | return utf8_null; 748 | } 749 | 750 | size_t utf8size(const void *str) { 751 | const char *s = (const char *)str; 752 | size_t size = 0; 753 | while ('\0' != s[size]) { 754 | size++; 755 | } 756 | 757 | // we are including the null terminating byte in the size calculation 758 | size++; 759 | return size; 760 | } 761 | 762 | size_t utf8spn(const void *src, const void *accept) { 763 | const char *s = (const char *)src; 764 | size_t chars = 0; 765 | 766 | while ('\0' != *s) { 767 | const char *a = (const char *)accept; 768 | size_t offset = 0; 769 | 770 | while ('\0' != *a) { 771 | // checking that if *r is the start of a utf8 codepoint 772 | // (it is not 0b10xxxxxx) and we have successfully matched 773 | // a previous character (0 < offset) - we found a match 774 | if ((0x80 != (0xc0 & *a)) && (0 < offset)) { 775 | // found a match, so increment the number of utf8 codepoints 776 | // that have matched and stop checking whether any other utf8 777 | // codepoints in a match 778 | chars++; 779 | s += offset; 780 | break; 781 | } else { 782 | if (*a == s[offset]) { 783 | offset++; 784 | a++; 785 | } else { 786 | // a could be in the middle of an unmatching utf8 codepoint, 787 | // so we need to march it on to the next character beginning, 788 | do { 789 | a++; 790 | } while (0x80 == (0xc0 & *a)); 791 | 792 | // reset offset too as we found a mismatch 793 | offset = 0; 794 | } 795 | } 796 | } 797 | 798 | // if a got to its terminating null byte, then we didn't find a match. 799 | // Return the current number of matched utf8 codepoints 800 | if ('\0' == *a) { 801 | return chars; 802 | } 803 | } 804 | 805 | return chars; 806 | } 807 | 808 | void *utf8str(const void *haystack, const void *needle) { 809 | const char *h = (const char *)haystack; 810 | utf8_int32_t throwaway_codepoint; 811 | 812 | // if needle has no utf8 codepoints before the null terminating 813 | // byte then return haystack 814 | if ('\0' == *((const char *)needle)) { 815 | return (void *)haystack; 816 | } 817 | 818 | while ('\0' != *h) { 819 | const char *maybeMatch = h; 820 | const char *n = (const char *)needle; 821 | 822 | while (*h == *n && (*h != '\0' && *n != '\0')) { 823 | n++; 824 | h++; 825 | } 826 | 827 | if ('\0' == *n) { 828 | // we found the whole utf8 string for needle in haystack at 829 | // maybeMatch, so return it 830 | return (void *)maybeMatch; 831 | } else { 832 | // h could be in the middle of an unmatching utf8 codepoint, 833 | // so we need to march it on to the next character beginning 834 | // starting from the current character 835 | h = (const char*)utf8codepoint(maybeMatch, &throwaway_codepoint); 836 | } 837 | } 838 | 839 | // no match 840 | return utf8_null; 841 | } 842 | 843 | void *utf8casestr(const void *haystack, const void *needle) { 844 | const void *h = haystack; 845 | 846 | // if needle has no utf8 codepoints before the null terminating 847 | // byte then return haystack 848 | if ('\0' == *((const char *)needle)) { 849 | return (void *)haystack; 850 | } 851 | 852 | for (;;) { 853 | const void *maybeMatch = h; 854 | const void *n = needle; 855 | utf8_int32_t h_cp, n_cp; 856 | 857 | // Get the next code point and track it 858 | const void *nextH = h = utf8codepoint(h, &h_cp); 859 | n = utf8codepoint(n, &n_cp); 860 | 861 | while ((0 != h_cp) && (0 != n_cp)) { 862 | h_cp = utf8lwrcodepoint(h_cp); 863 | n_cp = utf8lwrcodepoint(n_cp); 864 | 865 | // if we find a mismatch, bail out! 866 | if (h_cp != n_cp) { 867 | break; 868 | } 869 | 870 | h = utf8codepoint(h, &h_cp); 871 | n = utf8codepoint(n, &n_cp); 872 | } 873 | 874 | if (0 == n_cp) { 875 | // we found the whole utf8 string for needle in haystack at 876 | // maybeMatch, so return it 877 | return (void *)maybeMatch; 878 | } 879 | 880 | if (0 == h_cp) { 881 | // no match 882 | return utf8_null; 883 | } 884 | 885 | // Roll back to the next code point in the haystack to test 886 | h = nextH; 887 | } 888 | } 889 | 890 | void *utf8valid(const void *str) { 891 | const char *s = (const char *)str; 892 | 893 | while ('\0' != *s) { 894 | if (0xf0 == (0xf8 & *s)) { 895 | // ensure each of the 3 following bytes in this 4-byte 896 | // utf8 codepoint began with 0b10xxxxxx 897 | if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2])) || 898 | (0x80 != (0xc0 & s[3]))) { 899 | return (void *)s; 900 | } 901 | 902 | // ensure that our utf8 codepoint ended after 4 bytes 903 | if (0x80 == (0xc0 & s[4])) { 904 | return (void *)s; 905 | } 906 | 907 | // ensure that the top 5 bits of this 4-byte utf8 908 | // codepoint were not 0, as then we could have used 909 | // one of the smaller encodings 910 | if ((0 == (0x07 & s[0])) && (0 == (0x30 & s[1]))) { 911 | return (void *)s; 912 | } 913 | 914 | // 4-byte utf8 code point (began with 0b11110xxx) 915 | s += 4; 916 | } else if (0xe0 == (0xf0 & *s)) { 917 | // ensure each of the 2 following bytes in this 3-byte 918 | // utf8 codepoint began with 0b10xxxxxx 919 | if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2]))) { 920 | return (void *)s; 921 | } 922 | 923 | // ensure that our utf8 codepoint ended after 3 bytes 924 | if (0x80 == (0xc0 & s[3])) { 925 | return (void *)s; 926 | } 927 | 928 | // ensure that the top 5 bits of this 3-byte utf8 929 | // codepoint were not 0, as then we could have used 930 | // one of the smaller encodings 931 | if ((0 == (0x0f & s[0])) && (0 == (0x20 & s[1]))) { 932 | return (void *)s; 933 | } 934 | 935 | // 3-byte utf8 code point (began with 0b1110xxxx) 936 | s += 3; 937 | } else if (0xc0 == (0xe0 & *s)) { 938 | // ensure the 1 following byte in this 2-byte 939 | // utf8 codepoint began with 0b10xxxxxx 940 | if (0x80 != (0xc0 & s[1])) { 941 | return (void *)s; 942 | } 943 | 944 | // ensure that our utf8 codepoint ended after 2 bytes 945 | if (0x80 == (0xc0 & s[2])) { 946 | return (void *)s; 947 | } 948 | 949 | // ensure that the top 4 bits of this 2-byte utf8 950 | // codepoint were not 0, as then we could have used 951 | // one of the smaller encodings 952 | if (0 == (0x1e & s[0])) { 953 | return (void *)s; 954 | } 955 | 956 | // 2-byte utf8 code point (began with 0b110xxxxx) 957 | s += 2; 958 | } else if (0x00 == (0x80 & *s)) { 959 | // 1-byte ascii (began with 0b0xxxxxxx) 960 | s += 1; 961 | } else { 962 | // we have an invalid 0b1xxxxxxx utf8 code point entry 963 | return (void *)s; 964 | } 965 | } 966 | 967 | return utf8_null; 968 | } 969 | 970 | void *utf8codepoint(const void *utf8_restrict str, 971 | utf8_int32_t *utf8_restrict out_codepoint) { 972 | const char *s = (const char *)str; 973 | 974 | if (0xf0 == (0xf8 & s[0])) { 975 | // 4 byte utf8 codepoint 976 | *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) | 977 | ((0x3f & s[2]) << 6) | (0x3f & s[3]); 978 | s += 4; 979 | } else if (0xe0 == (0xf0 & s[0])) { 980 | // 3 byte utf8 codepoint 981 | *out_codepoint = 982 | ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]); 983 | s += 3; 984 | } else if (0xc0 == (0xe0 & s[0])) { 985 | // 2 byte utf8 codepoint 986 | *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]); 987 | s += 2; 988 | } else { 989 | // 1 byte utf8 codepoint otherwise 990 | *out_codepoint = s[0]; 991 | s += 1; 992 | } 993 | 994 | return (void *)s; 995 | } 996 | 997 | size_t utf8codepointsize(utf8_int32_t chr) { 998 | if (0 == ((utf8_int32_t)0xffffff80 & chr)) { 999 | return 1; 1000 | } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { 1001 | return 2; 1002 | } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { 1003 | return 3; 1004 | } else { // if (0 == ((int)0xffe00000 & chr)) { 1005 | return 4; 1006 | } 1007 | } 1008 | 1009 | void *utf8catcodepoint(void *utf8_restrict str, utf8_int32_t chr, size_t n) { 1010 | char *s = (char *)str; 1011 | 1012 | if (0 == ((utf8_int32_t)0xffffff80 & chr)) { 1013 | // 1-byte/7-bit ascii 1014 | // (0b0xxxxxxx) 1015 | if (n < 1) { 1016 | return utf8_null; 1017 | } 1018 | s[0] = (char)chr; 1019 | s += 1; 1020 | } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { 1021 | // 2-byte/11-bit utf8 code point 1022 | // (0b110xxxxx 0b10xxxxxx) 1023 | if (n < 2) { 1024 | return utf8_null; 1025 | } 1026 | s[0] = 0xc0 | (char)(chr >> 6); 1027 | s[1] = 0x80 | (char)(chr & 0x3f); 1028 | s += 2; 1029 | } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { 1030 | // 3-byte/16-bit utf8 code point 1031 | // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) 1032 | if (n < 3) { 1033 | return utf8_null; 1034 | } 1035 | s[0] = 0xe0 | (char)(chr >> 12); 1036 | s[1] = 0x80 | (char)((chr >> 6) & 0x3f); 1037 | s[2] = 0x80 | (char)(chr & 0x3f); 1038 | s += 3; 1039 | } else { // if (0 == ((int)0xffe00000 & chr)) { 1040 | // 4-byte/21-bit utf8 code point 1041 | // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) 1042 | if (n < 4) { 1043 | return utf8_null; 1044 | } 1045 | s[0] = 0xf0 | (char)(chr >> 18); 1046 | s[1] = 0x80 | (char)((chr >> 12) & 0x3f); 1047 | s[2] = 0x80 | (char)((chr >> 6) & 0x3f); 1048 | s[3] = 0x80 | (char)(chr & 0x3f); 1049 | s += 4; 1050 | } 1051 | 1052 | return s; 1053 | } 1054 | 1055 | int utf8islower(utf8_int32_t chr) { return chr != utf8uprcodepoint(chr); } 1056 | 1057 | int utf8isupper(utf8_int32_t chr) { return chr != utf8lwrcodepoint(chr); } 1058 | 1059 | void utf8lwr(void *utf8_restrict str) { 1060 | void *p, *pn; 1061 | utf8_int32_t cp; 1062 | 1063 | p = (char *)str; 1064 | pn = utf8codepoint(p, &cp); 1065 | 1066 | while (cp != 0) { 1067 | const utf8_int32_t lwr_cp = utf8lwrcodepoint(cp); 1068 | const size_t size = utf8codepointsize(lwr_cp); 1069 | 1070 | if (lwr_cp != cp) { 1071 | utf8catcodepoint(p, lwr_cp, size); 1072 | } 1073 | 1074 | p = pn; 1075 | pn = utf8codepoint(p, &cp); 1076 | } 1077 | } 1078 | 1079 | void utf8upr(void *utf8_restrict str) { 1080 | void *p, *pn; 1081 | utf8_int32_t cp; 1082 | 1083 | p = (char *)str; 1084 | pn = utf8codepoint(p, &cp); 1085 | 1086 | while (cp != 0) { 1087 | const utf8_int32_t lwr_cp = utf8uprcodepoint(cp); 1088 | const size_t size = utf8codepointsize(lwr_cp); 1089 | 1090 | if (lwr_cp != cp) { 1091 | utf8catcodepoint(p, lwr_cp, size); 1092 | } 1093 | 1094 | p = pn; 1095 | pn = utf8codepoint(p, &cp); 1096 | } 1097 | } 1098 | 1099 | utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) { 1100 | if (((0x0041 <= cp) && (0x005a >= cp)) || 1101 | ((0x00c0 <= cp) && (0x00d6 >= cp)) || 1102 | ((0x00d8 <= cp) && (0x00de >= cp)) || 1103 | ((0x0391 <= cp) && (0x03a1 >= cp)) || 1104 | ((0x03a3 <= cp) && (0x03ab >= cp))) { 1105 | cp += 32; 1106 | } else if (((0x0100 <= cp) && (0x012f >= cp)) || 1107 | ((0x0132 <= cp) && (0x0137 >= cp)) || 1108 | ((0x014a <= cp) && (0x0177 >= cp)) || 1109 | ((0x0182 <= cp) && (0x0185 >= cp)) || 1110 | ((0x01a0 <= cp) && (0x01a5 >= cp)) || 1111 | ((0x01de <= cp) && (0x01ef >= cp)) || 1112 | ((0x01f8 <= cp) && (0x021f >= cp)) || 1113 | ((0x0222 <= cp) && (0x0233 >= cp)) || 1114 | ((0x0246 <= cp) && (0x024f >= cp)) || 1115 | ((0x03d8 <= cp) && (0x03ef >= cp))) { 1116 | cp |= 0x1; 1117 | } else if (((0x0139 <= cp) && (0x0148 >= cp)) || 1118 | ((0x0179 <= cp) && (0x017e >= cp)) || 1119 | ((0x01af <= cp) && (0x01b0 >= cp)) || 1120 | ((0x01b3 <= cp) && (0x01b6 >= cp)) || 1121 | ((0x01cd <= cp) && (0x01dc >= cp))) { 1122 | cp += 1; 1123 | cp &= ~0x1; 1124 | } else { 1125 | switch (cp) { 1126 | default: break; 1127 | case 0x0178: cp = 0x00ff; break; 1128 | case 0x0243: cp = 0x0180; break; 1129 | case 0x018e: cp = 0x01dd; break; 1130 | case 0x023d: cp = 0x019a; break; 1131 | case 0x0220: cp = 0x019e; break; 1132 | case 0x01b7: cp = 0x0292; break; 1133 | case 0x01c4: cp = 0x01c6; break; 1134 | case 0x01c7: cp = 0x01c9; break; 1135 | case 0x01ca: cp = 0x01cc; break; 1136 | case 0x01f1: cp = 0x01f3; break; 1137 | case 0x01f7: cp = 0x01bf; break; 1138 | case 0x0187: cp = 0x0188; break; 1139 | case 0x018b: cp = 0x018c; break; 1140 | case 0x0191: cp = 0x0192; break; 1141 | case 0x0198: cp = 0x0199; break; 1142 | case 0x01a7: cp = 0x01a8; break; 1143 | case 0x01ac: cp = 0x01ad; break; 1144 | case 0x01af: cp = 0x01b0; break; 1145 | case 0x01b8: cp = 0x01b9; break; 1146 | case 0x01bc: cp = 0x01bd; break; 1147 | case 0x01f4: cp = 0x01f5; break; 1148 | case 0x023b: cp = 0x023c; break; 1149 | case 0x0241: cp = 0x0242; break; 1150 | case 0x03fd: cp = 0x037b; break; 1151 | case 0x03fe: cp = 0x037c; break; 1152 | case 0x03ff: cp = 0x037d; break; 1153 | case 0x037f: cp = 0x03f3; break; 1154 | case 0x0386: cp = 0x03ac; break; 1155 | case 0x0388: cp = 0x03ad; break; 1156 | case 0x0389: cp = 0x03ae; break; 1157 | case 0x038a: cp = 0x03af; break; 1158 | case 0x038c: cp = 0x03cc; break; 1159 | case 0x038e: cp = 0x03cd; break; 1160 | case 0x038f: cp = 0x03ce; break; 1161 | case 0x0370: cp = 0x0371; break; 1162 | case 0x0372: cp = 0x0373; break; 1163 | case 0x0376: cp = 0x0377; break; 1164 | case 0x03f4: cp = 0x03d1; break; 1165 | case 0x03cf: cp = 0x03d7; break; 1166 | case 0x03f9: cp = 0x03f2; break; 1167 | case 0x03f7: cp = 0x03f8; break; 1168 | case 0x03fa: cp = 0x03fb; break; 1169 | }; 1170 | } 1171 | 1172 | return cp; 1173 | } 1174 | 1175 | utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) { 1176 | if (((0x0061 <= cp) && (0x007a >= cp)) || 1177 | ((0x00e0 <= cp) && (0x00f6 >= cp)) || 1178 | ((0x00f8 <= cp) && (0x00fe >= cp)) || 1179 | ((0x03b1 <= cp) && (0x03c1 >= cp)) || 1180 | ((0x03c3 <= cp) && (0x03cb >= cp))) { 1181 | cp -= 32; 1182 | } else if (((0x0100 <= cp) && (0x012f >= cp)) || 1183 | ((0x0132 <= cp) && (0x0137 >= cp)) || 1184 | ((0x014a <= cp) && (0x0177 >= cp)) || 1185 | ((0x0182 <= cp) && (0x0185 >= cp)) || 1186 | ((0x01a0 <= cp) && (0x01a5 >= cp)) || 1187 | ((0x01de <= cp) && (0x01ef >= cp)) || 1188 | ((0x01f8 <= cp) && (0x021f >= cp)) || 1189 | ((0x0222 <= cp) && (0x0233 >= cp)) || 1190 | ((0x0246 <= cp) && (0x024f >= cp)) || 1191 | ((0x03d8 <= cp) && (0x03ef >= cp))) { 1192 | cp &= ~0x1; 1193 | } else if (((0x0139 <= cp) && (0x0148 >= cp)) || 1194 | ((0x0179 <= cp) && (0x017e >= cp)) || 1195 | ((0x01af <= cp) && (0x01b0 >= cp)) || 1196 | ((0x01b3 <= cp) && (0x01b6 >= cp)) || 1197 | ((0x01cd <= cp) && (0x01dc >= cp))) { 1198 | cp -= 1; 1199 | cp |= 0x1; 1200 | } else { 1201 | switch (cp) { 1202 | default: break; 1203 | case 0x00ff: cp = 0x0178; break; 1204 | case 0x0180: cp = 0x0243; break; 1205 | case 0x01dd: cp = 0x018e; break; 1206 | case 0x019a: cp = 0x023d; break; 1207 | case 0x019e: cp = 0x0220; break; 1208 | case 0x0292: cp = 0x01b7; break; 1209 | case 0x01c6: cp = 0x01c4; break; 1210 | case 0x01c9: cp = 0x01c7; break; 1211 | case 0x01cc: cp = 0x01ca; break; 1212 | case 0x01f3: cp = 0x01f1; break; 1213 | case 0x01bf: cp = 0x01f7; break; 1214 | case 0x0188: cp = 0x0187; break; 1215 | case 0x018c: cp = 0x018b; break; 1216 | case 0x0192: cp = 0x0191; break; 1217 | case 0x0199: cp = 0x0198; break; 1218 | case 0x01a8: cp = 0x01a7; break; 1219 | case 0x01ad: cp = 0x01ac; break; 1220 | case 0x01b0: cp = 0x01af; break; 1221 | case 0x01b9: cp = 0x01b8; break; 1222 | case 0x01bd: cp = 0x01bc; break; 1223 | case 0x01f5: cp = 0x01f4; break; 1224 | case 0x023c: cp = 0x023b; break; 1225 | case 0x0242: cp = 0x0241; break; 1226 | case 0x037b: cp = 0x03fd; break; 1227 | case 0x037c: cp = 0x03fe; break; 1228 | case 0x037d: cp = 0x03ff; break; 1229 | case 0x03f3: cp = 0x037f; break; 1230 | case 0x03ac: cp = 0x0386; break; 1231 | case 0x03ad: cp = 0x0388; break; 1232 | case 0x03ae: cp = 0x0389; break; 1233 | case 0x03af: cp = 0x038a; break; 1234 | case 0x03cc: cp = 0x038c; break; 1235 | case 0x03cd: cp = 0x038e; break; 1236 | case 0x03ce: cp = 0x038f; break; 1237 | case 0x0371: cp = 0x0370; break; 1238 | case 0x0373: cp = 0x0372; break; 1239 | case 0x0377: cp = 0x0376; break; 1240 | case 0x03d1: cp = 0x03f4; break; 1241 | case 0x03d7: cp = 0x03cf; break; 1242 | case 0x03f2: cp = 0x03f9; break; 1243 | case 0x03f8: cp = 0x03f7; break; 1244 | case 0x03fb: cp = 0x03fa; break; 1245 | }; 1246 | } 1247 | 1248 | return cp; 1249 | } 1250 | 1251 | #undef utf8_restrict 1252 | #undef utf8_null 1253 | 1254 | #ifdef __cplusplus 1255 | } // extern "C" 1256 | #endif 1257 | 1258 | #if defined(__clang__) 1259 | #pragma clang diagnostic pop 1260 | #endif 1261 | 1262 | #endif // SHEREDOM_UTF8_H_INCLUDED 1263 | -------------------------------------------------------------------------------- /unsafe_coerce/unsafe-coerce.cpp: -------------------------------------------------------------------------------- 1 | #include "purescript.h" 2 | 3 | // Tested with package v4.0.0 4 | 5 | FOREIGN_BEGIN( Unsafe_Coerce ) 6 | 7 | exports["unsafeCoerce"] = [](const boxed& x) -> boxed { 8 | return x; 9 | }; 10 | 11 | FOREIGN_END 12 | --------------------------------------------------------------------------------