/* * parseInt() tests * * parseInt() must have "mathematically exact" results for any supported * power of two radix (2, 4, 8, 16, 32). For instance, parsing the base-8 * representation of 2**256 must yield the exact IEEE double value. This * is easy for base two radixes. However, the same property is required * also for base 10 (though not for other bases), which is tricky. */ var WHITESPACE_CODEPOINTS = [ // from WhiteSpace production 0x0009, // 0x000B, // 0x000C, // 0x0020, // 0x00A0, // 0xFEFF, // // WhiteSpace production also has , which means any other Unicode // space separator (category Zs), which needs to be checked from (up to // date) Unicode data. The WhiteSpace-Z.txt file, created as part of // the build, currently contains (duplicates eliminated): // 0x0020, // 0020;SPACE;Zs;0;WS;;;;;N;;;;; // 0x00A0, // 00A0;NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;NON-BREAKING SPACE;;;; 0x1680, // 1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;; 0x180E, // 180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;; 0x2000, // 2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;; 0x2001, // 2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;; 0x2002, // 2002;EN SPACE;Zs;0;WS; 0020;;;;N;;;;; 0x2003, // 2003;EM SPACE;Zs;0;WS; 0020;;;;N;;;;; 0x2004, // 2004;THREE-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; 0x2005, // 2005;FOUR-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; 0x2006, // 2006;SIX-PER-EM SPACE;Zs;0;WS; 0020;;;;N;;;;; 0x2007, // 2007;FIGURE SPACE;Zs;0;WS; 0020;;;;N;;;;; 0x2008, // 2008;PUNCTUATION SPACE;Zs;0;WS; 0020;;;;N;;;;; 0x2009, // 2009;THIN SPACE;Zs;0;WS; 0020;;;;N;;;;; 0x200A, // 200A;HAIR SPACE;Zs;0;WS; 0020;;;;N;;;;; // 0x2028, // 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; // 0x2029, // 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; 0x202F, // 202F;NARROW NO-BREAK SPACE;Zs;0;CS; 0020;;;;N;;;;; 0x205F, // 205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS; 0020;;;;N;;;;; 0x3000, // 3000;IDEOGRAPHIC SPACE;Zs;0;WS; 0020;;;;N;;;;; // from LineTerminator production 0x000a, // 0x000d, // 0x2028, // 0x2029, // ]; // indirect eval -> this is bound to the global object, E5 Section 10.4.2, step 1.a. var g = (function () { var e = eval; return e('this'); } )(); /*=== basic tests NaN 123 51966 65 58798832 ===*/ /* parseInt: some very basic cases */ print('basic tests'); try { print(g.parseInt('')); print(g.parseInt(' 123')); print(g.parseInt('cafe', 16)); print(g.parseInt('01000001', 2)); // smallest supported radix print(g.parseInt('z09gw', 36)); // largest supported radix } catch (e) { print(e.name); } /*=== coercion toString() 123 ===*/ /* parseInt coercion: ToString() followed by string parsing. */ print('coercion'); try { print(g.parseInt( { toString: function() { print('toString()'); return '123'; }, valueOf: function() { print('valueOf()'); return 123; } } )); } catch (e) { print(e.name); } /*=== whitespace strip test 321 123 123 ===*/ /* parseInt white space stripping. * * StrWhiteSpaceChar is WhiteSpace or LineTerminator; WHITESPACE_CODEPOINTS * lists the codepoints. */ print('whitespace strip test'); function whiteSpaceStripTest() { var t = []; var i; var txt; // a simple test with only ASCII whitespace txt = '\u0009\u000b\u000c\u0020\u00a0\u000a\u000d321.0'; print(g.parseInt(txt)); // txt will contain every whitespace codepoint followed by the number for (i = 0; i < WHITESPACE_CODEPOINTS.length; i++) { t.push(String.fromCharCode(WHITESPACE_CODEPOINTS[i])); } t.push('123.0'); txt = t.join(''); print(g.parseInt(txt)); // try with trailing garbage print(g.parseInt(txt + 'xyz')); } try { whiteSpaceStripTest(); } catch (e) { print(e.name); } /*=== trailing garbage 123 123 123 123 123 123 -123 -123 -123 -128 128 -57005 4660 ===*/ /* Trailing garbage is ignored. */ print('trailing garbage'); function trailingGarbageTest() { // decimal print(g.parseInt('123xxx')); print(g.parseInt('123\uffff')); print(g.parseInt('123\u0000')); print(g.parseInt('+123xxx')); print(g.parseInt('+123\uffff')); print(g.parseInt(' +123\u0000')); print(g.parseInt(' -123xxx')); print(g.parseInt(' -123\uffff')); print(g.parseInt(' -123\u0000')); // a few tests in another radix print(g.parseInt(' -10000000xxx', 2)); print(g.parseInt(' 10000000xxx', 2)); // whitespace is also "garbage" print(g.parseInt(' -0xdead beefxxx', 16)); print(g.parseInt(' 1234 5678xxx', 16)); } try { trailingGarbageTest(); } catch (e) { print(e.name); } /*=== fractions 12345678 12345678 12345678 -12345678 -12345678 -12345678 -128 128 ===*/ /* Fractions (decimal or otherwise) as created by e.g. Number.prototype.toString() * are ignored when using parseInt; they are treated as garbage. */ print('fractions'); function fractionsTest() { // decimal print(g.parseInt('12345678.9')); print(g.parseInt('12345678.1')); print(g.parseInt(' +12345678.9')); print(g.parseInt(' -12345678.1')); print(g.parseInt(' -12345678.9')); print(g.parseInt(' -12345678.1')); // a few tests in another radix print(g.parseInt(' -10000000.001', 2)); print(g.parseInt(' 10000000.100', 2)); } try { fractionsTest(); } catch (e) { print(e.name); } /*=== radix tests NaN 8 1000 46656 NaN 1000 1000 1000 1000 1000 1000 46656 46656 NaN 8 1000 46656 NaN NaN 8 1000 46656 NaN 42875 42875 46656 ===*/ /* Valid radix range is 2 to 36, and is coerced with ToInt32. Note that * because ToInt32() uses a modulo-based coercion, integer radix N is the * same as radix N + k*2^32. Rounding is towards zero. * * R = 0 has special handling, it defaults R to 10 (step 9). */ print('radix tests'); function radixTest() { var txt = "1000"; var tp32 = 256 * 256 * 256 * 256; // basic integer range print(g.parseInt(txt, 1)); print(g.parseInt(txt, 2)); print(g.parseInt(txt, 10)); print(g.parseInt(txt, 36)); // 1*36*36*36 print(g.parseInt(txt, 37)); // not given, undefined, 0 radix are the same and interpreted as radix 10 print(g.parseInt(txt)); print(g.parseInt(txt, undefined)); print(g.parseInt(txt, 0)); print(g.parseInt(txt, 10)); // round towards zero print(g.parseInt(txt, 10.1)); print(g.parseInt(txt, 10.9)); print(g.parseInt(txt, 36.1)); print(g.parseInt(txt, 36.9)); // modulo effect print(g.parseInt(txt, 1 + tp32)); print(g.parseInt(txt, 2 + tp32)); print(g.parseInt(txt, 10 + tp32)); print(g.parseInt(txt, 36 + tp32)); print(g.parseInt(txt, 37 + tp32)); print(g.parseInt(txt, 1 - tp32)); print(g.parseInt(txt, 2 - tp32)); print(g.parseInt(txt, 10 - tp32)); print(g.parseInt(txt, 36 - tp32)); print(g.parseInt(txt, 37 - tp32)); // fractional radixes work differently because of round-towards-zero. // positive values round downwards before modulo computation; negative // values effectively round upwards print(g.parseInt(txt, 35.9 + tp32)); // 4294967331.9 -> 4294967331 -> 35 (after -2^32) print(g.parseInt(txt, 35.9)); print(g.parseInt(txt, 35.9 - tp32)); // -4294967260.1 -> -4294967260 -> 36 (after +2^32) } try { radixTest(); } catch (e) { print(e.name); } /*=== radix 16 51966 -51966 51966 -51966 -51966 51966 -51966 51966 0 0 0 0 ===*/ /* parseInt radix is defaulted to 16 if the string begins with "0x" or "0X". * The prefix "0x" or "0X" is permitted (only) if radix is 16. */ print('radix 16'); function testRadix16(x, r, arg_count) { var t; try { if (arg_count == 1) { t = g.parseInt(x); } else { t = g.parseInt(x, r); } print(t); } catch (e) { print(e); } } function radix16Test() { testRadix16('0xcafe', undefined, 1); testRadix16('-0Xcafe', undefined, 1); testRadix16(' 0xCAfe', undefined, 1); // whitespace + case variation testRadix16(' -0XCAfe', undefined, 1); testRadix16('-0xcafe', 16); testRadix16('0Xcafe', 16); testRadix16(' -0xCAfe', 16.5); testRadix16(' 0XCAfe', 16.5); /* The expected result here is not obvious. Let's consider the * first case. * * In step 6, R will be 15, which causes us to execute step 8.b, * i.e. stripPrefix will be false. Step 10 will then be skipped, * and the '0x' prefix should NOT cause an automatic radix 16 * conversion. * * Parsing in base 15, the first character will be a valid digit * (zero), while the second character will be garbage and terminate * parsing. The result should, thus be 0. * * (However, at least V8/Rhino will parse these as hexadecimal.) */ testRadix16('0xcafe', 15); testRadix16('0Xcafe', 15); testRadix16('0x1234', 10); testRadix16('0X1234', 10); } try { radix16Test(); } catch (e) { print(e.name); } /*=== radix 8 123 129 123 129 -123 -129 83 10 83 10 -83 -10 123 129 123 129 -123 -129 ===*/ /* Radix 8 test. * * These is no standard automatic mechanism for using radix 8 (like * "0x" or "0X" prefix for radix 16). However, both V8 and Rhino seem * to use a leading zero to indicate automatic radix 8. * * This is not standard behavior, so test against this behavior * (at least for now). */ /* FIXME: change Duktape behavior to match V8 and Rhino for octal? */ print('radix 8'); function radix8Test() { // this should be interpreted as base-10; V8 and Rhino interpret these // as octal (0129 will be parsed as "012" with 9 treated as garbage) print(g.parseInt('0123')); print(g.parseInt('0129')); print(g.parseInt('+0123')); print(g.parseInt('+0129')); print(g.parseInt('-0123')); print(g.parseInt('-0129')); // explicit radix 8 print(g.parseInt('0123', 8)); print(g.parseInt('0129', 8)); print(g.parseInt('+0123', 8)); print(g.parseInt('+0129', 8)); print(g.parseInt('-0123', 8)); print(g.parseInt('-0129', 8)); // explicit radix 10 print(g.parseInt('0123', 10)); print(g.parseInt('0129', 10)); print(g.parseInt('+0123', 10)); print(g.parseInt('+0129', 10)); print(g.parseInt('-0123', 10)); print(g.parseInt('-0129', 10)); } try { radix8Test(); } catch (e) { print(e.name); } /*=== signed values 123 -123 291 -291 66 -66 ===*/ /* Signed values; test negative values in other radixes especially. */ print('signed values'); function signedValueTest() { print(g.parseInt(' +123')); print(g.parseInt(' -123')); print(g.parseInt(' +0x123')); print(g.parseInt(' -0X123')); print(g.parseInt(' +123', 7)); print(g.parseInt(' -123', 7)); } try { signedValueTest(); } catch (e) { print(e.name); } /*=== leading zeroes 123 123 -123 129 129 -129 57005 57005 -57005 668 668 -668 ===*/ /* Leading zeroes. * * Note that V8 and Rhino use a leading zero (not followed by 'x' or 'X') to * indicate an automatic radix 8 (octal). This doesn't seem spec compliant, * so test against this for now. */ /* FIXME: change Duktape behavior to match V8 and Rhino for octal? */ print('leading zeroes'); function leadingZeroTest() { // V8 will yield +/- 83 for this print(g.parseInt('000123')); print(g.parseInt('+000123')); print(g.parseInt('-000123')); // V8 will yield +/- 10 for this (012 = 10 octal, 9 is garbage) print(g.parseInt('000129')); print(g.parseInt('+000129')); print(g.parseInt('-000129')); print(g.parseInt('0x0000dead')); print(g.parseInt('+0x0000dead')); print(g.parseInt('-0x0000dead')); print(g.parseInt('00001234', 8)); print(g.parseInt('+00001234', 8)); print(g.parseInt('-00001234', 8)); } try { leadingZeroTest(); } catch (e) { print(e.name); } /*=== numbers below/above 2**53 (testdump) 9007199254740984 9007199254740985 9007199254740986 9007199254740987 9007199254740988 9007199254740989 9007199254740990 9007199254740991 9007199254740992 9007199254740992 9007199254740994 9007199254740996 9007199254740996 9007199254740996 9007199254740998 9007199254741000 9007199254741000 (parse decimals) 9007199254740992 9007199254740992 9007199254740994 9007199254740996 9007199254740996 9007199254740996 9007199254740998 9007199254741000 9007199254741000 (parse hex) 9007199254740992 9007199254740992 9007199254740994 9007199254740996 9007199254740996 9007199254740996 9007199254740998 9007199254741000 9007199254741000 (parse radix 2) 9007199254740992 9007199254740992 9007199254740994 9007199254740996 9007199254740996 9007199254740996 9007199254740998 9007199254741000 9007199254741000 (parse radix 4) 9007199254740992 9007199254740992 9007199254740994 9007199254740996 9007199254740996 9007199254740996 9007199254740998 9007199254741000 9007199254741000 (parse radix 8) 9007199254740992 9007199254740992 9007199254740994 9007199254740996 9007199254740996 9007199254740996 9007199254740998 9007199254741000 9007199254741000 (parse radix 32) 9007199254740992 9007199254740992 9007199254740994 9007199254740996 9007199254740996 9007199254740996 9007199254740998 9007199254741000 9007199254741000 (parse radix 36) 9007199254740992 9007199254740992 9007199254740994 9007199254740996 9007199254740996 9007199254740996 9007199254740998 9007199254741000 9007199254741000 ===*/ /* Numbers close to just below and above the IEEE double range (53 bits). */ print('numbers below/above 2**53'); function numbersNear53BitsTest() { var two_to_53 = 65536*65536*65536*2*2*2*2*2; // 2**53 var i; // demonstrate how behavior after 2**53 changes // FIXME: elaborate on the rounding behavior print('(testdump)'); for (i = -8; i <= 8; i++) { print(two_to_53 + i); } print('(parse decimals)'); print(g.parseInt('9007199254740992')); print(g.parseInt('9007199254740993')); print(g.parseInt('9007199254740994')); print(g.parseInt('9007199254740995')); print(g.parseInt('9007199254740996')); print(g.parseInt('9007199254740997')); print(g.parseInt('9007199254740998')); print(g.parseInt('9007199254740999')); print(g.parseInt('9007199254741000')); print('(parse hex)'); print(g.parseInt('0x20000000000000')); print(g.parseInt('0x20000000000001')); print(g.parseInt('0x20000000000002')); print(g.parseInt('0x20000000000003')); print(g.parseInt('0x20000000000004')); print(g.parseInt('0x20000000000005')); print(g.parseInt('0x20000000000006')); print(g.parseInt('0x20000000000007')); print(g.parseInt('0x20000000000008')); print('(parse radix 2)'); print(g.parseInt('100000000000000000000000000000000000000000000000000000', 2)); print(g.parseInt('100000000000000000000000000000000000000000000000000001', 2)); print(g.parseInt('100000000000000000000000000000000000000000000000000010', 2)); print(g.parseInt('100000000000000000000000000000000000000000000000000011', 2)); print(g.parseInt('100000000000000000000000000000000000000000000000000100', 2)); print(g.parseInt('100000000000000000000000000000000000000000000000000101', 2)); print(g.parseInt('100000000000000000000000000000000000000000000000000110', 2)); print(g.parseInt('100000000000000000000000000000000000000000000000000111', 2)); print(g.parseInt('100000000000000000000000000000000000000000000000001000', 2)); print('(parse radix 4)'); print(g.parseInt('200000000000000000000000000', 4)); print(g.parseInt('200000000000000000000000001', 4)); print(g.parseInt('200000000000000000000000002', 4)); print(g.parseInt('200000000000000000000000003', 4)); print(g.parseInt('200000000000000000000000010', 4)); print(g.parseInt('200000000000000000000000011', 4)); print(g.parseInt('200000000000000000000000012', 4)); print(g.parseInt('200000000000000000000000013', 4)); print(g.parseInt('200000000000000000000000020', 4)); print('(parse radix 8)'); print(g.parseInt('400000000000000000', 8)); print(g.parseInt('400000000000000001', 8)); print(g.parseInt('400000000000000002', 8)); print(g.parseInt('400000000000000003', 8)); print(g.parseInt('400000000000000004', 8)); print(g.parseInt('400000000000000005', 8)); print(g.parseInt('400000000000000006', 8)); print(g.parseInt('400000000000000007', 8)); print(g.parseInt('400000000000000010', 8)); print('(parse radix 32)'); print(g.parseInt('80000000000', 32)); print(g.parseInt('80000000001', 32)); print(g.parseInt('80000000002', 32)); print(g.parseInt('80000000003', 32)); print(g.parseInt('80000000004', 32)); print(g.parseInt('80000000005', 32)); print(g.parseInt('80000000006', 32)); print(g.parseInt('80000000007', 32)); print(g.parseInt('80000000008', 32)); print('(parse radix 36)'); print(g.parseInt('2gosa7pa2gw', 36)); print(g.parseInt('2gosa7pa2gx', 36)); print(g.parseInt('2gosa7pa2gy', 36)); print(g.parseInt('2gosa7pa2gz', 36)); print(g.parseInt('2gosa7pa2h0', 36)); print(g.parseInt('2gosa7pa2h1', 36)); print(g.parseInt('2gosa7pa2h2', 36)); print(g.parseInt('2gosa7pa2h3', 36)); print(g.parseInt('2gosa7pa2h4', 36)); /* Parsing results for radix 3 are not required to be exact, so * printing these results would result in a custom test. V8 and * Rhino also have different results for the commented out radix 3 * test below in practice, too. */ /* print('(parse radix 3)'); print(g.parseInt('1121202011211211122211100012101112', 3)); print(g.parseInt('1121202011211211122211100012101120', 3)); print(g.parseInt('1121202011211211122211100012101121', 3)); print(g.parseInt('1121202011211211122211100012101122', 3)); print(g.parseInt('1121202011211211122211100012101200', 3)); print(g.parseInt('1121202011211211122211100012101201', 3)); print(g.parseInt('1121202011211211122211100012101202', 3)); print(g.parseInt('1121202011211211122211100012101210', 3)); print(g.parseInt('1121202011211211122211100012101211', 3)); */ } try { numbersNear53BitsTest(); } catch (e) { print(e.name); } /*=== large number test 2 3.402823669209385e+38 true 3 diff ok true 4 3.402823669209385e+38 true 5 diff ok true 6 diff ok true 7 diff ok true 8 3.402823669209385e+38 true 9 diff ok true 10 3.402823669209385e+38 true 11 diff ok true 12 diff ok true 13 diff ok true 14 diff ok true 15 diff ok true 16 3.402823669209385e+38 true 17 diff ok true 18 diff ok true 19 diff ok true 20 diff ok true 21 diff ok true 22 diff ok true 23 diff ok true 24 diff ok true 25 diff ok true 26 diff ok true 27 diff ok true 28 diff ok true 29 diff ok true 30 diff ok true 31 diff ok true 32 3.402823669209385e+38 true 33 diff ok true 34 diff ok true 35 diff ok true 36 diff ok true ===*/ /* Numbers much higher than 53 bits. * * Check 2**128 in all supported radixes. */ /* digits = '0123456789abcdefghijklmnopqrstuvwxyz'; print('// len(digits) = %d' % len(digits)) def tobase(x,n): t = [] while x != 0: t.append(digits[x % n]) x = x / n t.reverse() return ''.join(t) print('[') for i in xrange(2, 37): print('{ base: %d, str: "%s" },' % (i, tobase(2**128, i))) print(']') */ print('large number test'); function largeNumberTest() { var inputs = [ { base: 2, str: "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }, { base: 3, str: "202201102121002021012000211012011021221022212021111001022110211020010021100121011" }, { base: 4, str: "10000000000000000000000000000000000000000000000000000000000000000" }, { base: 5, str: "11031110441201303134210404233413032443021130230130231311" }, { base: 6, str: "23053353530155550541354043543542243325553444410304" }, { base: 7, str: "3115512162124626343001006330151620356026315304" }, { base: 8, str: "4000000000000000000000000000000000000000000" }, { base: 9, str: "22642532235024164257285244038424203240534" }, { base: 10, str: "340282366920938463463374607431768211456" }, { base: 11, str: "1000a504186892265432152aa27a7929366353" }, { base: 12, str: "5916b64b41143526a777873841863a6a6994" }, { base: 13, str: "47168c9c477c94ba75a2bc735955c7aa139" }, { base: 14, str: "51a45cb9506962a31983dac25409715d04" }, { base: 15, str: "7d491176809c28848a561186d4857d321" }, { base: 16, str: "100000000000000000000000000000000" }, { base: 17, str: "279078gb8485d7b72e2ag3c08ed3g121" }, { base: 18, str: "78a399ccdeb5bd6ha3184c0fh64da64" }, { base: 19, str: "1910510fd19aig25hc6g5gebeb98h84" }, { base: 20, str: "66f609c19456i2h147iga2g17b68cg" }, { base: 21, str: "1b71cc7c703ijd4g3k82ff6keb3c04" }, { base: 22, str: "8h8b5gheh7legf73fb0had7bhd3de" }, { base: 23, str: "2c59d9lld38jeh6fgh5m42j82lfdd" }, { base: 24, str: "iamei9lfd1i5k10n7fnfn25b3kag" }, { base: 25, str: "6365o71fgjb44dj83en26fd1fd86" }, { base: 26, str: "23745echihn4jcil7jec2kd69a1m" }, { base: 27, str: "kjbg2750m547p8n7d18cm6379g4" }, { base: 28, str: "81a71cgjeb6cjo7odb65d7icrl4" }, { base: 29, str: "36l6q70ega3gd8s9ag8rce14rap" }, { base: 30, str: "1a4p5qh8koob2e2gknbn3jbm88g" }, { base: 31, str: "hleoq9ui363gg16lmp8srn1je8" }, { base: 32, str: "80000000000000000000000000" }, { base: 33, str: "3nakotlgi17b10fs1825j5cf1p" }, { base: 34, str: "1ppi6nphe0ckbctn7qwp6qrh9i" }, { base: 35, str: "try5wbbiprfp7r727m0oyq2wb" }, { base: 36, str: "f5lxx1zz5pnorynqglhzmsp34" }, ]; var results = []; var i; var diff; // these are required to be exact by the specification: since 2**128 can be represented // exactly, the result must be exact and equal for all of these var required_exact = { '2': true, '4': true, '8': true, '16': true, '32': true, '10': true }; for (i = 0; i < inputs.length; i++) { results.push(g.parseInt(inputs[i].str, inputs[i].base)); if (required_exact[inputs[i].base]) { // Assume base 2 is correct and compare everything against that // for those radixes for which results are required to be bit // exact. print(inputs[i].base, results[i], results[i] === results[0]); } else { // Fon't print out the results for other bases, as they don't // necessarily match (even in practice). // // For 2**128, given mantissa is 53 bits (one bit implicit), // expect around some multiple of 2**(128-53) = 2**75 = // 3.777893186295716e+22 of error. Limit allows over 10-fold // error now. diff = results[i] - results[0]; print(inputs[i].base, 'diff ok', Math.abs(diff) < 4e23); //print(inputs[i].base, results[i], results[i] === results[0]); } } } try { largeNumberTest(); } catch (e) { print(e.name); } /*=== digit cases 3735928559 1047601316294262 ===*/ /* Upper and lowercase digits. */ print('digit cases'); function digitCaseTest() { print(g.parseInt('0xdeADbEeF')); print(g.parseInt('aBcDeFgGhI', 36)); } try { digitCaseTest(); } catch (e) { print(e.name); }