diff --git a/test/cmdlineTests/message_format_utf8/err b/test/cmdlineTests/message_format_utf8/err index c73ed714f..e14ed61e9 100644 --- a/test/cmdlineTests/message_format_utf8/err +++ b/test/cmdlineTests/message_format_utf8/err @@ -7,29 +7,30 @@ Warning: Source file does not specify required compiler version! Warning: Statement has no effect. --> message_format_utf8/input.sol:2:51: | -2 | /* ©©©©ᄅ©©©©© 2017 */ constructor () { "©©©©ᄅ©©©©©" ; } - | ^^^^^^^^^^^^ +2 | /* ©©©©ᄅ©©©©© 2017 */ constructor () { unicode"©©©©ᄅ©©©©©" ; } + | ^^^^^^^^^^^^^^^^^^^ Warning: Statement has no effect. --> message_format_utf8/input.sol:6:25: | -6 | "S = π × r²"; - | ^^^^^^^^^^^^ +6 | unicode"S = π × r²"; + | ^^^^^^^^^^^^^^^^^^^ Warning: Statement has no effect. --> message_format_utf8/input.sol:7:39: | -7 | /* ₀₁₂₃₄⁵⁶⁷⁸⁹ */ "∑ 1/n! ≈ 2.7"; // tabs in-between - | ^^^^^^^^^^^^^^ +7 | /* ₀₁₂₃₄⁵⁶⁷⁸⁹ */ unicode"∑ 1/n! ≈ 2.7"; // tabs in-between + | ^^^^^^^^^^^^^^^^^^^^^ Warning: Statement has no effect. --> message_format_utf8/input.sol:8:30: | -8 | /* Ŀŏŗėɯ ïƥŝʉɱ */ "μὴ χεῖρον βέλτιστον"; // tabs in-between and inside - | ^^^ ^^^^^^ ^^^^^^^^^^ +8 | /* Ŀŏŗėɯ ïƥŝʉɱ */ unicode"μὴ χεῖρον βέλτιστον"; // tabs in-between and inside + | ^^^^^^^^^^ ^^^^^^ ^^^^^^^^^^ Warning: Function state mutability can be restricted to pure --> message_format_utf8/input.sol:12:2: | 12 | function selector() public returns(uint) { // starts with tab | ^ (Relevant source part starts here and spans across multiple lines). + diff --git a/test/cmdlineTests/message_format_utf8/input.sol b/test/cmdlineTests/message_format_utf8/input.sol index dbeddfa01..faf18f139 100644 --- a/test/cmdlineTests/message_format_utf8/input.sol +++ b/test/cmdlineTests/message_format_utf8/input.sol @@ -1,11 +1,11 @@ contract Foo { -/* ©©©©ᄅ©©©©© 2017 */ constructor () { "©©©©ᄅ©©©©©" ; } +/* ©©©©ᄅ©©©©© 2017 */ constructor () { unicode"©©©©ᄅ©©©©©" ; } function f() public pure { - "S = π × r²"; -/* ₀₁₂₃₄⁵⁶⁷⁸⁹ */ "∑ 1/n! ≈ 2.7"; // tabs in-between -/* Ŀŏŗėɯ ïƥŝʉɱ */ "μὴ χεῖρον βέλτιστον"; // tabs in-between and inside + unicode"S = π × r²"; +/* ₀₁₂₃₄⁵⁶⁷⁸⁹ */ unicode"∑ 1/n! ≈ 2.7"; // tabs in-between +/* Ŀŏŗėɯ ïƥŝʉɱ */ unicode"μὴ χεῖρον βέλτιστον"; // tabs in-between and inside } diff --git a/test/libsolidity/ASTJSON/string.json b/test/libsolidity/ASTJSON/string.json new file mode 100644 index 000000000..f47b41e47 --- /dev/null +++ b/test/libsolidity/ASTJSON/string.json @@ -0,0 +1,131 @@ +{ + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 9 + ] + }, + "id": 10, + "nodeType": "SourceUnit", + "nodes": + [ + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "fullyImplemented": true, + "id": 9, + "linearizedBaseContracts": + [ + 9 + ], + "name": "C", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "body": + { + "id": 7, + "nodeType": "Block", + "src": "33:36:1", + "statements": + [ + { + "assignments": + [ + 4 + ], + "declarations": + [ + { + "constant": false, + "id": 4, + "mutability": "mutable", + "name": "x", + "nodeType": "VariableDeclaration", + "scope": 7, + "src": "35:15:1", + "stateVariable": false, + "storageLocation": "memory", + "typeDescriptions": + { + "typeIdentifier": "t_string_memory_ptr", + "typeString": "string" + }, + "typeName": + { + "id": 3, + "name": "string", + "nodeType": "ElementaryTypeName", + "src": "35:6:1", + "typeDescriptions": + { + "typeIdentifier": "t_string_storage_ptr", + "typeString": "string" + } + }, + "visibility": "internal" + } + ], + "id": 6, + "initialValue": + { + "hexValue": "48656c6c6f20576f726c64", + "id": 5, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "string", + "lValueRequested": false, + "nodeType": "Literal", + "src": "53:13:1", + "typeDescriptions": + { + "typeIdentifier": "t_stringliteral_592fa743889fc7f92ac2a37bb1f5ba1daf2a5c84741ca0e0061d243a2e6707ba", + "typeString": "literal_string \"Hello World\"" + }, + "value": "Hello World" + }, + "nodeType": "VariableDeclarationStatement", + "src": "35:31:1" + } + ] + }, + "functionSelector": "26121ff0", + "id": 8, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "f", + "nodeType": "FunctionDefinition", + "parameters": + { + "id": 1, + "nodeType": "ParameterList", + "parameters": [], + "src": "23:2:1" + }, + "returnParameters": + { + "id": 2, + "nodeType": "ParameterList", + "parameters": [], + "src": "33:0:1" + }, + "scope": 9, + "src": "13:56:1", + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + } + ], + "scope": 10, + "src": "0:71:1" + } + ], + "src": "0:72:1" +} diff --git a/test/libsolidity/ASTJSON/string.sol b/test/libsolidity/ASTJSON/string.sol new file mode 100644 index 000000000..a0a213475 --- /dev/null +++ b/test/libsolidity/ASTJSON/string.sol @@ -0,0 +1,3 @@ +contract C { function f() public { string memory x = "Hello World"; } } + +// ---- diff --git a/test/libsolidity/ASTJSON/string_legacy.json b/test/libsolidity/ASTJSON/string_legacy.json new file mode 100644 index 000000000..96c984209 --- /dev/null +++ b/test/libsolidity/ASTJSON/string_legacy.json @@ -0,0 +1,165 @@ +{ + "attributes": + { + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 9 + ] + } + }, + "children": + [ + { + "attributes": + { + "abstract": false, + "baseContracts": + [ + null + ], + "contractDependencies": + [ + null + ], + "contractKind": "contract", + "fullyImplemented": true, + "linearizedBaseContracts": + [ + 9 + ], + "name": "C", + "scope": 10 + }, + "children": + [ + { + "attributes": + { + "functionSelector": "26121ff0", + "implemented": true, + "isConstructor": false, + "kind": "function", + "modifiers": + [ + null + ], + "name": "f", + "scope": 9, + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + }, + "children": + [ + { + "attributes": + { + "parameters": + [ + null + ] + }, + "children": [], + "id": 1, + "name": "ParameterList", + "src": "23:2:1" + }, + { + "attributes": + { + "parameters": + [ + null + ] + }, + "children": [], + "id": 2, + "name": "ParameterList", + "src": "33:0:1" + }, + { + "children": + [ + { + "attributes": + { + "assignments": + [ + 4 + ] + }, + "children": + [ + { + "attributes": + { + "constant": false, + "mutability": "mutable", + "name": "x", + "scope": 7, + "stateVariable": false, + "storageLocation": "memory", + "type": "string", + "visibility": "internal" + }, + "children": + [ + { + "attributes": + { + "name": "string", + "type": "string" + }, + "id": 3, + "name": "ElementaryTypeName", + "src": "35:6:1" + } + ], + "id": 4, + "name": "VariableDeclaration", + "src": "35:15:1" + }, + { + "attributes": + { + "hexvalue": "48656c6c6f20576f726c64", + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "token": "string", + "type": "literal_string \"Hello World\"", + "value": "Hello World" + }, + "id": 5, + "name": "Literal", + "src": "53:13:1" + } + ], + "id": 6, + "name": "VariableDeclarationStatement", + "src": "35:31:1" + } + ], + "id": 7, + "name": "Block", + "src": "33:36:1" + } + ], + "id": 8, + "name": "FunctionDefinition", + "src": "13:56:1" + } + ], + "id": 9, + "name": "ContractDefinition", + "src": "0:71:1" + } + ], + "id": 10, + "name": "SourceUnit", + "src": "0:72:1" +} diff --git a/test/libsolidity/ASTJSON/unicode.json b/test/libsolidity/ASTJSON/unicode.json new file mode 100644 index 000000000..81c8ad0da --- /dev/null +++ b/test/libsolidity/ASTJSON/unicode.json @@ -0,0 +1,131 @@ +{ + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 9 + ] + }, + "id": 10, + "nodeType": "SourceUnit", + "nodes": + [ + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "fullyImplemented": true, + "id": 9, + "linearizedBaseContracts": + [ + 9 + ], + "name": "C", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "body": + { + "id": 7, + "nodeType": "Block", + "src": "33:42:1", + "statements": + [ + { + "assignments": + [ + 4 + ], + "declarations": + [ + { + "constant": false, + "id": 4, + "mutability": "mutable", + "name": "x", + "nodeType": "VariableDeclaration", + "scope": 7, + "src": "35:15:1", + "stateVariable": false, + "storageLocation": "memory", + "typeDescriptions": + { + "typeIdentifier": "t_string_memory_ptr", + "typeString": "string" + }, + "typeName": + { + "id": 3, + "name": "string", + "nodeType": "ElementaryTypeName", + "src": "35:6:1", + "typeDescriptions": + { + "typeIdentifier": "t_string_storage_ptr", + "typeString": "string" + } + }, + "visibility": "internal" + } + ], + "id": 6, + "initialValue": + { + "hexValue": "48656c6c6f20f09f9883", + "id": 5, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "unicodeString", + "lValueRequested": false, + "nodeType": "Literal", + "src": "53:19:1", + "typeDescriptions": + { + "typeIdentifier": "t_stringliteral_cd7a99177cebb3d14b8cc54e313dbf76867c71cd6fbb9a33ce3870dc80e9992b", + "typeString": "literal_string \"Hello \ud83d\ude03\"" + }, + "value": "Hello \ud83d\ude03" + }, + "nodeType": "VariableDeclarationStatement", + "src": "35:37:1" + } + ] + }, + "functionSelector": "26121ff0", + "id": 8, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "f", + "nodeType": "FunctionDefinition", + "parameters": + { + "id": 1, + "nodeType": "ParameterList", + "parameters": [], + "src": "23:2:1" + }, + "returnParameters": + { + "id": 2, + "nodeType": "ParameterList", + "parameters": [], + "src": "33:0:1" + }, + "scope": 9, + "src": "13:62:1", + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + } + ], + "scope": 10, + "src": "0:77:1" + } + ], + "src": "0:78:1" +} diff --git a/test/libsolidity/ASTJSON/unicode.sol b/test/libsolidity/ASTJSON/unicode.sol new file mode 100644 index 000000000..ca172bf25 --- /dev/null +++ b/test/libsolidity/ASTJSON/unicode.sol @@ -0,0 +1,3 @@ +contract C { function f() public { string memory x = unicode"Hello 😃"; } } + +// ---- diff --git a/test/libsolidity/ASTJSON/unicode_legacy.json b/test/libsolidity/ASTJSON/unicode_legacy.json new file mode 100644 index 000000000..22976f6f9 --- /dev/null +++ b/test/libsolidity/ASTJSON/unicode_legacy.json @@ -0,0 +1,165 @@ +{ + "attributes": + { + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 9 + ] + } + }, + "children": + [ + { + "attributes": + { + "abstract": false, + "baseContracts": + [ + null + ], + "contractDependencies": + [ + null + ], + "contractKind": "contract", + "fullyImplemented": true, + "linearizedBaseContracts": + [ + 9 + ], + "name": "C", + "scope": 10 + }, + "children": + [ + { + "attributes": + { + "functionSelector": "26121ff0", + "implemented": true, + "isConstructor": false, + "kind": "function", + "modifiers": + [ + null + ], + "name": "f", + "scope": 9, + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + }, + "children": + [ + { + "attributes": + { + "parameters": + [ + null + ] + }, + "children": [], + "id": 1, + "name": "ParameterList", + "src": "23:2:1" + }, + { + "attributes": + { + "parameters": + [ + null + ] + }, + "children": [], + "id": 2, + "name": "ParameterList", + "src": "33:0:1" + }, + { + "children": + [ + { + "attributes": + { + "assignments": + [ + 4 + ] + }, + "children": + [ + { + "attributes": + { + "constant": false, + "mutability": "mutable", + "name": "x", + "scope": 7, + "stateVariable": false, + "storageLocation": "memory", + "type": "string", + "visibility": "internal" + }, + "children": + [ + { + "attributes": + { + "name": "string", + "type": "string" + }, + "id": 3, + "name": "ElementaryTypeName", + "src": "35:6:1" + } + ], + "id": 4, + "name": "VariableDeclaration", + "src": "35:15:1" + }, + { + "attributes": + { + "hexvalue": "48656c6c6f20f09f9883", + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "token": "unicodeString", + "type": "literal_string \"Hello \ud83d\ude03\"", + "value": "Hello \ud83d\ude03" + }, + "id": 5, + "name": "Literal", + "src": "53:19:1" + } + ], + "id": 6, + "name": "VariableDeclarationStatement", + "src": "35:37:1" + } + ], + "id": 7, + "name": "Block", + "src": "33:42:1" + } + ], + "id": 8, + "name": "FunctionDefinition", + "src": "13:62:1" + } + ], + "id": 9, + "name": "ContractDefinition", + "src": "0:77:1" + } + ], + "id": 10, + "name": "SourceUnit", + "src": "0:78:1" +} diff --git a/test/libsolidity/SolidityScanner.cpp b/test/libsolidity/SolidityScanner.cpp index 7d5480fb8..531d98415 100644 --- a/test/libsolidity/SolidityScanner.cpp +++ b/test/libsolidity/SolidityScanner.cpp @@ -494,6 +494,8 @@ BOOST_AUTO_TEST_CASE(empty_comment) } +// Unicode string escapes + BOOST_AUTO_TEST_CASE(valid_unicode_string_escape) { Scanner scanner(CharStream("{ \"\\u00DAnicode\"", "")); @@ -533,6 +535,25 @@ BOOST_AUTO_TEST_CASE(invalid_short_unicode_string_escape) BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal); } +// Unicode string literal + +BOOST_AUTO_TEST_CASE(valid_unicode_literal) +{ + Scanner scanner(CharStream("{ unicode\"Hello 😃\"", "")); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); + BOOST_CHECK_EQUAL(scanner.next(), Token::UnicodeStringLiteral); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), std::string("Hello \xf0\x9f\x98\x83", 10)); +} + +BOOST_AUTO_TEST_CASE(valid_nonprintable_in_unicode_literal) +{ + // Non-printable characters are allowed in unicode strings... + Scanner scanner(CharStream("{ unicode\"Hello \007😃\"", "")); + BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace); + BOOST_CHECK_EQUAL(scanner.next(), Token::UnicodeStringLiteral); + BOOST_CHECK_EQUAL(scanner.currentLiteral(), std::string("Hello \x07\xf0\x9f\x98\x83", 11)); +} + // HEX STRING LITERAL BOOST_AUTO_TEST_CASE(valid_hex_literal) diff --git a/test/libsolidity/semanticTests/strings/unicode_string.sol b/test/libsolidity/semanticTests/strings/unicode_string.sol index 73616e479..ceea9702a 100644 --- a/test/libsolidity/semanticTests/strings/unicode_string.sol +++ b/test/libsolidity/semanticTests/strings/unicode_string.sol @@ -1,9 +1,14 @@ contract C { function f() public pure returns (string memory) { - return "😃, 😭, and 😈"; + return unicode"😃, 😭, and 😈"; + } + function g() public pure returns (string memory) { + return unicode"😃, 😭,\ + and 😈"; } } // ==== // compileViaYul: also // ---- // f() -> 0x20, 0x14, "\xf0\x9f\x98\x83, \xf0\x9f\x98\xad, and \xf0\x9f\x98\x88" +// g() -> 0x20, 0x14, "\xf0\x9f\x98\x83, \xf0\x9f\x98\xad, and \xf0\x9f\x98\x88" diff --git a/test/libsolidity/semanticTests/types/strings.sol b/test/libsolidity/semanticTests/types/strings.sol index 8e6f09430..0cc4565af 100644 --- a/test/libsolidity/semanticTests/types/strings.sol +++ b/test/libsolidity/semanticTests/types/strings.sol @@ -1,4 +1,7 @@ contract test { + function fixedBytesHex() public returns(bytes32 ret) { + return hex"aabb00ff"; + } function fixedBytes() public returns(bytes32 ret) { return "abc\x00\xff__"; } @@ -11,5 +14,6 @@ contract test { // ==== // compileViaYul: also // ---- +// fixedBytesHex() -> "\xaa\xbb\0\xff" // fixedBytes() -> "abc\0\xff__" // pipeThrough(bytes2, bool): "\0\x02", true -> "\0\x2", true diff --git a/test/libsolidity/syntaxTests/string/large_utf8_codepoint.sol b/test/libsolidity/syntaxTests/string/large_utf8_codepoint.sol index 5e406d0c6..ea13293a2 100644 --- a/test/libsolidity/syntaxTests/string/large_utf8_codepoint.sol +++ b/test/libsolidity/syntaxTests/string/large_utf8_codepoint.sol @@ -1,3 +1,4 @@ contract C { string s = "\xf0\x9f\xa6\x84"; } +// ---- diff --git a/test/libsolidity/syntaxTests/string/string_ascii.sol b/test/libsolidity/syntaxTests/string/string_ascii.sol new file mode 100644 index 000000000..47014df53 --- /dev/null +++ b/test/libsolidity/syntaxTests/string/string_ascii.sol @@ -0,0 +1,9 @@ +contract test { + function f() public pure returns (string memory) { + return "hello world"; + } + function g() public pure returns (string memory) { + return unicode"hello world"; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/string/string_multipart_unicode.sol b/test/libsolidity/syntaxTests/string/string_multipart_unicode.sol new file mode 100644 index 000000000..669413992 --- /dev/null +++ b/test/libsolidity/syntaxTests/string/string_multipart_unicode.sol @@ -0,0 +1,7 @@ +contract test { + function f() public pure returns (bytes32) { + bytes32 escapeCharacters = unicode"foo" unicode"😃, 😭, and 😈" unicode"!"; + return escapeCharacters; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/string/string_multipart_unicode_mixed.sol b/test/libsolidity/syntaxTests/string/string_multipart_unicode_mixed.sol new file mode 100644 index 000000000..6264799bd --- /dev/null +++ b/test/libsolidity/syntaxTests/string/string_multipart_unicode_mixed.sol @@ -0,0 +1,8 @@ +contract test { + function f() public pure returns (bytes32) { + bytes32 escapeCharacters = "foo" hex"aa" unicode"😃, 😭, and 😈" "!" hex"00"; + return escapeCharacters; + } +} +// ---- +// ParserError 2314: (106-113): Expected ';' but got 'HexStringLiteral' diff --git a/test/libsolidity/syntaxTests/string/string_unicode.sol b/test/libsolidity/syntaxTests/string/string_unicode.sol index a204e84e5..0f70121be 100644 --- a/test/libsolidity/syntaxTests/string/string_unicode.sol +++ b/test/libsolidity/syntaxTests/string/string_unicode.sol @@ -1,7 +1,6 @@ contract test { function f() public pure returns (string memory) { - return "😃, 😭, and 😈"; + return unicode"😃, 😭, and 😈"; } } // ---- -// ParserError 8936: (86-88): Invalid character in string. diff --git a/test/libsolidity/syntaxTests/string/string_unicode_without_prefix.sol b/test/libsolidity/syntaxTests/string/string_unicode_without_prefix.sol new file mode 100644 index 000000000..a204e84e5 --- /dev/null +++ b/test/libsolidity/syntaxTests/string/string_unicode_without_prefix.sol @@ -0,0 +1,7 @@ +contract test { + function f() public pure returns (string memory) { + return "😃, 😭, and 😈"; + } +} +// ---- +// ParserError 8936: (86-88): Invalid character in string. diff --git a/test/libsolidity/syntaxTests/string/unicode_escape_literals.sol b/test/libsolidity/syntaxTests/string/unicode_escape_literals.sol index 011f58b40..c3e419265 100644 --- a/test/libsolidity/syntaxTests/string/unicode_escape_literals.sol +++ b/test/libsolidity/syntaxTests/string/unicode_escape_literals.sol @@ -19,3 +19,4 @@ contract test { return res; } } +// ----