├── .travis.yml ├── Erlang.js ├── LICENSE ├── README.markdown ├── package.json └── tests └── ErlangTests.js /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "12" 4 | - "10" 5 | - "8" 6 | - "7" 7 | - "6" 8 | - "5" 9 | - "4" 10 | - "0.12" 11 | branches: 12 | only: 13 | - master 14 | notifications: 15 | email: 16 | recipients: 17 | - mjtruog@gmail.com 18 | irc: 19 | channels: 20 | - "irc.oftc.net#cloudi" 21 | template: 22 | - "%{repository_slug} (%{branch} - %{commit}) %{author}: %{commit_message}" 23 | - "View Changes %{compare_url}" 24 | - "Build #%{build_number}: %{message} (%{build_url})" 25 | on_success: change 26 | on_failure: always 27 | -------------------------------------------------------------------------------- /Erlang.js: -------------------------------------------------------------------------------- 1 | //-*-Mode:javascript;coding:utf-8;tab-width:4;c-basic-offset:4;indent-tabs-mode:()-*- 2 | // ex: set ft=javascript fenc=utf-8 sts=4 ts=4 sw=4 et nomod: 3 | // 4 | // MIT License 5 | // 6 | // Copyright (c) 2014-2023 Michael Truog 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a 9 | // copy of this software and associated documentation files (the "Software"), 10 | // to deal in the Software without restriction, including without limitation 11 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the 13 | // Software is furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 | // DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | exports.Erlang = new function() { 28 | var Erlang = this; // namespace 29 | 'use strict'; 30 | 31 | var zlib = require('zlib'); 32 | 33 | var UNDEFINED = 'undefined'; // Change with set_undefined 34 | 35 | // tag values here http://www.erlang.org/doc/apps/erts/erl_ext_dist.html 36 | var TAG_VERSION = 131; 37 | var TAG_COMPRESSED_ZLIB = 80; 38 | var TAG_NEW_FLOAT_EXT = 70; 39 | var TAG_BIT_BINARY_EXT = 77; 40 | var TAG_ATOM_CACHE_REF = 78; 41 | var TAG_NEW_PID_EXT = 88; 42 | var TAG_NEW_PORT_EXT = 89; 43 | var TAG_NEWER_REFERENCE_EXT = 90; 44 | var TAG_SMALL_INTEGER_EXT = 97; 45 | var TAG_INTEGER_EXT = 98; 46 | var TAG_FLOAT_EXT = 99; 47 | var TAG_ATOM_EXT = 100; 48 | var TAG_REFERENCE_EXT = 101; 49 | var TAG_PORT_EXT = 102; 50 | var TAG_PID_EXT = 103; 51 | var TAG_SMALL_TUPLE_EXT = 104; 52 | var TAG_LARGE_TUPLE_EXT = 105; 53 | var TAG_NIL_EXT = 106; 54 | var TAG_STRING_EXT = 107; 55 | var TAG_LIST_EXT = 108; 56 | var TAG_BINARY_EXT = 109; 57 | var TAG_SMALL_BIG_EXT = 110; 58 | var TAG_LARGE_BIG_EXT = 111; 59 | var TAG_NEW_FUN_EXT = 112; 60 | var TAG_EXPORT_EXT = 113; 61 | var TAG_NEW_REFERENCE_EXT = 114; 62 | var TAG_SMALL_ATOM_EXT = 115; 63 | var TAG_MAP_EXT = 116; 64 | var TAG_FUN_EXT = 117; 65 | var TAG_ATOM_UTF8_EXT = 118; 66 | var TAG_SMALL_ATOM_UTF8_EXT = 119; 67 | var TAG_V4_PORT_EXT = 120; 68 | var TAG_LOCAL_EXT = 121; 69 | 70 | var nodejs_version = process.versions['node'].split('.').map(function (s) { 71 | return parseInt(s); 72 | }); 73 | Erlang.nodejs_version_after = function nodejs_version_after (s, include) { 74 | var v = s.split('.').map(function (s) { 75 | return parseInt(s); 76 | }); 77 | for (var i = 0; i < v.length; i++) { 78 | if (nodejs_version[i] > v[i]) { 79 | return true; 80 | } 81 | if (nodejs_version[i] < v[i]) { 82 | return false; 83 | } 84 | } 85 | return include; 86 | }; 87 | var toNativeString = {}.toString; 88 | var bufferFrom; 89 | var bufferAlloc; 90 | if (Erlang.nodejs_version_after('5.10.0',true)) { 91 | bufferFrom = Buffer.from; 92 | bufferAlloc = Buffer.alloc; 93 | } 94 | else { 95 | bufferFrom = Buffer; 96 | bufferAlloc = Buffer; 97 | } 98 | var packUint16 = function packUint16 (value, i, buffer) { // big endian 99 | buffer[i] = (value >>> 8) & 0xff; 100 | buffer[i + 1] = value & 0xff; 101 | return buffer; 102 | }; 103 | var packUint32 = function packUint32 (value, i, buffer) { // big endian 104 | buffer[i] = (value >>> 24) & 0xff; 105 | buffer[i + 1] = (value >>> 16) & 0xff; 106 | buffer[i + 2] = (value >>> 8) & 0xff; 107 | buffer[i + 3] = value & 0xff; 108 | return buffer; 109 | }; 110 | var unpackUint16 = function unpackUint16 (i, buffer) { // big endian 111 | return (buffer[i] << 8) | 112 | buffer[i + 1]; 113 | }; 114 | var unpackUint32 = function unpackUint32 (i, buffer) { // big endian 115 | return (buffer[i] << 24) | 116 | (buffer[i + 1] << 16) | 117 | (buffer[i + 2] << 8) | 118 | buffer[i + 3]; 119 | }; 120 | 121 | // Exception objects listed alphabetically 122 | 123 | var InputException = function InputException (message) { 124 | var error = new Error(message); 125 | error.name = 'InputException'; 126 | this.message = error.message; 127 | if (error.stack) { 128 | this.stack = error.stack; 129 | } 130 | } 131 | InputException.prototype = Object.create(Error.prototype, { 132 | name: { value: 'InputException' } 133 | }); 134 | var OutputException = function OutputException (message) { 135 | var error = new Error(message); 136 | error.name = 'OutputException'; 137 | this.message = error.message; 138 | if (error.stack) { 139 | this.stack = error.stack; 140 | } 141 | } 142 | OutputException.prototype = Object.create(Error.prototype, { 143 | name: { value: 'OutputException' } 144 | }); 145 | var ParseException = function ParseException (message) { 146 | var error = new Error(message); 147 | error.name = 'ParseException'; 148 | this.message = error.message; 149 | if (error.stack) { 150 | this.stack = error.stack; 151 | } 152 | } 153 | ParseException.prototype = Object.create(Error.prototype, { 154 | name: { value: 'ParseException' } 155 | }); 156 | 157 | var compress = function(buffer_in, level, callback) { 158 | var o = zlib.createDeflate({level: level}); 159 | var buffers_out = []; 160 | o.on('error', function(err) { 161 | o.removeAllListeners(); 162 | callback(new OutputException(err.toString()), undefined); 163 | }); 164 | o.on('data', function(chunk) { 165 | buffers_out.push(chunk); 166 | }); 167 | o.on('end', function() { 168 | o.removeAllListeners(); 169 | var buffer_out = Buffer.concat(buffers_out); 170 | callback(undefined, buffer_out); 171 | }); 172 | o.write(buffer_in); 173 | o.end(); 174 | }; 175 | var uncompress = function(buffer_in, callback) { 176 | zlib.inflate(buffer_in, function(err, buffer_out) { 177 | if (err) { 178 | callback(new ParseException(err.toString()), undefined); 179 | } 180 | else { 181 | callback(undefined, buffer_out); 182 | } 183 | }); 184 | }; 185 | 186 | // Erlang term objects listed alphabetically 187 | 188 | Erlang.OtpErlangAtom = function OtpErlangAtom (value, utf8) { 189 | this.value = value; 190 | this.utf8 = typeof utf8 !== 'undefined' ? utf8 : true; 191 | }; 192 | Erlang.OtpErlangAtom.prototype.binary = function() { 193 | if (typeof this.value == 'number') { 194 | var buffer = new bufferAlloc(2); 195 | buffer[0] = TAG_ATOM_CACHE_REF; 196 | buffer[1] = this.value; 197 | return buffer; 198 | } 199 | else if (typeof this.value == 'string') { 200 | var length = this.value.length; 201 | if (this.utf8) { 202 | if (length <= 255) { 203 | var buffer = new bufferAlloc(2 + length); 204 | buffer[0] = TAG_SMALL_ATOM_UTF8_EXT; 205 | buffer[1] = length; 206 | buffer.write(this.value, 2, length, 'binary'); 207 | return buffer; 208 | } 209 | else if (length <= 65535) { 210 | var buffer = new bufferAlloc(3 + length); 211 | buffer[0] = TAG_ATOM_UTF8_EXT; 212 | packUint16(length, 1, buffer); 213 | buffer.write(this.value, 3, length, 'binary'); 214 | return buffer; 215 | } 216 | else { 217 | throw new OutputException('uint16 overflow'); 218 | } 219 | } 220 | else { 221 | // deprecated 222 | // (not used in Erlang/OTP 26, i.e., minor_version 2) 223 | if (length <= 255) { 224 | var buffer = new bufferAlloc(2 + length); 225 | buffer[0] = TAG_SMALL_ATOM_EXT; 226 | buffer[1] = length; 227 | buffer.write(this.value, 2, length, 'binary'); 228 | return buffer; 229 | } 230 | else if (length <= 65535) { 231 | var buffer = new bufferAlloc(3 + length); 232 | buffer[0] = TAG_ATOM_EXT; 233 | packUint16(length, 1, buffer); 234 | buffer.write(this.value, 3, length, 'binary'); 235 | return buffer; 236 | } 237 | else { 238 | throw new OutputException('uint16 overflow'); 239 | } 240 | } 241 | } 242 | else { 243 | throw new OutputException('unknown atom type'); 244 | } 245 | }; 246 | Erlang.OtpErlangAtom.prototype.toString = function() { 247 | return 'OtpErlangAtom(' + this.value + ',' + this.utf8 + ')'; 248 | }; 249 | 250 | Erlang.OtpErlangAtomLarge = function OtpErlangAtomLarge (value, utf8) { 251 | this.value = value; 252 | this.utf8 = typeof utf8 !== 'undefined' ? utf8 : true; 253 | }; 254 | Erlang.OtpErlangAtomLarge.prototype.binary = function() { 255 | if (typeof this.value == 'string') { 256 | var length = this.value.length; 257 | if (this.utf8) { 258 | if (length <= 65535) { 259 | var buffer = new bufferAlloc(3 + length); 260 | buffer[0] = TAG_ATOM_UTF8_EXT; 261 | packUint16(length, 1, buffer); 262 | buffer.write(this.value, 3, length, 'binary'); 263 | return buffer; 264 | } 265 | else { 266 | throw new OutputException('uint16 overflow'); 267 | } 268 | } 269 | else { 270 | // deprecated 271 | // (not used in Erlang/OTP 26, i.e., minor_version 2) 272 | if (length <= 65535) { 273 | var buffer = new bufferAlloc(3 + length); 274 | buffer[0] = TAG_ATOM_EXT; 275 | packUint16(length, 1, buffer); 276 | buffer.write(this.value, 3, length, 'binary'); 277 | return buffer; 278 | } 279 | else { 280 | throw new OutputException('uint16 overflow'); 281 | } 282 | } 283 | } 284 | else { 285 | throw new OutputException('unknown atom type'); 286 | } 287 | }; 288 | Erlang.OtpErlangAtomLarge.prototype.toString = function() { 289 | return 'OtpErlangAtomLarge(' + this.value + ',' + this.utf8 + ')'; 290 | }; 291 | 292 | Erlang.OtpErlangBinary = function OtpErlangBinary (value, bits) { 293 | this.value = value; 294 | this.bits = typeof bits !== 'undefined' ? bits : 8; 295 | }; 296 | Erlang.OtpErlangBinary.prototype.binary = function() { 297 | if (typeof this.value == 'string') { 298 | var length = this.value.length; 299 | if (length > 4294967295) { 300 | throw new OutputException('uint32 overflow'); 301 | } 302 | else if (this.bits != 8) { 303 | var buffer = new bufferAlloc(6 + length); 304 | buffer[0] = TAG_BIT_BINARY_EXT; 305 | packUint32(length, 1, buffer); 306 | buffer[5] = this.bits; 307 | buffer.write(this.value, 6, length, 'binary'); 308 | return buffer; 309 | } 310 | else { 311 | var buffer = new bufferAlloc(5 + length); 312 | buffer[0] = TAG_BINARY_EXT; 313 | packUint32(length, 1, buffer); 314 | buffer.write(this.value, 5, length, 'binary'); 315 | return buffer; 316 | } 317 | } 318 | else if (Buffer.isBuffer(this.value)) { 319 | var length = this.value.length; 320 | if (length > 4294967295) { 321 | throw new OutputException('uint32 overflow'); 322 | } 323 | else if (this.bits != 8) { 324 | var buffer = new bufferAlloc(6 + length); 325 | buffer[0] = TAG_BIT_BINARY_EXT; 326 | packUint32(length, 1, buffer); 327 | buffer[5] = this.bits; 328 | this.value.copy(buffer, 6); 329 | return buffer; 330 | } 331 | else { 332 | var buffer = new bufferAlloc(5 + length); 333 | buffer[0] = TAG_BINARY_EXT; 334 | packUint32(length, 1, buffer); 335 | this.value.copy(buffer, 5); 336 | return buffer; 337 | } 338 | } 339 | else { 340 | throw new OutputException('unknown binary type'); 341 | } 342 | }; 343 | Erlang.OtpErlangBinary.prototype.toString = function() { 344 | return 'OtpErlangBinary(' + (typeof this.value) + ',' + this.bits + ')'; 345 | }; 346 | 347 | Erlang.OtpErlangList = function OtpErlangList (value, improper) { 348 | this.value = value; 349 | this.improper = typeof improper !== 'undefined' ? improper : false; 350 | }; 351 | Erlang.OtpErlangList.prototype.binary = function() { 352 | if (typeof this.value === 'object' && 353 | toNativeString.call(this.value) == '[object Array]') { 354 | var length = this.value.length; 355 | if (length == 0) { 356 | return new bufferFrom([TAG_NIL_EXT]); 357 | } 358 | if (length > 4294967295) { 359 | throw new OutputException('uint32 overflow'); 360 | } 361 | var header = new bufferAlloc(5); 362 | header[0] = TAG_LIST_EXT; 363 | if (this.improper) { 364 | packUint32(length - 1, 1, header); 365 | } 366 | else { 367 | packUint32(length, 1, header); 368 | } 369 | var buffers = [header]; 370 | for (var i = 0; i < length; i++) { 371 | buffers.push(Erlang._term_to_binary(this.value[i])); 372 | } 373 | if (! this.improper) { 374 | buffers.push(new bufferFrom([TAG_NIL_EXT])); 375 | } 376 | return Buffer.concat(buffers); 377 | } 378 | else { 379 | throw new OutputException('unknown list type'); 380 | } 381 | }; 382 | 383 | Erlang.OtpErlangList.prototype.toString = function() { 384 | return 'OtpErlangList([' + this.value.join(',') + '],' + 385 | this.improper + ')'; 386 | }; 387 | 388 | Erlang.OtpErlangMap = function OtpErlangMap (value) { 389 | this.value = value; 390 | }; 391 | Erlang.OtpErlangMap.prototype.binary = function() { 392 | if (typeof this.value === 'object') { 393 | return Erlang._object_to_binary(this.value); 394 | } 395 | else { 396 | throw new OutputException('unknown map type'); 397 | } 398 | }; 399 | Erlang.OtpErlangMap.prototype.toString = function() { 400 | return 'OtpErlangMap()'; 401 | }; 402 | 403 | Erlang.OtpErlangPid = function OtpErlangPid (node, id, serial, creation) { 404 | this.node = node; 405 | this.id = id; 406 | this.serial = serial; 407 | this.creation = creation; 408 | }; 409 | Erlang.OtpErlangPid.prototype.binary = function() { 410 | var creation_size = this.creation.length; 411 | if (creation_size == 1) { 412 | return Buffer.concat([new bufferFrom([TAG_PID_EXT]), 413 | this.node.binary(), 414 | this.id, this.serial, this.creation]); 415 | } 416 | else if (creation_size == 4) { 417 | return Buffer.concat([new bufferFrom([TAG_NEW_PID_EXT]), 418 | this.node.binary(), 419 | this.id, this.serial, this.creation]); 420 | } 421 | else { 422 | throw new OutputException('unknown pid type'); 423 | } 424 | }; 425 | Erlang.OtpErlangPid.prototype.toString = function() { 426 | return 'OtpErlangPid()'; 427 | }; 428 | 429 | Erlang.OtpErlangPort = function OtpErlangPort (node, id, creation) { 430 | this.node = node; 431 | this.id = id; 432 | this.creation = creation; 433 | }; 434 | Erlang.OtpErlangPort.prototype.binary = function() { 435 | var id_size = this.id.length; 436 | if (id_size == 8) { 437 | return Buffer.concat([new bufferFrom([TAG_V4_PORT_EXT]), 438 | this.node.binary(), this.id, this.creation]); 439 | } 440 | var creation_size = this.creation.length; 441 | if (creation_size == 4) { 442 | return Buffer.concat([new bufferFrom([TAG_NEW_PORT_EXT]), 443 | this.node.binary(), this.id, this.creation]); 444 | } 445 | else if (creation_size == 1) { 446 | return Buffer.concat([new bufferFrom([TAG_PORT_EXT]), 447 | this.node.binary(), this.id, this.creation]); 448 | } 449 | else { 450 | throw new OutputException('unknown port type'); 451 | } 452 | }; 453 | Erlang.OtpErlangPort.prototype.toString = function() { 454 | return 'OtpErlangPort()'; 455 | }; 456 | 457 | Erlang.OtpErlangReference = function OtpErlangReference (node, id, creation) { 458 | this.node = node; 459 | this.id = id; 460 | this.creation = creation; 461 | }; 462 | Erlang.OtpErlangReference.prototype.binary = function() { 463 | var length = this.id.length / 4; 464 | if (length == 0) { 465 | var header = new bufferAlloc(3); 466 | header[0] = TAG_REFERENCE_EXT; 467 | packUint16(length, 1, header); 468 | return Buffer.concat([header, 469 | this.node.binary(), this.id, this.creation]); 470 | } 471 | else if (length <= 65535) { 472 | var creation_size = this.creation.length; 473 | var header = new bufferAlloc(3); 474 | if (creation_size == 1) { 475 | header[0] = TAG_NEW_REFERENCE_EXT; 476 | } 477 | else if (creation_size == 4) { 478 | header[0] = TAG_NEWER_REFERENCE_EXT; 479 | } 480 | else { 481 | throw new OutputException('unknown reference type'); 482 | } 483 | packUint16(length, 1, header); 484 | return Buffer.concat([header, 485 | this.node.binary(), this.creation, this.id]); 486 | } 487 | else { 488 | throw new OutputException('uint16 overflow'); 489 | } 490 | }; 491 | Erlang.OtpErlangReference.prototype.toString = function() { 492 | var tag; 493 | var length = this.id.length / 4; 494 | if (length == 0) { 495 | tag = TAG_REFERENCE_EXT; 496 | } 497 | else { 498 | var creation_size = this.creation.length; 499 | if (creation_size == 1) { 500 | tag = TAG_NEW_REFERENCE_EXT; 501 | } 502 | else if (creation_size == 4) { 503 | tag = TAG_NEWER_REFERENCE_EXT; 504 | } 505 | else { 506 | throw new OutputException('unknown reference type'); 507 | } 508 | } 509 | return 'OtpErlangReference(' + tag + ')'; 510 | }; 511 | 512 | Erlang.OtpErlangFunction = function OtpErlangFunction (tag, value) { 513 | this.tag = tag; 514 | this.value = value; 515 | }; 516 | Erlang.OtpErlangFunction.prototype.binary = function() { 517 | return Buffer.concat([new bufferFrom([this.tag]), this.value]); 518 | }; 519 | Erlang.OtpErlangFunction.prototype.toString = function() { 520 | return 'OtpErlangFunction(' + this.tag + ')'; 521 | }; 522 | 523 | // core functionality 524 | 525 | Erlang.binary_to_term = function binary_to_term (data, callback) { 526 | if (typeof callback === 'undefined') { 527 | throw new InputException('callback required'); 528 | } 529 | try { 530 | if (typeof data === 'string') { 531 | data = new bufferFrom(data, 'binary'); 532 | } 533 | if (! Buffer.isBuffer(data)) { 534 | throw new ParseException('not bytes input'); 535 | } 536 | var size = data.length; 537 | if (size <= 1) { 538 | throw new ParseException('null input'); 539 | } 540 | if (data[0] != TAG_VERSION) { 541 | throw new ParseException('invalid version'); 542 | } 543 | if (TAG_COMPRESSED_ZLIB == data[1]) { 544 | if (size <= 6) { 545 | throw new ParseException('null compressed input'); 546 | } 547 | var i = 2; 548 | var size_uncompressed = unpackUint32(i, data); 549 | if (size_uncompressed == 0) { 550 | throw new ParseException('compressed data null'); 551 | } 552 | i += 4; 553 | var data_compressed = data.slice(i); 554 | var j = data_compressed.length; 555 | uncompress(data_compressed, function(err, data_uncompressed) { 556 | if (err) { 557 | callback(err, undefined); 558 | } 559 | else { 560 | if (size_uncompressed != data_uncompressed.length) { 561 | callback(new ParseException('compression corrupt'), 562 | undefined); 563 | return; 564 | } 565 | var result = Erlang._binary_to_term(0, data_uncompressed); 566 | if (result[0] != size_uncompressed) { 567 | callback(new ParseException('unparsed data'), 568 | undefined); 569 | return; 570 | } 571 | callback(undefined, result[1]); 572 | } 573 | }); 574 | } 575 | else { 576 | var result = Erlang._binary_to_term(1, data); 577 | if (result[0] != size) { 578 | throw new ParseException('unparsed data'); 579 | } 580 | callback(undefined, result[1]); 581 | } 582 | } 583 | catch (err) { 584 | if (! (err instanceof ParseException)) { 585 | var err_new = new ParseException('missing data'); 586 | if (err.stack) { 587 | err_new.stack = err.stack; 588 | } 589 | err = err_new; 590 | } 591 | callback(err, undefined); 592 | } 593 | }; 594 | 595 | Erlang.term_to_binary = function term_to_binary (term, callback, compressed) { 596 | if (typeof callback === 'undefined') { 597 | throw new InputException('callback required'); 598 | } 599 | compressed = typeof compressed !== 'undefined' ? compressed : false; 600 | try { 601 | var data_uncompressed = Erlang._term_to_binary(term); 602 | if (compressed === false) { 603 | callback(undefined, 604 | Buffer.concat([new bufferFrom([TAG_VERSION]), 605 | data_uncompressed])); 606 | } 607 | else { 608 | if (compressed === true) { 609 | compressed = 6; 610 | } 611 | else if (compressed < 0 || compressed > 9) { 612 | throw new InputException('compressed in [0..9]'); 613 | } 614 | else if (compressed === 0) { 615 | throw new InputException('node.js zlib compressed 0 broken'); 616 | } 617 | compress(data_uncompressed, compressed, 618 | function (err, data_compressed) { 619 | if (err) { 620 | callback(err, undefined); 621 | } 622 | else { 623 | var size_uncompressed = data_uncompressed.length; 624 | if (size_uncompressed > 4294967295) { 625 | throw new OutputException('uint32 overflow'); 626 | } 627 | var header = new bufferAlloc(6); 628 | header[0] = TAG_VERSION; 629 | header[1] = TAG_COMPRESSED_ZLIB; 630 | packUint32(size_uncompressed, 2, header); 631 | callback(undefined, 632 | Buffer.concat([header, data_compressed])); 633 | } 634 | }); 635 | } 636 | } 637 | catch (err) { 638 | if (! (err instanceof InputException || 639 | err instanceof OutputException)) { 640 | var err_new = new OutputException(err.toString()); 641 | if (err.stack) { 642 | err_new.stack = err.stack; 643 | } 644 | err = err_new; 645 | } 646 | callback(err, undefined); 647 | } 648 | }; 649 | 650 | // binary_to_term implementation functions 651 | 652 | Erlang._binary_to_term = function _binary_to_term (i, data) { 653 | var tag = data[i]; 654 | i += 1; 655 | switch (tag) { 656 | case TAG_NEW_FLOAT_EXT: 657 | var buffer = new ArrayBuffer(8); 658 | var view = new Uint8Array(buffer); 659 | for (var offset = 0; offset < 8; ++offset) { 660 | view[offset] = data[i + offset]; 661 | } 662 | var value = new DataView(buffer); 663 | return [i + 8, value.getFloat64(0)]; 664 | case TAG_BIT_BINARY_EXT: 665 | var j = unpackUint32(i, data); 666 | i += 4; 667 | var bits = data[i]; 668 | i += 1; 669 | return [i + j, 670 | new Erlang.OtpErlangBinary(data.slice(i, i + j), bits)]; 671 | case TAG_ATOM_CACHE_REF: 672 | return [i + 1, new Erlang.OtpErlangAtom(data[i])]; 673 | case TAG_SMALL_INTEGER_EXT: 674 | return [i + 1, data[i]]; 675 | case TAG_INTEGER_EXT: 676 | var value = unpackUint32(i, data); 677 | if (0 != (value & 0x80000000)) { 678 | value = -2147483648 + (value & 0x7fffffff); 679 | } 680 | return [i + 4, value]; 681 | case TAG_FLOAT_EXT: 682 | return [i + 31, parseFloat(data.toString('binary', i, i + 31))]; 683 | case TAG_V4_PORT_EXT: 684 | case TAG_NEW_PORT_EXT: 685 | case TAG_REFERENCE_EXT: 686 | case TAG_PORT_EXT: 687 | var result = Erlang._binary_to_atom(i, data); 688 | i = result[0]; 689 | var node = result[1]; 690 | var id; 691 | if (tag == TAG_V4_PORT_EXT) { 692 | id = data.slice(i, i + 8); 693 | i += 8; 694 | } 695 | else { 696 | id = data.slice(i, i + 4); 697 | i += 4; 698 | } 699 | var creation; 700 | if (tag == TAG_V4_PORT_EXT || tag == TAG_NEW_PORT_EXT) { 701 | creation = data.slice(i, i + 4); 702 | i += 4; 703 | } 704 | else { 705 | creation = data.slice(i, i + 1); 706 | i += 1; 707 | if (tag == TAG_REFERENCE_EXT) { 708 | return [i, new Erlang.OtpErlangReference(node, id, 709 | creation)]; 710 | } 711 | } 712 | // tag == TAG_V4_PORT_EXT || tag == TAG_NEW_PORT_EXT || 713 | // tag == TAG_PORT_EXT 714 | return [i, new Erlang.OtpErlangPort(node, id, creation)]; 715 | case TAG_NEW_PID_EXT: 716 | case TAG_PID_EXT: 717 | var result = Erlang._binary_to_atom(i, data); 718 | i = result[0]; 719 | var node = result[1]; 720 | var id = data.slice(i, i + 4); 721 | i += 4; 722 | var serial = data.slice(i, i + 4); 723 | i += 4; 724 | var creation; 725 | if (tag == TAG_NEW_PID_EXT) { 726 | creation = data.slice(i, i + 4); 727 | i += 4; 728 | } 729 | else if (tag == TAG_PID_EXT) { 730 | creation = data.slice(i, i + 1); 731 | i += 1; 732 | } 733 | return [i, new Erlang.OtpErlangPid(node, id, serial, creation)]; 734 | case TAG_SMALL_TUPLE_EXT: 735 | case TAG_LARGE_TUPLE_EXT: 736 | var length; 737 | if (tag == TAG_SMALL_TUPLE_EXT) { 738 | length = data[i]; 739 | i += 1; 740 | } 741 | else if (tag == TAG_LARGE_TUPLE_EXT) { 742 | length = unpackUint32(i, data); 743 | i += 4; 744 | } 745 | return Erlang._binary_to_term_sequence(i, length, data); 746 | case TAG_NIL_EXT: 747 | return [i, new Erlang.OtpErlangList([])]; 748 | case TAG_STRING_EXT: 749 | var j = unpackUint16(i, data); 750 | i += 2; 751 | return [i + j, data.toString('binary', i, i + j)]; 752 | case TAG_LIST_EXT: 753 | var length = unpackUint32(i, data); 754 | i += 4; 755 | var result = Erlang._binary_to_term_sequence(i, length, data); 756 | i = result[0]; 757 | var tmp = result[1]; 758 | result = Erlang._binary_to_term(i, data); 759 | i = result[0]; 760 | var tail = result[1]; 761 | if (! (tail instanceof Erlang.OtpErlangList) || 762 | tail.value.length != 0) { 763 | tmp.push(tail); 764 | tmp = new Erlang.OtpErlangList(tmp, true); 765 | } 766 | else { 767 | tmp = new Erlang.OtpErlangList(tmp); 768 | } 769 | return [i, tmp]; 770 | case TAG_BINARY_EXT: 771 | var j = unpackUint32(i, data); 772 | i += 4; 773 | return [i + j, 774 | new Erlang.OtpErlangBinary(data.slice(i, i + j), 8)]; 775 | case TAG_SMALL_BIG_EXT: 776 | case TAG_LARGE_BIG_EXT: 777 | var j; 778 | if (tag == TAG_SMALL_BIG_EXT) { 779 | j = data[i]; 780 | i += 1; 781 | } 782 | else if (tag == TAG_LARGE_BIG_EXT) { 783 | j = unpackUint32(i, data); 784 | i += 4; 785 | } 786 | var sign = data[i]; 787 | var bignum = 0; 788 | for (var bignum_index = 0; bignum_index < j; bignum_index++) { 789 | bignum = bignum * 256 + data[i + j - bignum_index]; 790 | } 791 | if (sign == 1) { 792 | bignum *= -1; 793 | } 794 | i += 1; 795 | return [i + j, bignum]; 796 | case TAG_NEW_FUN_EXT: 797 | var length = unpackUint32(i, data); 798 | return [i + length, 799 | new Erlang.OtpErlangFunction(tag, 800 | data.slice(i, i + length))]; 801 | case TAG_EXPORT_EXT: 802 | var old_i = i; 803 | var result = Erlang._binary_to_atom(i, data); 804 | i = result[0]; 805 | var module = result[1]; 806 | result = Erlang._binary_to_atom(i, data); 807 | i = result[0]; 808 | var f = result[1]; 809 | if (data[i] != TAG_SMALL_INTEGER_EXT) { 810 | throw new ParseException('invalid small integer tag'); 811 | } 812 | i += 1; 813 | var arity = data[i]; 814 | i += 1; 815 | return [i, 816 | new Erlang.OtpErlangFunction(tag, data.slice(old_i, i))]; 817 | case TAG_NEWER_REFERENCE_EXT: 818 | case TAG_NEW_REFERENCE_EXT: 819 | var j = unpackUint16(i, data) * 4; 820 | i += 2; 821 | var result = Erlang._binary_to_atom(i, data); 822 | i = result[0]; 823 | var node = result[1]; 824 | var creation; 825 | if (tag == TAG_NEWER_REFERENCE_EXT) { 826 | creation = data.slice(i, i + 4); 827 | i += 4; 828 | } 829 | else if (tag == TAG_NEW_REFERENCE_EXT) { 830 | creation = data.slice(i, i + 1); 831 | i += 1; 832 | } 833 | return [i + j, 834 | new Erlang.OtpErlangReference(node, data.slice(i, i + j), 835 | creation)] 836 | case TAG_MAP_EXT: 837 | var length = unpackUint32(i, data); 838 | i += 4; 839 | var pairs = new Map(); 840 | for (var length_index = 0; length_index < length; length_index++) { 841 | var result = Erlang._binary_to_term(i, data); 842 | i = result[0]; 843 | var key = result[1]; 844 | result = Erlang._binary_to_term(i, data); 845 | i = result[0]; 846 | var value = result[1]; 847 | pairs.set(key, value); 848 | } 849 | return [i, new Erlang.OtpErlangMap(pairs)]; 850 | case TAG_FUN_EXT: 851 | var old_i = i; 852 | var numfree = unpackUint32(i, data); 853 | i += 4; 854 | var result = Erlang._binary_to_pid(i, data); 855 | i = result[0]; 856 | var pid = result[1]; 857 | var result = Erlang._binary_to_atom(i, data); 858 | i = result[0]; 859 | var module = result[1]; 860 | var result = Erlang._binary_to_integer(i, data); 861 | i = result[0]; 862 | var index = result[1]; 863 | var result = Erlang._binary_to_integer(i, data); 864 | i = result[0]; 865 | var uniq = result[1]; 866 | var result = Erlang._binary_to_term_sequence(i, numfree, data); 867 | i = result[0]; 868 | var free = result[1]; 869 | return [i, 870 | new Erlang.OtpErlangFunction(tag, data.slice(old_i, i))]; 871 | case TAG_ATOM_UTF8_EXT: 872 | case TAG_ATOM_EXT: 873 | var j = unpackUint16(i, data); 874 | i += 2; 875 | var atom_name = data.toString('binary', i, i + j); 876 | var tmp; 877 | if (atom_name == 'true') { 878 | tmp = true; 879 | } 880 | else if (atom_name == 'false') { 881 | tmp = false; 882 | } 883 | else if (atom_name == UNDEFINED) { 884 | tmp = null; 885 | } 886 | else { 887 | var utf8 = (tag == TAG_ATOM_UTF8_EXT); 888 | tmp = new Erlang.OtpErlangAtom(atom_name, utf8); 889 | } 890 | return [i + j, tmp]; 891 | case TAG_SMALL_ATOM_UTF8_EXT: 892 | case TAG_SMALL_ATOM_EXT: 893 | var j = data[i]; 894 | i += 1; 895 | var atom_name = data.toString('binary', i, i + j); 896 | var tmp; 897 | if (atom_name == 'true') { 898 | tmp = true; 899 | } 900 | else if (atom_name == 'false') { 901 | tmp = false; 902 | } 903 | else if (atom_name == UNDEFINED) { 904 | tmp = null; 905 | } 906 | else { 907 | var utf8 = (tag == TAG_SMALL_ATOM_UTF8_EXT); 908 | tmp = new Erlang.OtpErlangAtom(atom_name, utf8); 909 | } 910 | return [i + j, tmp]; 911 | case TAG_COMPRESSED_ZLIB: 912 | // never happens with Erlang output 913 | // (not handled here to avoid going to callback hell) 914 | throw new ParseException('nested compression unsupported'); 915 | case TAG_LOCAL_EXT: 916 | throw new ParseException('LOCAL_EXT is opaque'); 917 | default: 918 | throw new ParseException('invalid tag'); 919 | } 920 | }; 921 | 922 | Erlang._binary_to_term_sequence = function _binary_to_term_sequence 923 | (i, length, data) { 924 | var sequence = []; 925 | for (var length_index = 0; length_index < length; length_index++) { 926 | var result = Erlang._binary_to_term(i, data); 927 | i = result[0]; 928 | sequence.push(result[1]); 929 | } 930 | return [i, sequence]; 931 | }; 932 | 933 | // (binary_to_term Erlang term primitive type functions) 934 | 935 | Erlang._binary_to_integer = function _binary_to_integer (i, data) { 936 | var tag = data[i]; 937 | i += 1; 938 | switch (tag) { 939 | case TAG_SMALL_INTEGER_EXT: 940 | return [i + 1, data[i]]; 941 | case TAG_INTEGER_EXT: 942 | var value = unpackUint32(i, data); 943 | if (0 != (value & 0x80000000)) { 944 | value = -2147483648 + (value & 0x7fffffff); 945 | } 946 | return [i + 4, value]; 947 | default: 948 | throw new ParseException('invalid integer tag'); 949 | } 950 | }; 951 | 952 | Erlang._binary_to_pid = function _binary_to_pid (i, data) { 953 | var tag = data[i]; 954 | i += 1; 955 | switch (tag) { 956 | case TAG_NEW_PID_EXT: 957 | var result = Erlang._binary_to_atom(i, data); 958 | i = result[0]; 959 | var node = result[1]; 960 | var id = data.slice(i, i + 4); 961 | i += 4; 962 | var serial = data.slice(i, i + 4); 963 | i += 4; 964 | var creation = data.slice(i, i + 4); 965 | i += 4; 966 | return [i, new Erlang.OtpErlangPid(node, id, serial, creation)]; 967 | case TAG_PID_EXT: 968 | var result = Erlang._binary_to_atom(i, data); 969 | i = result[0]; 970 | var node = result[1]; 971 | var id = data.slice(i, i + 4); 972 | i += 4; 973 | var serial = data.slice(i, i + 4); 974 | i += 4; 975 | var creation = data.slice(i, i + 1); 976 | i += 1; 977 | return [i, new Erlang.OtpErlangPid(node, id, serial, creation)]; 978 | default: 979 | throw new ParseException('invalid pid tag'); 980 | } 981 | }; 982 | 983 | Erlang._binary_to_atom = function _binary_to_atom (i, data) { 984 | var tag = data[i]; 985 | i += 1; 986 | switch (tag) { 987 | case TAG_ATOM_EXT: 988 | var j = unpackUint16(i, data); 989 | i += 2; 990 | return [i + j, 991 | new Erlang.OtpErlangAtom(data.toString('binary', 992 | i, i + j), false)]; 993 | case TAG_ATOM_CACHE_REF: 994 | return [i + 1, new Erlang.OtpErlangAtom(data[i])]; 995 | case TAG_SMALL_ATOM_EXT: 996 | var j = data[i]; 997 | i += 1; 998 | return [i + j, 999 | new Erlang.OtpErlangAtom(data.toString('binary', 1000 | i, i + j), false)]; 1001 | case TAG_ATOM_UTF8_EXT: 1002 | var j = unpackUint16(i, data); 1003 | i += 2; 1004 | return [i + j, 1005 | new Erlang.OtpErlangAtom(data.toString('binary', 1006 | i, i + j))]; 1007 | case TAG_SMALL_ATOM_UTF8_EXT: 1008 | var j = data[i]; 1009 | i += 1; 1010 | return [i + j, 1011 | new Erlang.OtpErlangAtom(data.toString('binary', 1012 | i, i + j))]; 1013 | default: 1014 | throw new ParseException('invalid atom tag'); 1015 | } 1016 | }; 1017 | 1018 | // term_to_binary implementation functions 1019 | 1020 | Erlang._term_to_binary = function _term_to_binary (term) { 1021 | switch (typeof term) { 1022 | case 'string': 1023 | return Erlang._string_to_binary(term); 1024 | case 'number': 1025 | if (isFinite(term) && term % 1 === 0) { 1026 | return Erlang._integer_to_binary(term); 1027 | } 1028 | else { 1029 | return Erlang._float_to_binary(term); 1030 | } 1031 | case 'boolean': 1032 | if (term) { 1033 | term = new Erlang.OtpErlangAtom('true'); 1034 | } 1035 | else { 1036 | term = new Erlang.OtpErlangAtom('false'); 1037 | } 1038 | return term.binary(); 1039 | case 'object': 1040 | switch (toNativeString.call(term)) { 1041 | case '[object Null]': 1042 | term = new Erlang.OtpErlangAtom(UNDEFINED); 1043 | return term.binary(); 1044 | case '[object Array]': 1045 | return Erlang._tuple_to_binary(term); 1046 | case '[object Object]': 1047 | if (term instanceof Erlang.OtpErlangAtom || 1048 | term instanceof Erlang.OtpErlangAtomLarge || 1049 | term instanceof Erlang.OtpErlangBinary || 1050 | term instanceof Erlang.OtpErlangList || 1051 | term instanceof Erlang.OtpErlangMap || 1052 | term instanceof Erlang.OtpErlangPid || 1053 | term instanceof Erlang.OtpErlangPort || 1054 | term instanceof Erlang.OtpErlangReference || 1055 | term instanceof Erlang.OtpErlangFunction) { 1056 | return term.binary(); 1057 | } 1058 | else { 1059 | return Erlang._object_to_binary(term); 1060 | } 1061 | default: 1062 | throw new OutputException('unknown javascript object type'); 1063 | } 1064 | default: 1065 | throw new OutputException('unknown javascript type'); 1066 | } 1067 | }; 1068 | 1069 | // (term_to_binary Erlang term composite type functions) 1070 | 1071 | Erlang._string_to_binary = function _string_to_binary (term) { 1072 | var length = term.length; 1073 | if (length == 0) { 1074 | return new bufferFrom([TAG_NIL_EXT]); 1075 | } 1076 | else if (length <= 65535) { 1077 | var buffer = new bufferAlloc(3 + length); 1078 | buffer[0] = TAG_STRING_EXT; 1079 | packUint16(length, 1, buffer); 1080 | buffer.write(term, 3, length, 'binary'); 1081 | return buffer; 1082 | } 1083 | else if (length <= 4294967295) { 1084 | var buffer = new bufferAlloc(6 + 2 * length); 1085 | buffer[0] = TAG_LIST_EXT; 1086 | packUint32(length, 1, buffer); 1087 | for (var i = 0; i < length; i++) { 1088 | var j = 5 + 2 * i; 1089 | buffer[j] = TAG_SMALL_INTEGER_EXT; 1090 | buffer[j + 1] = term.charCodeAt(i); 1091 | } 1092 | buffer[5 + 2 * length] = TAG_NIL_EXT; 1093 | return buffer; 1094 | } 1095 | else { 1096 | throw new OutputException('uint32 overflow'); 1097 | } 1098 | }; 1099 | 1100 | Erlang._tuple_to_binary = function _tuple_to_binary (term) { 1101 | var length = term.length; 1102 | var header; 1103 | if (length <= 255) { 1104 | header = new bufferAlloc(2); 1105 | header[0] = TAG_SMALL_TUPLE_EXT; 1106 | header[1] = length; 1107 | } 1108 | else if (length <= 4294967295) { 1109 | header = new bufferAlloc(5); 1110 | header[0] = TAG_LARGE_TUPLE_EXT; 1111 | packUint32(length, 1, header); 1112 | } 1113 | else { 1114 | throw new OutputException('uint32 overflow'); 1115 | } 1116 | var buffers = [header]; 1117 | for (var i = 0; i < length; i++) { 1118 | buffers.push(Erlang._term_to_binary(term[i])); 1119 | } 1120 | return Buffer.concat(buffers); 1121 | }; 1122 | 1123 | Erlang._object_to_binary = function _object_to_binary (map) { 1124 | var length = 0; 1125 | var buffers = []; 1126 | switch (toNativeString.call(map)) { 1127 | case '[object Map]': 1128 | map.forEach(function (value, key) { 1129 | length++; 1130 | buffers.push(Erlang._term_to_binary(key)); 1131 | buffers.push(Erlang._term_to_binary(value)); 1132 | }); 1133 | break; 1134 | case '[object Object]': 1135 | for (var key in map) { 1136 | if (map.hasOwnProperty(key)) { 1137 | length++; 1138 | buffers.push(Erlang._term_to_binary(key)); 1139 | buffers.push(Erlang._term_to_binary(map[key])); 1140 | } 1141 | } 1142 | break; 1143 | default: 1144 | throw new OutputException('unknown map type'); 1145 | } 1146 | if (length <= 4294967295) { 1147 | var header = new bufferAlloc(5); 1148 | header[0] = TAG_MAP_EXT; 1149 | packUint32(length, 1, header); 1150 | buffers.unshift(header) 1151 | return Buffer.concat(buffers); 1152 | } 1153 | else { 1154 | throw new OutputException('uint32 overflow'); 1155 | } 1156 | }; 1157 | 1158 | // (term_to_binary Erlang term primitive type functions) 1159 | 1160 | Erlang._integer_to_binary = function _integer_to_binary (term) { 1161 | if (0 <= term && term <= 255) { 1162 | return new bufferFrom([TAG_SMALL_INTEGER_EXT, term]); 1163 | } 1164 | else if (-2147483648 <= term && term <= 2147483647) { 1165 | var buffer = new bufferAlloc(5); 1166 | buffer[0] = TAG_INTEGER_EXT; 1167 | packUint32(term, 1, buffer); 1168 | return buffer; 1169 | } 1170 | else { 1171 | return Erlang._bignum_to_binary(term); 1172 | } 1173 | }; 1174 | 1175 | Erlang._bignum_to_binary = function _bignum_to_binary (term) { 1176 | var bignum = Math.abs(term); 1177 | if (term < 0) { 1178 | sign = 1; 1179 | } 1180 | else { 1181 | sign = 0; 1182 | } 1183 | var buffers = []; 1184 | while (bignum > 0) { 1185 | var b = new bufferAlloc(1) 1186 | b[0] = bignum & 255; 1187 | buffers.push(b); 1188 | bignum >>>= 8; 1189 | } 1190 | var length = buffers.length; 1191 | if (length <= 255) { 1192 | var header = new bufferAlloc(3); 1193 | header[0] = TAG_SMALL_BIG_EXT; 1194 | header[1] = length; 1195 | header[2] = sign; 1196 | buffers.unshift(header); 1197 | return Buffer.concat(buffers); 1198 | } 1199 | else if (length <= 4294967295) { 1200 | var header = new bufferAlloc(6); 1201 | header[0] = TAG_LARGE_BIG_EXT; 1202 | packUint32(length, 1, header); 1203 | header[5] = sign; 1204 | buffers.unshift(header); 1205 | return Buffer.concat(buffers); 1206 | } 1207 | else { 1208 | throw new OutputException('uint32 overflow'); 1209 | } 1210 | }; 1211 | 1212 | Erlang._float_to_binary = function _float_to_binary (term) { 1213 | var buffer_in = new ArrayBuffer(8); 1214 | var value = new DataView(buffer_in); 1215 | value.setFloat64(0, term); 1216 | var view = new Uint8Array(buffer_in); 1217 | var buffer_out = new bufferAlloc(9); 1218 | buffer_out[0] = TAG_NEW_FLOAT_EXT; 1219 | for (var i = 0; i < 8; i++) { 1220 | buffer_out[1 + i] = view[i]; 1221 | } 1222 | return buffer_out; 1223 | }; 1224 | 1225 | // Elixir use can set to 'nil' 1226 | Erlang.set_undefined = function set_undefined (value) { 1227 | UNDEFINED = value; 1228 | }; 1229 | 1230 | // Exception objects listed alphabetically 1231 | 1232 | Erlang.InputException = InputException; 1233 | Erlang.OutputException = OutputException; 1234 | Erlang.ParseException = ParseException; 1235 | 1236 | }; 1237 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014-2023 Michael Truog 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a 6 | copy of this software and associated documentation files (the "Software"), 7 | to deal in the Software without restriction, including without limitation 8 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | and/or sell copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all 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 20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Erlang External Term Format for Javascript 2 | ========================================== 3 | 4 | [![Build Status](https://app.travis-ci.com/okeuday/erlang_js.svg?branch=master)](https://app.travis-ci.com/okeuday/erlang_js) 5 | [![npm Package Version](https://img.shields.io/npm/v/erlang_js.svg?maxAge=2592000)](https://www.npmjs.com/package/erlang_js) 6 | 7 | Provides all encoding and decoding for the Erlang External Term Format 8 | (as defined at [http://erlang.org/doc/apps/erts/erl_ext_dist.html](http://erlang.org/doc/apps/erts/erl_ext_dist.html)) 9 | in a single Javascript file. 10 | 11 | Available as a [npm package at `https://www.npmjs.org/package/erlang_js`](https://www.npmjs.org/package/erlang_js). 12 | 13 | Tests 14 | ----- 15 | 16 | npm test 17 | 18 | Author 19 | ------ 20 | 21 | Michael Truog (mjtruog at protonmail dot com) 22 | 23 | License 24 | ------- 25 | 26 | MIT License 27 | 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Michael Truog (https://github.com/okeuday)", 3 | "name": "erlang_js", 4 | "description": "Erlang External Term Format for Javascript", 5 | "version": "2.0.7", 6 | "homepage": "https://github.com/okeuday/erlang_js", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/okeuday/erlang_js.git" 10 | }, 11 | "license": "MIT", 12 | "keywords": [ 13 | "erlang" 14 | ], 15 | "main": "Erlang.js", 16 | "scripts": { 17 | "test": "node tests/ErlangTests.js" 18 | }, 19 | "dependencies": {}, 20 | "devDependencies": {}, 21 | "optionalDependencies": {}, 22 | "engines": { 23 | "node": "*" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/ErlangTests.js: -------------------------------------------------------------------------------- 1 | //-*-Mode:javascript;coding:utf-8;tab-width:4;c-basic-offset:4;indent-tabs-mode:()-*- 2 | // ex: set ft=javascript fenc=utf-8 sts=4 ts=4 sw=4 et nomod: 3 | // 4 | // MIT License 5 | // 6 | // Copyright (c) 2014-2023 Michael Truog 7 | // Copyright (c) 2009-2013 Dmitry Vasiliev 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a 10 | // copy of this software and associated documentation files (the "Software"), 11 | // to deal in the Software without restriction, including without limitation 12 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 | // and/or sell copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | // DEALINGS IN THE SOFTWARE. 26 | // 27 | 28 | var Erlang = require('./../Erlang.js').Erlang; 29 | var assert = require('assert'); 30 | 31 | // many of the test cases were adapted 32 | // from erlport (https://github.com/hdima/erlport) 33 | // to make the tests more exhaustive 34 | 35 | var toNativeString = {}.toString; 36 | var bufferFrom; 37 | if (Erlang.nodejs_version_after('5.10.0',true)) { 38 | bufferFrom = Buffer.from; 39 | } 40 | else { 41 | bufferFrom = Buffer; 42 | } 43 | String.prototype.repeat = function(i) { 44 | return new Array(i + 1).join(this); 45 | }; 46 | Array.prototype.fill = function(value) { 47 | for (var i = 0; i < this.length; i++) { 48 | this[i] = value; 49 | } 50 | return this; 51 | }; 52 | var hex = function hex(buffer) { 53 | var output = ''; 54 | for (var i = 0; i < buffer.length; i++) 55 | { 56 | var code = buffer[i]; 57 | if (code >= 32 && code <= 126) { 58 | output += String.fromCharCode(code); 59 | } 60 | else { 61 | var c = code.toString(16); 62 | if (c.length == 1) { 63 | c = '0' + c; 64 | } 65 | output += '\\x' + c; 66 | } 67 | } 68 | return output; 69 | }; 70 | 71 | (function AtomTestCase () { 72 | (function test_atom () { 73 | var atom1 = new Erlang.OtpErlangAtom('test'); 74 | assert.equal(toNativeString.call(atom1), '[object Object]'); 75 | assert.deepEqual(new Erlang.OtpErlangAtom('test'), atom1); 76 | assert.equal('OtpErlangAtom(test,true)', '' + atom1); 77 | assert.ok(atom1 instanceof Erlang.OtpErlangAtom); 78 | var atom2 = new Erlang.OtpErlangAtom('test2'); 79 | var atom1_new = new Erlang.OtpErlangAtom('test'); 80 | assert.notDeepEqual(atom1, atom2); 81 | assert.deepEqual(atom1, atom1_new); 82 | assert.notStrictEqual(atom1, atom1_new); 83 | assert.equal('X'.repeat(255), 84 | (new Erlang.OtpErlangAtom('X'.repeat(255))).value); 85 | assert.equal('X'.repeat(256), 86 | (new Erlang.OtpErlangAtom('X'.repeat(256))).value); 87 | }).call(this); 88 | (function test_atom () { 89 | assert.throws(function() { 90 | (new Erlang.OtpErlangAtom([1, 2])).binary(); 91 | }, Erlang.OutputException); 92 | }).call(this); 93 | }).call(this); 94 | 95 | (function ListTestCase () { 96 | (function test_list () { 97 | var lst = new Erlang.OtpErlangList([116, 101, 115, 116]); 98 | assert.ok(lst instanceof Erlang.OtpErlangList); 99 | assert.deepEqual(new Erlang.OtpErlangList([116, 101, 115, 116]), lst); 100 | assert.deepEqual([116, 101, 115, 116], lst.value); 101 | assert.equal('OtpErlangList([116,101,115,116],false)', lst.toString()); 102 | }).call(this); 103 | }).call(this); 104 | 105 | (function ImproperListTestCase () { 106 | (function test_improper_list () { 107 | var lst = new Erlang.OtpErlangList([1, 2, 3, 4], true); 108 | assert.ok(lst instanceof Erlang.OtpErlangList); 109 | assert.deepEqual([1, 2, 3, 4], lst.value); 110 | assert.equal(4, lst.value[lst.value.length - 1]); 111 | assert.equal('OtpErlangList([1,2,3,4],true)', lst.toString()); 112 | }).call(this); 113 | (function test_comparison () { 114 | var lst = new Erlang.OtpErlangList([1, 2, 3, 4], true); 115 | assert.deepEqual(lst, lst); 116 | assert.deepEqual(lst, new Erlang.OtpErlangList([1, 2, 3, 4], true)); 117 | assert.notDeepEqual(lst, new Erlang.OtpErlangList([1, 2, 3, 5], true)); 118 | assert.notDeepEqual(lst, new Erlang.OtpErlangList([1, 2, 3], true)); 119 | }).call(this); 120 | (function test_errors () { 121 | assert.throws(function() { 122 | (new Erlang.OtpErlangList('invalid')).binary(); 123 | }, Erlang.OutputException); 124 | }).call(this); 125 | }).call(this); 126 | 127 | (function DecodeTestCase () { 128 | (function test_binary_to_term () { 129 | Erlang.binary_to_term('', function(err, term) { 130 | assert.ok(err instanceof Erlang.ParseException); 131 | assert.strictEqual(term, undefined); 132 | }); 133 | Erlang.binary_to_term('\0', function(err, term) { 134 | assert.ok(err instanceof Erlang.ParseException); 135 | assert.strictEqual(term, undefined); 136 | }); 137 | Erlang.binary_to_term('\x83', function(err, term) { 138 | assert.ok(err instanceof Erlang.ParseException); 139 | assert.strictEqual(term, undefined); 140 | }); 141 | Erlang.binary_to_term('\x83z', function(err, term) { 142 | assert.ok(err instanceof Erlang.ParseException); 143 | assert.strictEqual(term, undefined); 144 | }); 145 | }).call(this); 146 | (function test_binary_to_term_atom () { 147 | Erlang.binary_to_term('\x83d', function(err, term) { 148 | assert.ok(err instanceof Erlang.ParseException); 149 | assert.strictEqual(term, undefined); 150 | }); 151 | Erlang.binary_to_term('\x83d\0', function(err, term) { 152 | assert.ok(err instanceof Erlang.ParseException); 153 | assert.strictEqual(term, undefined); 154 | }); 155 | Erlang.binary_to_term('\x83d\0\1', function(err, term) { 156 | assert.ok(err instanceof Erlang.ParseException); 157 | assert.strictEqual(term, undefined); 158 | }); 159 | Erlang.binary_to_term('\x83v\0\0', function(err, term) { 160 | assert.strictEqual(err, undefined); 161 | assert.deepEqual(term, new Erlang.OtpErlangAtom('')); 162 | }); 163 | Erlang.binary_to_term('\x83d\0\0', function(err, term) { 164 | assert.strictEqual(err, undefined); 165 | assert.deepEqual(term, new Erlang.OtpErlangAtom('', false)); 166 | }); 167 | Erlang.binary_to_term('\x83w\0', function(err, term) { 168 | assert.strictEqual(err, undefined); 169 | assert.deepEqual(term, new Erlang.OtpErlangAtom('')); 170 | }); 171 | Erlang.binary_to_term('\x83s\0', function(err, term) { 172 | assert.strictEqual(err, undefined); 173 | assert.deepEqual(term, new Erlang.OtpErlangAtom('', false)); 174 | }); 175 | Erlang.binary_to_term('\x83v\0\4test', function(err, term) { 176 | assert.strictEqual(err, undefined); 177 | assert.deepEqual(term, new Erlang.OtpErlangAtom('test')); 178 | }); 179 | Erlang.binary_to_term('\x83d\0\4test', function(err, term) { 180 | assert.strictEqual(err, undefined); 181 | assert.deepEqual(term, new Erlang.OtpErlangAtom('test', false)); 182 | }); 183 | Erlang.binary_to_term('\x83w\4test', function(err, term) { 184 | assert.strictEqual(err, undefined); 185 | assert.deepEqual(term, new Erlang.OtpErlangAtom('test')); 186 | }); 187 | Erlang.binary_to_term('\x83s\4test', function(err, term) { 188 | assert.strictEqual(err, undefined); 189 | assert.deepEqual(term, new Erlang.OtpErlangAtom('test', false)); 190 | }); 191 | }).call(this); 192 | (function test_binary_to_term_predefined_atom () { 193 | Erlang.binary_to_term('\x83w\4true', function(err, term) { 194 | assert.strictEqual(err, undefined); 195 | assert.strictEqual(term, true); 196 | }); 197 | Erlang.binary_to_term('\x83w\5false', function(err, term) { 198 | assert.strictEqual(err, undefined); 199 | assert.strictEqual(term, false); 200 | }); 201 | Erlang.binary_to_term('\x83v\0\11undefined', function(err, term) { 202 | assert.strictEqual(err, undefined); 203 | assert.deepEqual(term, null); 204 | }); 205 | }).call(this); 206 | (function test_binary_to_term_empty_list () { 207 | Erlang.binary_to_term('\x83j', function(err, term) { 208 | assert.strictEqual(err, undefined); 209 | assert.deepEqual(term, new Erlang.OtpErlangList([])); 210 | }); 211 | }).call(this); 212 | (function test_binary_to_term_string_list () { 213 | Erlang.binary_to_term('\x83k', function(err, term) { 214 | assert.ok(err instanceof Erlang.ParseException); 215 | assert.strictEqual(term, undefined); 216 | }); 217 | Erlang.binary_to_term('\x83k\0', function(err, term) { 218 | assert.ok(err instanceof Erlang.ParseException); 219 | assert.strictEqual(term, undefined); 220 | }); 221 | Erlang.binary_to_term('\x83k\0\1', function(err, term) { 222 | assert.ok(err instanceof Erlang.ParseException); 223 | assert.strictEqual(term, undefined); 224 | }); 225 | Erlang.binary_to_term('\x83k\0\0', function(err, term) { 226 | assert.strictEqual(err, undefined); 227 | assert.equal(term, ''); 228 | }); 229 | Erlang.binary_to_term('\x83k\0\4test', function(err, term) { 230 | assert.strictEqual(err, undefined); 231 | assert.equal(term, 'test'); 232 | }); 233 | }).call(this); 234 | (function test_binary_to_term_list () { 235 | Erlang.binary_to_term('\x83l', function(err, term) { 236 | assert.ok(err instanceof Erlang.ParseException); 237 | assert.strictEqual(term, undefined); 238 | }); 239 | Erlang.binary_to_term('\x83l\0', function(err, term) { 240 | assert.ok(err instanceof Erlang.ParseException); 241 | assert.strictEqual(term, undefined); 242 | }); 243 | Erlang.binary_to_term('\x83l\0\0', function(err, term) { 244 | assert.ok(err instanceof Erlang.ParseException); 245 | assert.strictEqual(term, undefined); 246 | }); 247 | Erlang.binary_to_term('\x83l\0\0\0', function(err, term) { 248 | assert.ok(err instanceof Erlang.ParseException); 249 | assert.strictEqual(term, undefined); 250 | }); 251 | Erlang.binary_to_term('\x83l\0\0\0\0', function(err, term) { 252 | assert.ok(err instanceof Erlang.ParseException); 253 | assert.strictEqual(term, undefined); 254 | }); 255 | Erlang.binary_to_term('\x83l\0\0\0\0j', function(err, term) { 256 | assert.strictEqual(err, undefined); 257 | assert.deepEqual(term, new Erlang.OtpErlangList([])); 258 | }); 259 | Erlang.binary_to_term('\x83l\0\0\0\2jjj', function(err, term) { 260 | assert.strictEqual(err, undefined); 261 | assert.deepEqual(term, new Erlang.OtpErlangList([ 262 | new Erlang.OtpErlangList([]), 263 | new Erlang.OtpErlangList([])])); 264 | }); 265 | }).call(this); 266 | (function test_binary_to_term_improper_list () { 267 | Erlang.binary_to_term('\x83l\0\0\0\0k', function(err, term) { 268 | assert.ok(err instanceof Erlang.ParseException); 269 | assert.strictEqual(term, undefined); 270 | }); 271 | Erlang.binary_to_term('\x83l\0\0\0\1jv\0\4tail', function(err, lst) { 272 | assert.strictEqual(err, undefined); 273 | assert.ok(lst instanceof Erlang.OtpErlangList); 274 | assert.deepEqual([new Erlang.OtpErlangList([]), 275 | new Erlang.OtpErlangAtom('tail')], lst.value); 276 | assert.equal(true, lst.improper); 277 | }); 278 | }).call(this); 279 | (function test_binary_to_term_small_tuple () { 280 | Erlang.binary_to_term('\x83h', function(err, term) { 281 | assert.ok(err instanceof Erlang.ParseException); 282 | assert.strictEqual(term, undefined); 283 | }); 284 | Erlang.binary_to_term('\x83h\1', function(err, term) { 285 | assert.ok(err instanceof Erlang.ParseException); 286 | assert.strictEqual(term, undefined); 287 | }); 288 | Erlang.binary_to_term('\x83h\0', function(err, term) { 289 | assert.strictEqual(err, undefined); 290 | assert.deepEqual(term, []); 291 | }); 292 | Erlang.binary_to_term('\x83h\2jj', function(err, term) { 293 | assert.strictEqual(err, undefined); 294 | assert.deepEqual(term, [new Erlang.OtpErlangList([]), 295 | new Erlang.OtpErlangList([])]); 296 | }); 297 | }).call(this); 298 | (function test_binary_to_term_large_tuple () { 299 | Erlang.binary_to_term('\x83i', function(err, term) { 300 | assert.ok(err instanceof Erlang.ParseException); 301 | assert.strictEqual(term, undefined); 302 | }); 303 | Erlang.binary_to_term('\x83i\0', function(err, term) { 304 | assert.ok(err instanceof Erlang.ParseException); 305 | assert.strictEqual(term, undefined); 306 | }); 307 | Erlang.binary_to_term('\x83i\0\0', function(err, term) { 308 | assert.ok(err instanceof Erlang.ParseException); 309 | assert.strictEqual(term, undefined); 310 | }); 311 | Erlang.binary_to_term('\x83i\0\0\0', function(err, term) { 312 | assert.ok(err instanceof Erlang.ParseException); 313 | assert.strictEqual(term, undefined); 314 | }); 315 | Erlang.binary_to_term('\x83i\0\0\0\1', function(err, term) { 316 | assert.ok(err instanceof Erlang.ParseException); 317 | assert.strictEqual(term, undefined); 318 | }); 319 | Erlang.binary_to_term('\x83i\0\0\0\0', function(err, term) { 320 | assert.strictEqual(err, undefined); 321 | assert.deepEqual(term, []); 322 | }); 323 | Erlang.binary_to_term('\x83i\0\0\0\2jj', function(err, term) { 324 | assert.strictEqual(err, undefined); 325 | assert.deepEqual(term, [new Erlang.OtpErlangList([]), 326 | new Erlang.OtpErlangList([])]); 327 | }); 328 | }).call(this); 329 | (function test_binary_to_term_small_integer () { 330 | Erlang.binary_to_term('\x83a', function(err, term) { 331 | assert.ok(err instanceof Erlang.ParseException); 332 | assert.strictEqual(term, undefined); 333 | }); 334 | Erlang.binary_to_term('\x83a\0', function(err, term) { 335 | assert.strictEqual(err, undefined); 336 | assert.deepEqual(term, 0); 337 | }); 338 | Erlang.binary_to_term('\x83a\xff', function(err, term) { 339 | assert.strictEqual(err, undefined); 340 | assert.deepEqual(term, 255); 341 | }); 342 | }).call(this); 343 | (function test_binary_to_term_integer () { 344 | Erlang.binary_to_term('\x83b', function(err, term) { 345 | assert.ok(err instanceof Erlang.ParseException); 346 | assert.strictEqual(term, undefined); 347 | }); 348 | Erlang.binary_to_term('\x83b\0', function(err, term) { 349 | assert.ok(err instanceof Erlang.ParseException); 350 | assert.strictEqual(term, undefined); 351 | }); 352 | Erlang.binary_to_term('\x83b\0\0', function(err, term) { 353 | assert.ok(err instanceof Erlang.ParseException); 354 | assert.strictEqual(term, undefined); 355 | }); 356 | Erlang.binary_to_term('\x83b\0\0\0', function(err, term) { 357 | assert.ok(err instanceof Erlang.ParseException); 358 | assert.strictEqual(term, undefined); 359 | }); 360 | Erlang.binary_to_term('\x83b\0\0\0\0', function(err, term) { 361 | assert.strictEqual(err, undefined); 362 | assert.equal(term, 0); 363 | }); 364 | Erlang.binary_to_term('\x83b\x7f\xff\xff\xff', function(err, term) { 365 | assert.strictEqual(err, undefined); 366 | assert.equal(term, 2147483647); 367 | }); 368 | Erlang.binary_to_term('\x83b\x80\0\0\0', function(err, term) { 369 | assert.strictEqual(err, undefined); 370 | assert.equal(term, -2147483648); 371 | }); 372 | Erlang.binary_to_term('\x83b\xff\xff\xff\xff', function(err, term) { 373 | assert.strictEqual(err, undefined); 374 | assert.equal(term, -1); 375 | }); 376 | }).call(this); 377 | (function test_binary_to_term_binary () { 378 | Erlang.binary_to_term('\x83m', function(err, term) { 379 | assert.ok(err instanceof Erlang.ParseException); 380 | assert.strictEqual(term, undefined); 381 | }); 382 | Erlang.binary_to_term('\x83m\0', function(err, term) { 383 | assert.ok(err instanceof Erlang.ParseException); 384 | assert.strictEqual(term, undefined); 385 | }); 386 | Erlang.binary_to_term('\x83m\0\0', function(err, term) { 387 | assert.ok(err instanceof Erlang.ParseException); 388 | assert.strictEqual(term, undefined); 389 | }); 390 | Erlang.binary_to_term('\x83m\0\0\0', function(err, term) { 391 | assert.ok(err instanceof Erlang.ParseException); 392 | assert.strictEqual(term, undefined); 393 | }); 394 | Erlang.binary_to_term('\x83m\0\0\0\1', function(err, term) { 395 | assert.ok(err instanceof Erlang.ParseException); 396 | assert.strictEqual(term, undefined); 397 | }); 398 | Erlang.binary_to_term('\x83m\0\0\0\0', function(err, term) { 399 | assert.strictEqual(err, undefined); 400 | assert.deepEqual(term, new Erlang.OtpErlangBinary( 401 | new bufferFrom([]))); 402 | }); 403 | Erlang.binary_to_term('\x83m\0\0\0\4data', function(err, term) { 404 | assert.strictEqual(err, undefined); 405 | assert.deepEqual(term, new Erlang.OtpErlangBinary( 406 | new bufferFrom('data', 'binary'))); 407 | }); 408 | }).call(this); 409 | (function test_binary_to_term_float () { 410 | Erlang.binary_to_term('\x83F', function(err, term) { 411 | assert.ok(err instanceof Erlang.ParseException); 412 | assert.strictEqual(term, undefined); 413 | }); 414 | Erlang.binary_to_term('\x83F\0', function(err, term) { 415 | assert.ok(err instanceof Erlang.ParseException); 416 | assert.strictEqual(term, undefined); 417 | }); 418 | Erlang.binary_to_term('\x83F\0', function(err, term) { 419 | assert.ok(err instanceof Erlang.ParseException); 420 | assert.strictEqual(term, undefined); 421 | }); 422 | Erlang.binary_to_term('\x83F\0\0', function(err, term) { 423 | assert.ok(err instanceof Erlang.ParseException); 424 | assert.strictEqual(term, undefined); 425 | }); 426 | Erlang.binary_to_term('\x83F\0\0\0', function(err, term) { 427 | assert.ok(err instanceof Erlang.ParseException); 428 | assert.strictEqual(term, undefined); 429 | }); 430 | Erlang.binary_to_term('\x83F\0\0\0\0', function(err, term) { 431 | assert.ok(err instanceof Erlang.ParseException); 432 | assert.strictEqual(term, undefined); 433 | }); 434 | Erlang.binary_to_term('\x83F\0\0\0\0\0', function(err, term) { 435 | assert.ok(err instanceof Erlang.ParseException); 436 | assert.strictEqual(term, undefined); 437 | }); 438 | Erlang.binary_to_term('\x83F\0\0\0\0\0\0', function(err, term) { 439 | assert.ok(err instanceof Erlang.ParseException); 440 | assert.strictEqual(term, undefined); 441 | }); 442 | Erlang.binary_to_term('\x83F\0\0\0\0\0\0\0', function(err, term) { 443 | assert.ok(err instanceof Erlang.ParseException); 444 | assert.strictEqual(term, undefined); 445 | }); 446 | Erlang.binary_to_term('\x83F\0\0\0\0\0\0\0\0', function(err, term) { 447 | assert.strictEqual(err, undefined); 448 | assert.equal(term, 0.0); 449 | }); 450 | Erlang.binary_to_term('\x83F?\xf8\0\0\0\0\0\0', function(err, term) { 451 | assert.strictEqual(err, undefined); 452 | assert.equal(term, 1.5); 453 | }); 454 | }).call(this); 455 | (function test_binary_to_term_small_big_integer () { 456 | Erlang.binary_to_term('\x83n', function(err, term) { 457 | assert.ok(err instanceof Erlang.ParseException); 458 | assert.strictEqual(term, undefined); 459 | }); 460 | Erlang.binary_to_term('\x83n\0', function(err, term) { 461 | assert.ok(err instanceof Erlang.ParseException); 462 | assert.strictEqual(term, undefined); 463 | }); 464 | Erlang.binary_to_term('\x83n\1\0', function(err, term) { 465 | assert.ok(err instanceof Erlang.ParseException); 466 | assert.strictEqual(term, undefined); 467 | }); 468 | Erlang.binary_to_term('\x83n\0\0', function(err, term) { 469 | assert.strictEqual(err, undefined); 470 | assert.equal(term, 0); 471 | }); 472 | Erlang.binary_to_term('\x83n\6\0\1\2\3\4\5\6', function(err, term) { 473 | assert.strictEqual(err, undefined); 474 | assert.equal(term, 6618611909121); 475 | }); 476 | Erlang.binary_to_term('\x83n\6\1\1\2\3\4\5\6', function(err, term) { 477 | assert.strictEqual(err, undefined); 478 | assert.equal(term, -6618611909121); 479 | }); 480 | }).call(this); 481 | (function test_binary_to_term_big_integer () { 482 | Erlang.binary_to_term('\x83o', function(err, term) { 483 | assert.ok(err instanceof Erlang.ParseException); 484 | assert.strictEqual(term, undefined); 485 | }); 486 | Erlang.binary_to_term('\x83o\0', function(err, term) { 487 | assert.ok(err instanceof Erlang.ParseException); 488 | assert.strictEqual(term, undefined); 489 | }); 490 | Erlang.binary_to_term('\x83o\0\0', function(err, term) { 491 | assert.ok(err instanceof Erlang.ParseException); 492 | assert.strictEqual(term, undefined); 493 | }); 494 | Erlang.binary_to_term('\x83o\0\0\0', function(err, term) { 495 | assert.ok(err instanceof Erlang.ParseException); 496 | assert.strictEqual(term, undefined); 497 | }); 498 | Erlang.binary_to_term('\x83o\0\0\0\0', function(err, term) { 499 | assert.ok(err instanceof Erlang.ParseException); 500 | assert.strictEqual(term, undefined); 501 | }); 502 | Erlang.binary_to_term('\x83o\0\0\0\1\0', function(err, term) { 503 | assert.ok(err instanceof Erlang.ParseException); 504 | assert.strictEqual(term, undefined); 505 | }); 506 | Erlang.binary_to_term('\x83o\0\0\0\0\0', function(err, term) { 507 | assert.strictEqual(err, undefined); 508 | assert.equal(term, 0); 509 | }); 510 | Erlang.binary_to_term('\x83o\0\0\0\6\0\1\2\3\4\5\6', 511 | function(err, term) { 512 | assert.strictEqual(err, undefined); 513 | assert.equal(term, 6618611909121); 514 | }); 515 | Erlang.binary_to_term('\x83o\0\0\0\6\1\1\2\3\4\5\6', 516 | function(err, term) { 517 | assert.strictEqual(err, undefined); 518 | assert.equal(term, -6618611909121); 519 | }); 520 | }).call(this); 521 | (function test_binary_to_term_map () { 522 | Erlang.binary_to_term('\x83t', function(err, term) { 523 | assert.ok(err instanceof Erlang.ParseException); 524 | assert.strictEqual(term, undefined); 525 | }); 526 | Erlang.binary_to_term('\x83t\x00', function(err, term) { 527 | assert.ok(err instanceof Erlang.ParseException); 528 | assert.strictEqual(term, undefined); 529 | }); 530 | Erlang.binary_to_term('\x83t\x00\x00', function(err, term) { 531 | assert.ok(err instanceof Erlang.ParseException); 532 | assert.strictEqual(term, undefined); 533 | }); 534 | Erlang.binary_to_term('\x83t\x00\x00\x00', function(err, term) { 535 | assert.ok(err instanceof Erlang.ParseException); 536 | assert.strictEqual(term, undefined); 537 | }); 538 | Erlang.binary_to_term('\x83t\x00\x00\x00\x01', function(err, term) { 539 | assert.ok(err instanceof Erlang.ParseException); 540 | assert.strictEqual(term, undefined); 541 | }); 542 | Erlang.binary_to_term('\x83t\x00\x00\x00\x00', function(err, term) { 543 | assert.strictEqual(err, undefined); 544 | assert.ok(term instanceof Erlang.OtpErlangMap); 545 | assert.equal(term.value.size, 0); 546 | }); 547 | Erlang.binary_to_term('\x83t\x00\x00\x00\x01s\x01aa\x01', 548 | function(err, term) { 549 | assert.strictEqual(err, undefined); 550 | assert.ok(term instanceof Erlang.OtpErlangMap); 551 | assert.equal(term.value.size, 1); 552 | var keys = term.value.keys(); 553 | var key0 = keys.next().value; 554 | assert.deepEqual(key0, new Erlang.OtpErlangAtom('a', false)); 555 | assert.equal(term.value.get(key0), 1); 556 | }); 557 | Erlang.binary_to_term( 558 | '\x83\x74\x00\x00\x00\x02\x77\x09\x75\x6E\x64\x65\x66\x69' + 559 | '\x6E\x65\x64\x6D\x00\x00\x00\x07\x6E\x6F\x74\x68\x69\x6E' + 560 | '\x67\x4D\x00\x00\x00\x01\x06\xA8\x6D\x00\x00\x00\x0A\x65' + 561 | '\x76\x65\x72\x79\x74\x68\x69\x6E\x67', 562 | function(err, term) { 563 | assert.strictEqual(err, undefined); 564 | assert.ok(term instanceof Erlang.OtpErlangMap); 565 | assert.equal(term.value.size, 2); 566 | var keys = term.value.keys(); 567 | var key0 = keys.next().value; 568 | assert.equal(key0, null); 569 | var key1 = keys.next().value; 570 | assert.deepEqual(key1, new Erlang.OtpErlangBinary( 571 | new bufferFrom('\xA8', 'binary'), 6)); 572 | var value0 = term.value.get(key0); 573 | assert.deepEqual(value0, new Erlang.OtpErlangBinary( 574 | new bufferFrom('nothing', 'binary'))); 575 | var value1 = term.value.get(key1); 576 | assert.deepEqual(value1, new Erlang.OtpErlangBinary( 577 | new bufferFrom('everything', 'binary'))); 578 | }); 579 | }).call(this); 580 | (function test_binary_to_term_pid () { 581 | var pid_old_binary = ( 582 | '\x83\x67\x64\x00\x0D\x6E\x6F\x6E\x6F\x64\x65\x40\x6E\x6F' + 583 | '\x68\x6F\x73\x74\x00\x00\x00\x4E\x00\x00\x00\x00\x00' 584 | ); 585 | Erlang.binary_to_term(pid_old_binary, 586 | function(err, term) { 587 | assert.strictEqual(err, undefined); 588 | assert.ok(term instanceof Erlang.OtpErlangPid); 589 | Erlang.term_to_binary(term, 590 | function(err, binary) { 591 | assert.strictEqual(err, undefined); 592 | assert.equal(binary.toString('binary'), 593 | '\x83gs\rnonode@nohost\x00\x00\x00N' + 594 | '\x00\x00\x00\x00\x00'); 595 | }); 596 | }); 597 | var pid_new_binary = ( 598 | '\x83\x58\x64\x00\x0D\x6E\x6F\x6E\x6F\x64\x65\x40\x6E\x6F\x68' + 599 | '\x6F\x73\x74\x00\x00\x00\x4E\x00\x00\x00\x00\x00\x00\x00\x00' 600 | ); 601 | Erlang.binary_to_term(pid_new_binary, 602 | function(err, term) { 603 | assert.strictEqual(err, undefined); 604 | assert.ok(term instanceof Erlang.OtpErlangPid); 605 | Erlang.term_to_binary(term, 606 | function(err, binary) { 607 | assert.strictEqual(err, undefined); 608 | assert.equal(binary.toString('binary'), 609 | '\x83Xs\rnonode@nohost\x00\x00\x00N' + 610 | '\x00\x00\x00\x00\x00\x00\x00\x00'); 611 | }); 612 | }); 613 | }).call(this); 614 | (function test_binary_to_term_port () { 615 | var port_old_binary = ( 616 | '\x83\x66\x64\x00\x0D\x6E\x6F\x6E\x6F\x64\x65\x40\x6E\x6F\x68' + 617 | '\x6F\x73\x74\x00\x00\x00\x06\x00' 618 | ); 619 | Erlang.binary_to_term(port_old_binary, 620 | function(err, term) { 621 | assert.strictEqual(err, undefined); 622 | assert.ok(term instanceof Erlang.OtpErlangPort); 623 | Erlang.term_to_binary(term, 624 | function(err, binary) { 625 | assert.strictEqual(err, undefined); 626 | assert.equal(binary.toString('binary'), 627 | '\x83fs\rnonode@nohost\x00\x00\x00\x06\x00'); 628 | }); 629 | }); 630 | var port_new_binary = ( 631 | '\x83\x59\x64\x00\x0D\x6E\x6F\x6E\x6F\x64\x65\x40\x6E\x6F\x68' + 632 | '\x6F\x73\x74\x00\x00\x00\x06\x00\x00\x00\x00' 633 | ); 634 | Erlang.binary_to_term(port_new_binary, 635 | function(err, term) { 636 | assert.strictEqual(err, undefined); 637 | assert.ok(term instanceof Erlang.OtpErlangPort); 638 | Erlang.term_to_binary(term, 639 | function(err, binary) { 640 | assert.strictEqual(err, undefined); 641 | assert.equal(binary.toString('binary'), 642 | '\x83Ys\rnonode@nohost\x00\x00\x00\x06' + 643 | '\x00\x00\x00\x00'); 644 | }); 645 | }); 646 | var port_v4_binary = ( 647 | "\x83\x78\x77\x0D\x6E\x6F\x6E\x6F\x64\x65\x40\x6E\x6F\x68\x6F" + 648 | "\x73\x74\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00" 649 | ); 650 | Erlang.binary_to_term(port_v4_binary, 651 | function(err, term) { 652 | assert.strictEqual(err, undefined); 653 | assert.ok(term instanceof Erlang.OtpErlangPort); 654 | Erlang.term_to_binary(term, 655 | function(err, binary) { 656 | assert.strictEqual(err, undefined); 657 | assert.equal(binary.toString('binary'), port_v4_binary); 658 | }); 659 | }); 660 | }).call(this); 661 | (function test_binary_to_term_ref () { 662 | var ref_new_binary = ( 663 | '\x83\x72\x00\x03\x64\x00\x0D\x6E\x6F\x6E\x6F\x64\x65\x40\x6E' + 664 | '\x6F\x68\x6F\x73\x74\x00\x00\x03\xE8\x4E\xE7\x68\x00\x02\xA4' + 665 | '\xC8\x53\x40' 666 | ); 667 | Erlang.binary_to_term(ref_new_binary, 668 | function(err, term) { 669 | assert.strictEqual(err, undefined); 670 | assert.ok(term instanceof Erlang.OtpErlangReference); 671 | Erlang.term_to_binary(term, 672 | function(err, binary) { 673 | assert.strictEqual(err, undefined); 674 | assert.equal(binary.toString('binary'), 675 | '\x83r\x00\x03s\rnonode@nohost\x00\x00\x03\xe8' + 676 | 'N\xe7h\x00\x02\xa4\xc8S@'); 677 | }); 678 | }); 679 | var ref_newer_binary = ( 680 | '\x83\x5A\x00\x03\x64\x00\x0D\x6E\x6F\x6E\x6F\x64\x65\x40\x6E' + 681 | '\x6F\x68\x6F\x73\x74\x00\x00\x00\x00\x00\x01\xAC\x03\xC7\x00' + 682 | '\x00\x04\xBB\xB2\xCA\xEE' 683 | ); 684 | Erlang.binary_to_term(ref_newer_binary, 685 | function(err, term) { 686 | assert.strictEqual(err, undefined); 687 | assert.ok(term instanceof Erlang.OtpErlangReference); 688 | Erlang.term_to_binary(term, 689 | function(err, binary) { 690 | assert.strictEqual(err, undefined); 691 | assert.equal(binary.toString('binary'), 692 | '\x83Z\x00\x03s\rnonode@nohost\x00\x00\x00\x00\x00' + 693 | '\x01\xac\x03\xc7\x00\x00\x04\xbb\xb2\xca\xee'); 694 | }); 695 | }); 696 | }).call(this); 697 | (function test_binary_to_term_compressed_term () { 698 | Erlang.binary_to_term('\x83P', function(err, term) { 699 | assert.ok(err instanceof Erlang.ParseException); 700 | assert.strictEqual(term, undefined); 701 | }); 702 | Erlang.binary_to_term('\x83P\0', function(err, term) { 703 | assert.ok(err instanceof Erlang.ParseException); 704 | assert.strictEqual(term, undefined); 705 | }); 706 | Erlang.binary_to_term('\x83P\0\0', function(err, term) { 707 | assert.ok(err instanceof Erlang.ParseException); 708 | assert.strictEqual(term, undefined); 709 | }); 710 | Erlang.binary_to_term('\x83P\0\0\0', function(err, term) { 711 | assert.ok(err instanceof Erlang.ParseException); 712 | assert.strictEqual(term, undefined); 713 | }); 714 | Erlang.binary_to_term('\x83P\0\0\0\0', function(err, term) { 715 | assert.ok(err instanceof Erlang.ParseException); 716 | assert.strictEqual(term, undefined); 717 | }); 718 | Erlang.binary_to_term( 719 | '\x83P\0\0\0\x16\x78\xda\xcb\x66\x10\x49\xc1\2\0\x5d\x60\x08\x50', 720 | function(err, term) { 721 | assert.ok(err instanceof Erlang.ParseException); 722 | assert.strictEqual(term, undefined); 723 | } 724 | ); 725 | Erlang.binary_to_term( 726 | '\x83P\0\0\0\x17\x78\xda\xcb\x66\x10\x49\xc1\2\0\x5d\x60\x08\x50', 727 | function(err, term) { 728 | assert.strictEqual(err, undefined); 729 | assert.equal(term, 'd'.repeat(20)); 730 | } 731 | ); 732 | }).call(this); 733 | }).call(this); 734 | 735 | (function EncodeTestCase () { 736 | (function test_term_to_binary_tuple () { 737 | Erlang.term_to_binary([], function(err, binary) { 738 | assert.strictEqual(err, undefined); 739 | assert.equal(binary.toString('binary'), '\x83h\0'); 740 | }); 741 | Erlang.term_to_binary([[], []], function(err, binary) { 742 | assert.strictEqual(err, undefined); 743 | assert.equal(binary.toString('binary'), '\x83h\2h\0h\0'); 744 | }); 745 | Erlang.term_to_binary(new Array(255).fill([]), function(err, binary) { 746 | assert.strictEqual(err, undefined); 747 | assert.equal(binary.toString('binary'), 748 | '\x83h\xff' + 'h\0'.repeat(255)); 749 | }); 750 | Erlang.term_to_binary(new Array(256).fill([]), function(err, binary) { 751 | assert.strictEqual(err, undefined); 752 | assert.equal(binary.toString('binary'), 753 | '\x83i\0\0\1\0' + 'h\0'.repeat(256)); 754 | }); 755 | }).call(this); 756 | (function test_term_to_binary_empty_list () { 757 | Erlang.term_to_binary(new Erlang.OtpErlangList([]), 758 | function(err, binary) { 759 | assert.strictEqual(err, undefined); 760 | assert.equal(binary.toString('binary'), '\x83j'); 761 | }); 762 | }).call(this); 763 | (function test_term_to_binary_string_list () { 764 | Erlang.term_to_binary('', function(err, binary) { 765 | assert.strictEqual(err, undefined); 766 | assert.equal(binary.toString('binary'), '\x83j'); 767 | }); 768 | Erlang.term_to_binary('\0', function(err, binary) { 769 | assert.strictEqual(err, undefined); 770 | assert.equal(binary.toString('binary'), '\x83k\0\1\0'); 771 | }); 772 | var s = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r' + 773 | '\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a' + 774 | '\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>' + 775 | '?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopq' + 776 | 'rstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88' + 777 | '\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95' + 778 | '\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2' + 779 | '\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf' + 780 | '\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc' + 781 | '\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9' + 782 | '\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6' + 783 | '\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3' + 784 | '\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0' + 785 | '\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'; 786 | Erlang.term_to_binary(s, function(err, binary) { 787 | assert.strictEqual(err, undefined); 788 | assert.equal(binary.toString('binary'), '\x83k\1\0' + s); 789 | }); 790 | }).call(this); 791 | (function test_term_to_binary_list_basic () { 792 | Erlang.term_to_binary(new Erlang.OtpErlangList([]), 793 | function(err, binary) { 794 | assert.strictEqual(err, undefined); 795 | assert.equal(binary.toString('binary'), '\x83\x6A'); 796 | }); 797 | Erlang.term_to_binary(new Erlang.OtpErlangList(['']), 798 | function(err, binary) { 799 | assert.strictEqual(err, undefined); 800 | assert.equal(binary.toString('binary'), 801 | '\x83\x6C\x00\x00\x00\x01\x6A\x6A'); 802 | }); 803 | Erlang.term_to_binary(new Erlang.OtpErlangList([1]), 804 | function(err, binary) { 805 | assert.strictEqual(err, undefined); 806 | assert.equal(binary.toString('binary'), 807 | '\x83\x6C\x00\x00\x00\x01\x61\x01\x6A'); 808 | }); 809 | Erlang.term_to_binary(new Erlang.OtpErlangList([255]), 810 | function(err, binary) { 811 | assert.strictEqual(err, undefined); 812 | assert.equal(binary.toString('binary'), 813 | '\x83\x6C\x00\x00\x00\x01\x61\xFF\x6A'); 814 | }); 815 | Erlang.term_to_binary(new Erlang.OtpErlangList([256]), 816 | function(err, binary) { 817 | assert.strictEqual(err, undefined); 818 | assert.equal(binary.toString('binary'), 819 | '\x83\x6C\x00\x00\x00\x01\x62\x00\x00\x01\x00\x6A'); 820 | }); 821 | Erlang.term_to_binary(new Erlang.OtpErlangList([2147483647]), 822 | function(err, binary) { 823 | assert.strictEqual(err, undefined); 824 | assert.equal(binary.toString('binary'), 825 | '\x83\x6C\x00\x00\x00\x01\x62\x7F\xFF\xFF\xFF\x6A'); 826 | }); 827 | Erlang.term_to_binary(new Erlang.OtpErlangList([2147483648]), 828 | function(err, binary) { 829 | assert.strictEqual(err, undefined); 830 | assert.equal(binary.toString('binary'), 831 | '\x83\x6C\x00\x00\x00\x01\x6E\x04\x00\x00\x00\x00\x80\x6A'); 832 | }); 833 | Erlang.term_to_binary(new Erlang.OtpErlangList([0]), 834 | function(err, binary) { 835 | assert.strictEqual(err, undefined); 836 | assert.equal(binary.toString('binary'), 837 | '\x83\x6C\x00\x00\x00\x01\x61\x00\x6A'); 838 | }); 839 | Erlang.term_to_binary(new Erlang.OtpErlangList([-1]), 840 | function(err, binary) { 841 | assert.strictEqual(err, undefined); 842 | assert.equal(binary.toString('binary'), 843 | '\x83\x6C\x00\x00\x00\x01\x62\xFF\xFF\xFF\xFF\x6A'); 844 | }); 845 | Erlang.term_to_binary(new Erlang.OtpErlangList([-256]), 846 | function(err, binary) { 847 | assert.strictEqual(err, undefined); 848 | assert.equal(binary.toString('binary'), 849 | '\x83\x6C\x00\x00\x00\x01\x62\xFF\xFF\xFF\x00\x6A'); 850 | }); 851 | Erlang.term_to_binary(new Erlang.OtpErlangList([-257]), 852 | function(err, binary) { 853 | assert.strictEqual(err, undefined); 854 | assert.equal(binary.toString('binary'), 855 | '\x83\x6C\x00\x00\x00\x01\x62\xFF\xFF\xFE\xFF\x6A'); 856 | }); 857 | Erlang.term_to_binary(new Erlang.OtpErlangList([-2147483648]), 858 | function(err, binary) { 859 | assert.strictEqual(err, undefined); 860 | assert.equal(binary.toString('binary'), 861 | '\x83\x6C\x00\x00\x00\x01\x62\x80\x00\x00\x00\x6A'); 862 | }); 863 | Erlang.term_to_binary(new Erlang.OtpErlangList([-2147483649]), 864 | function(err, binary) { 865 | assert.strictEqual(err, undefined); 866 | assert.equal(binary.toString('binary'), 867 | '\x83\x6C\x00\x00\x00\x01\x6E\x04\x01\x01\x00\x00\x80\x6A'); 868 | }); 869 | Erlang.term_to_binary(new Erlang.OtpErlangList(['test']), 870 | function(err, binary) { 871 | assert.strictEqual(err, undefined); 872 | assert.equal(binary.toString('binary'), 873 | '\x83\x6C\x00\x00\x00\x01\x6B\x00\x04\x74\x65\x73\x74\x6A'); 874 | }); 875 | Erlang.term_to_binary(new Erlang.OtpErlangList([373, 455]), 876 | function(err, binary) { 877 | assert.strictEqual(err, undefined); 878 | assert.equal(binary.toString('binary'), 879 | '\x83\x6C\x00\x00\x00\x02\x62\x00\x00\x01\x75\x62\x00\x00' + 880 | '\x01\xC7\x6A'); 881 | }); 882 | Erlang.term_to_binary(new Erlang.OtpErlangList([ 883 | new Erlang.OtpErlangList([])]), 884 | function(err, binary) { 885 | assert.strictEqual(err, undefined); 886 | assert.equal(binary.toString('binary'), 887 | '\x83\x6C\x00\x00\x00\x01\x6A\x6A'); 888 | }); 889 | Erlang.term_to_binary(new Erlang.OtpErlangList([ 890 | new Erlang.OtpErlangList([]), 891 | new Erlang.OtpErlangList([])]), 892 | function(err, binary) { 893 | assert.strictEqual(err, undefined); 894 | assert.equal(binary.toString('binary'), 895 | '\x83\x6C\x00\x00\x00\x02\x6A\x6A\x6A'); 896 | }); 897 | Erlang.term_to_binary(new Erlang.OtpErlangList([ 898 | new Erlang.OtpErlangList(['this', 'is']), 899 | new Erlang.OtpErlangList([ 900 | new Erlang.OtpErlangList(['a'])]), 901 | 'test']), 902 | function(err, binary) { 903 | assert.strictEqual(err, undefined); 904 | assert.equal(binary.toString('binary'), 905 | '\x83\x6C\x00\x00\x00\x03\x6C\x00\x00\x00\x02\x6B\x00\x04' + 906 | '\x74\x68\x69\x73\x6B\x00\x02\x69\x73\x6A\x6C\x00\x00\x00' + 907 | '\x01\x6C\x00\x00\x00\x01\x6B\x00\x01\x61\x6A\x6A\x6B\x00' + 908 | '\x04\x74\x65\x73\x74\x6A'); 909 | }); 910 | }).call(this); 911 | (function test_term_to_binary_list () { 912 | Erlang.term_to_binary(new Erlang.OtpErlangList([ 913 | new Erlang.OtpErlangList([])]), 914 | function(err, binary) { 915 | assert.strictEqual(err, undefined); 916 | assert.equal(binary.toString('binary'), '\x83l\0\0\0\1jj'); 917 | }); 918 | Erlang.term_to_binary(new Erlang.OtpErlangList([ 919 | new Erlang.OtpErlangList([]), 920 | new Erlang.OtpErlangList([]), 921 | new Erlang.OtpErlangList([]), 922 | new Erlang.OtpErlangList([]), 923 | new Erlang.OtpErlangList([])]), 924 | function(err, binary) { 925 | assert.strictEqual(err, undefined); 926 | assert.equal(binary.toString('binary'), '\x83l\0\0\0\5jjjjjj'); 927 | }); 928 | }).call(this); 929 | (function test_term_to_binary_improper_list () { 930 | Erlang.term_to_binary(new Erlang.OtpErlangList([[], []], true), 931 | function(err, binary) { 932 | assert.strictEqual(err, undefined); 933 | assert.equal(binary.toString('binary'), '\x83l\0\0\0\1h\0h\0'); 934 | }); 935 | Erlang.term_to_binary(new Erlang.OtpErlangList([0, 1], true), 936 | function(err, binary) { 937 | assert.strictEqual(err, undefined); 938 | assert.equal(binary.toString('binary'), '\x83l\0\0\0\1a\0a\1'); 939 | }); 940 | }).call(this); 941 | (function test_term_to_binary_unicode () { 942 | Erlang.term_to_binary('', function(err, binary) { 943 | assert.strictEqual(err, undefined); 944 | assert.equal(binary.toString('binary'), '\x83j'); 945 | }); 946 | Erlang.term_to_binary('test', function(err, binary) { 947 | assert.strictEqual(err, undefined); 948 | assert.equal(binary.toString('binary'), '\x83k\0\4test'); 949 | }); 950 | Erlang.term_to_binary('\x00\xc3\xbf', function(err, binary) { 951 | assert.strictEqual(err, undefined); 952 | assert.equal(binary.toString('binary'), '\x83k\0\3\x00\xc3\xbf'); 953 | }); 954 | Erlang.term_to_binary('\xc4\x80', function(err, binary) { 955 | assert.strictEqual(err, undefined); 956 | assert.equal(binary.toString('binary'), '\x83k\0\2\xc4\x80'); 957 | }); 958 | Erlang.term_to_binary('\xd1\x82\xd0\xb5\xd1\x81\xd1\x82', 959 | function(err, binary) { 960 | assert.strictEqual(err, undefined); 961 | assert.equal(binary.toString('binary'), 962 | '\x83k\0\x08\xd1\x82\xd0\xb5\xd1\x81\xd1\x82'); 963 | }); 964 | // becomes a list of small integers 965 | Erlang.term_to_binary('\xd0\x90'.repeat(65536), 966 | function(err, binary) { 967 | assert.strictEqual(err, undefined); 968 | assert.equal(binary.toString('binary'), 969 | '\x83l\x00\x02\x00\x00' + 'a\xd0a\x90'.repeat(65536) + 'j'); 970 | 971 | }); 972 | }).call(this); 973 | (function test_term_to_binary_atom () { 974 | Erlang.term_to_binary(new Erlang.OtpErlangAtom(''), 975 | function(err, binary) { 976 | assert.strictEqual(err, undefined); 977 | assert.equal(binary.toString('binary'), '\x83w\0'); 978 | }); 979 | Erlang.term_to_binary(new Erlang.OtpErlangAtom('', false), 980 | function(err, binary) { 981 | assert.strictEqual(err, undefined); 982 | assert.equal(binary.toString('binary'), '\x83s\0'); 983 | }); 984 | Erlang.term_to_binary(new Erlang.OtpErlangAtom('test'), 985 | function(err, binary) { 986 | assert.strictEqual(err, undefined); 987 | assert.equal(binary.toString('binary'), '\x83w\4test'); 988 | }); 989 | Erlang.term_to_binary(new Erlang.OtpErlangAtom('test', false), 990 | function(err, binary) { 991 | assert.strictEqual(err, undefined); 992 | assert.equal(binary.toString('binary'), '\x83s\4test'); 993 | }); 994 | Erlang.term_to_binary(new Erlang.OtpErlangAtomLarge('test'), 995 | function(err, binary) { 996 | assert.strictEqual(err, undefined); 997 | assert.equal(binary.toString('binary'), '\x83v\0\4test'); 998 | }); 999 | Erlang.term_to_binary(new Erlang.OtpErlangAtomLarge('test', false), 1000 | function(err, binary) { 1001 | assert.strictEqual(err, undefined); 1002 | assert.equal(binary.toString('binary'), '\x83d\0\4test'); 1003 | }); 1004 | }).call(this); 1005 | (function test_term_to_binary_string_basic () { 1006 | Erlang.term_to_binary('', function(err, binary) { 1007 | assert.strictEqual(err, undefined); 1008 | assert.equal(binary.toString('binary'), '\x83\x6A'); 1009 | }); 1010 | Erlang.term_to_binary('test', function(err, binary) { 1011 | assert.strictEqual(err, undefined); 1012 | assert.equal(binary.toString('binary'), 1013 | '\x83\x6B\x00\x04\x74\x65\x73\x74'); 1014 | }); 1015 | Erlang.term_to_binary('two words', function(err, binary) { 1016 | assert.strictEqual(err, undefined); 1017 | assert.equal(binary.toString('binary'), 1018 | '\x83\x6B\x00\x09\x74\x77\x6F\x20\x77\x6F\x72\x64\x73'); 1019 | }); 1020 | Erlang.term_to_binary('testing multiple words', function(err, binary) { 1021 | assert.strictEqual(err, undefined); 1022 | assert.equal(binary.toString('binary'), 1023 | '\x83\x6B\x00\x16\x74\x65\x73\x74\x69\x6E\x67\x20\x6D' + 1024 | '\x75\x6C\x74\x69\x70\x6C\x65\x20\x77\x6F\x72\x64\x73'); 1025 | }); 1026 | Erlang.term_to_binary(' ', function(err, binary) { 1027 | assert.strictEqual(err, undefined); 1028 | assert.equal(binary.toString('binary'), '\x83\x6B\x00\x01\x20'); 1029 | }); 1030 | Erlang.term_to_binary(' ', function(err, binary) { 1031 | assert.strictEqual(err, undefined); 1032 | assert.equal(binary.toString('binary'), '\x83\x6B\x00\x02\x20\x20'); 1033 | }); 1034 | Erlang.term_to_binary('1', function(err, binary) { 1035 | assert.strictEqual(err, undefined); 1036 | assert.equal(binary.toString('binary'), '\x83\x6B\x00\x01\x31'); 1037 | }); 1038 | Erlang.term_to_binary('37', function(err, binary) { 1039 | assert.strictEqual(err, undefined); 1040 | assert.equal(binary.toString('binary'), '\x83\x6B\x00\x02\x33\x37'); 1041 | }); 1042 | Erlang.term_to_binary('one = 1', function(err, binary) { 1043 | assert.strictEqual(err, undefined); 1044 | assert.equal(binary.toString('binary'), 1045 | '\x83\x6B\x00\x07\x6F\x6E\x65\x20\x3D\x20\x31'); 1046 | }); 1047 | Erlang.term_to_binary('!@#$%^&*()_+-=[]{}\\|;\':",./<>?~`', 1048 | function(err, binary) { 1049 | assert.strictEqual(err, undefined); 1050 | assert.equal(binary.toString('binary'), 1051 | '\x83\x6B\x00\x20\x21\x40\x23\x24\x25\x5E\x26\x2A\x28' + 1052 | '\x29\x5F\x2B\x2D\x3D\x5B\x5D\x7B\x7D\x5C\x7C\x3B\x27' + 1053 | '\x3A\x22\x2C\x2E\x2F\x3C\x3E\x3F\x7E\x60'); 1054 | }); 1055 | Erlang.term_to_binary('\"\b\f\n\r\t\v\123\x12', 1056 | function(err, binary) { 1057 | assert.strictEqual(err, undefined); 1058 | assert.equal(binary.toString('binary'), 1059 | '\x83\x6B\x00\x09\x22\x08\x0C\x0A\x0D\x09\x0B\x53\x12'); 1060 | }); 1061 | }).call(this); 1062 | (function test_term_to_binary_string () { 1063 | Erlang.term_to_binary('', function(err, binary) { 1064 | assert.strictEqual(err, undefined); 1065 | assert.equal(binary.toString('binary'), '\x83j'); 1066 | }); 1067 | Erlang.term_to_binary('test', function(err, binary) { 1068 | assert.strictEqual(err, undefined); 1069 | assert.equal(binary.toString('binary'), '\x83k\0\4test'); 1070 | }); 1071 | }).call(this); 1072 | (function test_term_to_binary_predefined_atom () { 1073 | Erlang.term_to_binary(true, function(err, binary) { 1074 | assert.strictEqual(err, undefined); 1075 | assert.equal(binary.toString('binary'), '\x83w\4true'); 1076 | }); 1077 | Erlang.term_to_binary(false, function(err, binary) { 1078 | assert.strictEqual(err, undefined); 1079 | assert.equal(binary.toString('binary'), '\x83w\5false'); 1080 | }); 1081 | Erlang.term_to_binary(null, function(err, binary) { 1082 | assert.strictEqual(err, undefined); 1083 | assert.equal(binary.toString('binary'), '\x83w\x09undefined'); 1084 | }); 1085 | }).call(this); 1086 | (function test_term_to_binary_short_integer () { 1087 | Erlang.term_to_binary(0, function(err, binary) { 1088 | assert.strictEqual(err, undefined); 1089 | assert.equal(binary.toString('binary'), '\x83a\0'); 1090 | }); 1091 | Erlang.term_to_binary(255, function(err, binary) { 1092 | assert.strictEqual(err, undefined); 1093 | assert.equal(binary.toString('binary'), '\x83a\xff'); 1094 | }); 1095 | }).call(this); 1096 | (function test_term_to_binary_integer () { 1097 | Erlang.term_to_binary(-1, function(err, binary) { 1098 | assert.strictEqual(err, undefined); 1099 | assert.equal(binary.toString('binary'), '\x83b\xff\xff\xff\xff'); 1100 | }); 1101 | Erlang.term_to_binary(-2147483648, function(err, binary) { 1102 | assert.strictEqual(err, undefined); 1103 | assert.equal(binary.toString('binary'), '\x83b\x80\0\0\0'); 1104 | }); 1105 | Erlang.term_to_binary(256, function(err, binary) { 1106 | assert.strictEqual(err, undefined); 1107 | assert.equal(binary.toString('binary'), '\x83b\0\0\1\0'); 1108 | }); 1109 | Erlang.term_to_binary(2147483647, function(err, binary) { 1110 | assert.strictEqual(err, undefined); 1111 | assert.equal(binary.toString('binary'), '\x83b\x7f\xff\xff\xff'); 1112 | }); 1113 | }).call(this); 1114 | (function test_term_to_binary_long_integer () { 1115 | Erlang.term_to_binary(2147483648, function(err, binary) { 1116 | assert.strictEqual(err, undefined); 1117 | assert.equal(binary.toString('binary'), '\x83n\4\0\0\0\0\x80'); 1118 | }); 1119 | Erlang.term_to_binary(-2147483649, function(err, binary) { 1120 | assert.strictEqual(err, undefined); 1121 | assert.equal(binary.toString('binary'), '\x83n\4\1\1\0\0\x80'); 1122 | }); 1123 | }).call(this); 1124 | (function test_term_to_binary_float () { 1125 | // javascript makes 0.0 === 0, so it becomes an integer 1126 | Erlang.term_to_binary(0.0, function(err, binary) { 1127 | assert.strictEqual(err, undefined); 1128 | assert.equal(binary.toString('binary'), '\x83a\0'); 1129 | }); 1130 | Erlang.term_to_binary(0.5, function(err, binary) { 1131 | assert.strictEqual(err, undefined); 1132 | assert.equal(binary.toString('binary'), 1133 | '\x83F?\xe0\0\0\0\0\0\0'); 1134 | }); 1135 | Erlang.term_to_binary(-0.5, function(err, binary) { 1136 | assert.strictEqual(err, undefined); 1137 | assert.equal(binary.toString('binary'), 1138 | '\x83F\xbf\xe0\0\0\0\0\0\0'); 1139 | }); 1140 | Erlang.term_to_binary(3.1415926, function(err, binary) { 1141 | assert.strictEqual(err, undefined); 1142 | assert.equal(binary.toString('binary'), 1143 | '\x83F@\t!\xfbM\x12\xd8J'); 1144 | }); 1145 | Erlang.term_to_binary(-3.1415926, function(err, binary) { 1146 | assert.strictEqual(err, undefined); 1147 | assert.equal(binary.toString('binary'), 1148 | '\x83F\xc0\t!\xfbM\x12\xd8J'); 1149 | }); 1150 | }).call(this); 1151 | (function test_term_to_binary_float () { 1152 | Erlang.term_to_binary(new Erlang.OtpErlangList(new Array(15).fill( 1153 | new Erlang.OtpErlangList([]))), 1154 | function(err, binary) { 1155 | assert.strictEqual(err, undefined); 1156 | assert.equal(binary.toString('binary'), 1157 | '\x83P\x00\x00\x00\x15x\x9c\xcba``\xe0\xcfB\x03\x00B@\x07\x1c'); 1158 | }, true); 1159 | Erlang.term_to_binary(new Erlang.OtpErlangList(new Array(15).fill( 1160 | new Erlang.OtpErlangList([]))), 1161 | function(err, binary) { 1162 | assert.strictEqual(err, undefined); 1163 | assert.equal(binary.toString('binary'), 1164 | '\x83P\x00\x00\x00\x15x\x9c\xcba``\xe0\xcfB\x03\x00B@\x07\x1c'); 1165 | }, 6); 1166 | Erlang.term_to_binary(new Erlang.OtpErlangList(new Array(15).fill( 1167 | new Erlang.OtpErlangList([]))), 1168 | function(err, binary) { 1169 | assert.strictEqual(err, undefined); 1170 | assert.equal(binary.toString('binary'), 1171 | '\x83P\x00\x00\x00\x15x\xda\xcba``\xe0\xcfB\x03\x00B@\x07\x1c'); 1172 | }, 9); 1173 | // node.js zlib is unable to use compression level 0 properly 1174 | // (in version 0.6.12) so showing compression level 1 instead 1175 | Erlang.term_to_binary(new Erlang.OtpErlangList(new Array(15).fill( 1176 | new Erlang.OtpErlangList([]))), 1177 | function(err, binary) { 1178 | assert.strictEqual(err, undefined); 1179 | assert.equal(binary.toString('binary'), 1180 | '\x83P\x00\x00\x00\x15x\x01\xcba``\xe0\xcfB\x03\x00B@\x07\x1c'); 1181 | }, 1); 1182 | Erlang.term_to_binary('d'.repeat(20), function(err, binary) { 1183 | assert.strictEqual(err, undefined); 1184 | assert.equal(binary.toString('binary'), 1185 | '\x83P\0\0\0\x17\x78\xda\xcb\x66\x10\x49\xc1\2\0' + 1186 | '\x5d\x60\x08\x50'); 1187 | }, 9); 1188 | }).call(this); 1189 | (function test_term_to_binary_map () { 1190 | Erlang.term_to_binary(new Erlang.OtpErlangMap(new Map()), 1191 | function(err, binary) { 1192 | assert.strictEqual(err, undefined); 1193 | assert.equal(binary.toString('binary'), 1194 | '\x83t\x00\x00\x00\x00'); 1195 | }); 1196 | var map1 = new Map(); 1197 | map1.set(new Erlang.OtpErlangAtom("a", false), 1); 1198 | Erlang.term_to_binary(new Erlang.OtpErlangMap(map1), 1199 | function(err, binary) { 1200 | assert.strictEqual(err, undefined); 1201 | assert.equal(binary.toString('binary'), 1202 | '\x83t\x00\x00\x00\x01s\x01aa\x01'); 1203 | }); 1204 | var map2 = new Map(); 1205 | map2.set( 1206 | new Erlang.OtpErlangAtom('undefined'), 1207 | new Erlang.OtpErlangBinary( 1208 | new bufferFrom('nothing', 'binary'))); 1209 | map2.set( 1210 | new Erlang.OtpErlangBinary( 1211 | new bufferFrom('\xA8', 'binary'), 6), 1212 | new Erlang.OtpErlangBinary( 1213 | new bufferFrom('everything', 'binary'))); 1214 | Erlang.term_to_binary(new Erlang.OtpErlangMap(map2), 1215 | function(err, binary) { 1216 | assert.strictEqual(err, undefined); 1217 | assert.equal(binary.toString('binary'), 1218 | '\x83\x74\x00\x00\x00\x02\x77\x09\x75\x6E\x64\x65\x66' + 1219 | '\x69\x6E\x65\x64\x6D\x00\x00\x00\x07\x6E\x6F\x74\x68' + 1220 | '\x69\x6E\x67\x4D\x00\x00\x00\x01\x06\xA8\x6D\x00\x00' + 1221 | '\x00\x0A\x65\x76\x65\x72\x79\x74\x68\x69\x6E\x67'); 1222 | }); 1223 | }).call(this); 1224 | }).call(this); 1225 | --------------------------------------------------------------------------------