diff --git a/Changelog.md b/Changelog.md index 693874608..a86b3ac59 100644 --- a/Changelog.md +++ b/Changelog.md @@ -14,6 +14,7 @@ Bugfixes: * isoltest: Added new keyword `wei` to express function value in semantic tests * Standard-JSON-Interface: Fix a bug related to empty filenames and imports. * SMTChecker: Fix internal errors when analysing tuples. + * Yul AST Import: correctly import blocks as statements, switch statements and string literals. ### 0.6.3 (2020-02-18) diff --git a/libsolidity/ast/AsmJsonImporter.cpp b/libsolidity/ast/AsmJsonImporter.cpp index a47ea27f7..302388841 100644 --- a/libsolidity/ast/AsmJsonImporter.cpp +++ b/libsolidity/ast/AsmJsonImporter.cpp @@ -104,6 +104,8 @@ yul::Statement AsmJsonImporter::createStatement(Json::Value const& _node) return createContinue(_node); else if (nodeType == "Leave") return createLeave(_node); + else if (nodeType == "Block") + return createBlock(_node); else astAssert(false, "Invalid nodeType as statement"); } @@ -158,10 +160,9 @@ yul::Literal AsmJsonImporter::createLiteral(Json::Value const& _node) lit.value = YulString{member(_node, "value").asString()}; lit.type= YulString{member(_node, "type").asString()}; - langutil::Scanner scanner{langutil::CharStream(lit.value.str(), "")}; - if (kind == "number") { + langutil::Scanner scanner{langutil::CharStream(lit.value.str(), "")}; lit.kind = yul::LiteralKind::Number; astAssert( scanner.currentToken() == Token::Number, @@ -170,6 +171,7 @@ yul::Literal AsmJsonImporter::createLiteral(Json::Value const& _node) } else if (kind == "bool") { + langutil::Scanner scanner{langutil::CharStream(lit.value.str(), "")}; lit.kind = yul::LiteralKind::Boolean; astAssert( scanner.currentToken() == Token::TrueLiteral || @@ -180,7 +182,10 @@ yul::Literal AsmJsonImporter::createLiteral(Json::Value const& _node) else if (kind == "string") { lit.kind = yul::LiteralKind::String; - astAssert(scanner.currentToken() == Token::StringLiteral, "Expected string literal!"); + astAssert( + lit.value.str().size() <= 32, + "String literal too long (" + to_string(lit.value.str().size()) + " > 32)" + ); } else solAssert(false, "unknown type of literal"); @@ -268,7 +273,11 @@ yul::If AsmJsonImporter::createIf(Json::Value const& _node) yul::Case AsmJsonImporter::createCase(Json::Value const& _node) { auto caseStatement = createAsmNode(_node); - caseStatement.value = member(_node, "value").asString() == "default" ? nullptr : make_unique(createLiteral(member(_node, "value"))); + auto const& value = member(_node, "value"); + if (value.isString()) + astAssert(value.asString() == "default", "Expected default case"); + else + caseStatement.value = make_unique(createLiteral(value)); caseStatement.body = createBlock(member(_node, "body")); return caseStatement; } @@ -276,7 +285,7 @@ yul::Case AsmJsonImporter::createCase(Json::Value const& _node) yul::Switch AsmJsonImporter::createSwitch(Json::Value const& _node) { auto switchStatement = createAsmNode(_node); - switchStatement.expression = make_unique(createExpression(member(_node, "value"))); + switchStatement.expression = make_unique(createExpression(member(_node, "expression"))); for (auto const& var: member(_node, "cases")) switchStatement.cases.emplace_back(createCase(var)); return switchStatement; diff --git a/scripts/ASTImportTest.sh b/scripts/ASTImportTest.sh index 800c5a514..f9172df0c 100755 --- a/scripts/ASTImportTest.sh +++ b/scripts/ASTImportTest.sh @@ -10,6 +10,7 @@ SOLC=${REPO_ROOT}/${SOLIDITY_BUILD_DIR}/solc/solc SPLITSOURCES=${REPO_ROOT}/scripts/splitSources.py SYNTAXTESTS_DIR="${REPO_ROOT}/test/libsolidity/syntaxTests" +ASTJSONTESTS_DIR="${REPO_ROOT}/test/libsolidity/ASTJSON" NSOURCES="$(find $SYNTAXTESTS_DIR -type f | wc -l)" # DEV_DIR="${REPO_ROOT}/../tmp/contracts/" @@ -75,7 +76,7 @@ echo "Looking at $NSOURCES .sol files..." WORKINGDIR=$PWD # for solfile in $(find $DEV_DIR -name *.sol) -for solfile in $(find $SYNTAXTESTS_DIR -name *.sol) +for solfile in $(find $SYNTAXTESTS_DIR $ASTJSONTESTS_DIR -name *.sol) do echo -n "." # create a temporary sub-directory diff --git a/test/libsolidity/ASTJSON/assembly/empty_block.json b/test/libsolidity/ASTJSON/assembly/empty_block.json new file mode 100644 index 000000000..575b1f7f4 --- /dev/null +++ b/test/libsolidity/ASTJSON/assembly/empty_block.json @@ -0,0 +1,95 @@ +{ + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 6 + ] + }, + "id": 7, + "nodeType": "SourceUnit", + "nodes": + [ + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "documentation": null, + "fullyImplemented": true, + "id": 6, + "linearizedBaseContracts": + [ + 6 + ], + "name": "C", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "body": + { + "id": 4, + "nodeType": "Block", + "src": "42:31:1", + "statements": + [ + { + "AST": + { + "nodeType": "YulBlock", + "src": "61:6:1", + "statements": + [ + { + "nodeType": "YulBlock", + "src": "63:2:1", + "statements": [] + } + ] + }, + "evmVersion": %EVMVERSION%, + "externalReferences": [], + "id": 3, + "nodeType": "InlineAssembly", + "src": "52:15:1" + } + ] + }, + "documentation": null, + "functionSelector": "e2179b8e", + "id": 5, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "g", + "nodeType": "FunctionDefinition", + "overrides": null, + "parameters": + { + "id": 1, + "nodeType": "ParameterList", + "parameters": [], + "src": "27:2:1" + }, + "returnParameters": + { + "id": 2, + "nodeType": "ParameterList", + "parameters": [], + "src": "42:0:1" + }, + "scope": 6, + "src": "17:56:1", + "stateMutability": "view", + "virtual": false, + "visibility": "public" + } + ], + "scope": 7, + "src": "0:75:1" + } + ], + "src": "0:76:1" +} diff --git a/test/libsolidity/ASTJSON/assembly/empty_block.sol b/test/libsolidity/ASTJSON/assembly/empty_block.sol new file mode 100644 index 000000000..23c2babbe --- /dev/null +++ b/test/libsolidity/ASTJSON/assembly/empty_block.sol @@ -0,0 +1,7 @@ +contract C { + function g() view public { + assembly { {} } + } +} + +// ---- diff --git a/test/libsolidity/ASTJSON/assembly/empty_block_legacy.json b/test/libsolidity/ASTJSON/assembly/empty_block_legacy.json new file mode 100644 index 000000000..108a76a00 --- /dev/null +++ b/test/libsolidity/ASTJSON/assembly/empty_block_legacy.json @@ -0,0 +1,123 @@ +{ + "attributes": + { + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 6 + ] + } + }, + "children": + [ + { + "attributes": + { + "abstract": false, + "baseContracts": + [ + null + ], + "contractDependencies": + [ + null + ], + "contractKind": "contract", + "documentation": null, + "fullyImplemented": true, + "linearizedBaseContracts": + [ + 6 + ], + "name": "C", + "scope": 7 + }, + "children": + [ + { + "attributes": + { + "documentation": null, + "functionSelector": "e2179b8e", + "implemented": true, + "isConstructor": false, + "kind": "function", + "modifiers": + [ + null + ], + "name": "g", + "overrides": null, + "scope": 6, + "stateMutability": "view", + "virtual": false, + "visibility": "public" + }, + "children": + [ + { + "attributes": + { + "parameters": + [ + null + ] + }, + "children": [], + "id": 1, + "name": "ParameterList", + "src": "27:2:1" + }, + { + "attributes": + { + "parameters": + [ + null + ] + }, + "children": [], + "id": 2, + "name": "ParameterList", + "src": "42:0:1" + }, + { + "children": + [ + { + "attributes": + { + "evmVersion": %EVMVERSION%, + "externalReferences": + [ + null + ], + "operations": "{ { } }" + }, + "children": [], + "id": 3, + "name": "InlineAssembly", + "src": "52:15:1" + } + ], + "id": 4, + "name": "Block", + "src": "42:31:1" + } + ], + "id": 5, + "name": "FunctionDefinition", + "src": "17:56:1" + } + ], + "id": 6, + "name": "ContractDefinition", + "src": "0:75:1" + } + ], + "id": 7, + "name": "SourceUnit", + "src": "0:76:1" +} diff --git a/test/libsolidity/ASTJSON/assembly/switch_default.json b/test/libsolidity/ASTJSON/assembly/switch_default.json new file mode 100644 index 000000000..c0bf26438 --- /dev/null +++ b/test/libsolidity/ASTJSON/assembly/switch_default.json @@ -0,0 +1,116 @@ +{ + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 6 + ] + }, + "id": 7, + "nodeType": "SourceUnit", + "nodes": + [ + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "documentation": null, + "fullyImplemented": true, + "id": 6, + "linearizedBaseContracts": + [ + 6 + ], + "name": "C", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "body": + { + "id": 4, + "nodeType": "Block", + "src": "42:48:1", + "statements": + [ + { + "AST": + { + "nodeType": "YulBlock", + "src": "61:23:1", + "statements": + [ + { + "cases": + [ + { + "body": + { + "nodeType": "YulBlock", + "src": "80:2:1", + "statements": [] + }, + "nodeType": "YulCase", + "src": "72:10:1", + "value": "default" + } + ], + "expression": + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "70:1:1", + "type": "", + "value": "0" + }, + "nodeType": "YulSwitch", + "src": "63:19:1" + } + ] + }, + "evmVersion": %EVMVERSION%, + "externalReferences": [], + "id": 3, + "nodeType": "InlineAssembly", + "src": "52:32:1" + } + ] + }, + "documentation": null, + "functionSelector": "e2179b8e", + "id": 5, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "g", + "nodeType": "FunctionDefinition", + "overrides": null, + "parameters": + { + "id": 1, + "nodeType": "ParameterList", + "parameters": [], + "src": "27:2:1" + }, + "returnParameters": + { + "id": 2, + "nodeType": "ParameterList", + "parameters": [], + "src": "42:0:1" + }, + "scope": 6, + "src": "17:73:1", + "stateMutability": "view", + "virtual": false, + "visibility": "public" + } + ], + "scope": 7, + "src": "0:92:1" + } + ], + "src": "0:93:1" +} diff --git a/test/libsolidity/ASTJSON/assembly/switch_default.sol b/test/libsolidity/ASTJSON/assembly/switch_default.sol new file mode 100644 index 000000000..8bfba2c11 --- /dev/null +++ b/test/libsolidity/ASTJSON/assembly/switch_default.sol @@ -0,0 +1,7 @@ +contract C { + function g() view public { + assembly { switch 0 default {} } + } +} + +// ---- diff --git a/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json b/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json new file mode 100644 index 000000000..2d5caa0fa --- /dev/null +++ b/test/libsolidity/ASTJSON/assembly/switch_default_legacy.json @@ -0,0 +1,123 @@ +{ + "attributes": + { + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 6 + ] + } + }, + "children": + [ + { + "attributes": + { + "abstract": false, + "baseContracts": + [ + null + ], + "contractDependencies": + [ + null + ], + "contractKind": "contract", + "documentation": null, + "fullyImplemented": true, + "linearizedBaseContracts": + [ + 6 + ], + "name": "C", + "scope": 7 + }, + "children": + [ + { + "attributes": + { + "documentation": null, + "functionSelector": "e2179b8e", + "implemented": true, + "isConstructor": false, + "kind": "function", + "modifiers": + [ + null + ], + "name": "g", + "overrides": null, + "scope": 6, + "stateMutability": "view", + "virtual": false, + "visibility": "public" + }, + "children": + [ + { + "attributes": + { + "parameters": + [ + null + ] + }, + "children": [], + "id": 1, + "name": "ParameterList", + "src": "27:2:1" + }, + { + "attributes": + { + "parameters": + [ + null + ] + }, + "children": [], + "id": 2, + "name": "ParameterList", + "src": "42:0:1" + }, + { + "children": + [ + { + "attributes": + { + "evmVersion": %EVMVERSION%, + "externalReferences": + [ + null + ], + "operations": "{\n switch 0\n default { }\n}" + }, + "children": [], + "id": 3, + "name": "InlineAssembly", + "src": "52:32:1" + } + ], + "id": 4, + "name": "Block", + "src": "42:48:1" + } + ], + "id": 5, + "name": "FunctionDefinition", + "src": "17:73:1" + } + ], + "id": 6, + "name": "ContractDefinition", + "src": "0:92:1" + } + ], + "id": 7, + "name": "SourceUnit", + "src": "0:93:1" +}