/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see <http://www.gnu.org/licenses/>. */ // SPDX-License-Identifier: GPL-3.0 /** * @author julius <djudju@protonmail.com> * @date 2019 *Component that imports an AST from json format to the internal format */ #include <libsolidity/ast/ASTJsonImporter.h> #include <libsolidity/ast/AsmJsonImporter.h> #include <liblangutil/Scanner.h> #include <libyul/Dialect.h> #include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string.hpp> #include <liblangutil/Token.h> #include <libyul/AsmParser.h> #include <libyul/backends/evm/EVMDialect.h> #include <liblangutil/SourceLocation.h> #include <liblangutil/Exceptions.h> #include <liblangutil/ErrorReporter.h> using namespace std; namespace solidity::frontend { using SourceLocation = langutil::SourceLocation; template<class T> ASTPointer<T> ASTJsonImporter::nullOrCast(Json::Value const& _json) { if (_json.isNull()) return nullptr; else return dynamic_pointer_cast<T>(convertJsonToASTNode(_json)); } // ============ public =========================== map<string, ASTPointer<SourceUnit>> ASTJsonImporter::jsonToSourceUnit(map<string, Json::Value> const& _sourceList) { m_sourceList = _sourceList; for (auto const& src: _sourceList) m_sourceLocations.emplace_back(make_shared<string const>(src.first)); for (auto const& srcPair: m_sourceList) { astAssert(!srcPair.second.isNull(), ""); astAssert(member(srcPair.second,"nodeType") == "SourceUnit", "The 'nodeType' of the highest node must be 'SourceUnit'."); m_currentSourceName = srcPair.first; m_sourceUnits[srcPair.first] = createSourceUnit(srcPair.second, srcPair.first); } return m_sourceUnits; } // ============ private =========================== // =========== general creation functions ============== template <typename T, typename... Args> ASTPointer<T> ASTJsonImporter::createASTNode(Json::Value const& _node, Args&&... _args) { astAssert(member(_node, "id").isInt64(), "'id'-field must be 64bit integer."); int64_t id = _node["id"].asInt64(); astAssert(m_usedIDs.insert(id).second, "Found duplicate node ID!"); auto n = make_shared<T>( id, createSourceLocation(_node), forward<Args>(_args)... ); return n; } SourceLocation const ASTJsonImporter::createSourceLocation(Json::Value const& _node) { astAssert(member(_node, "src").isString(), "'src' must be a string"); return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_currentSourceName, m_sourceLocations.size()); } template<class T> ASTPointer<T> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _node) { ASTPointer<T> ret = dynamic_pointer_cast<T>(convertJsonToASTNode(_node)); astAssert(ret, "cast of converted json-node must not be nullptr"); return ret; } ASTPointer<ASTNode> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _json) { astAssert(_json["nodeType"].isString() && _json.isMember("id"), "JSON-Node needs to have 'nodeType' and 'id' fields."); string nodeType = _json["nodeType"].asString(); if (nodeType == "PragmaDirective") return createPragmaDirective(_json); if (nodeType == "ImportDirective") return createImportDirective(_json); if (nodeType == "ContractDefinition") return createContractDefinition(_json); if (nodeType == "InheritanceSpecifier") return createInheritanceSpecifier(_json); if (nodeType == "UsingForDirective") return createUsingForDirective(_json); if (nodeType == "StructDefinition") return createStructDefinition(_json); if (nodeType == "EnumDefinition") return createEnumDefinition(_json); if (nodeType == "EnumValue") return createEnumValue(_json); if (nodeType == "ParameterList") return createParameterList(_json); if (nodeType == "OverrideSpecifier") return createOverrideSpecifier(_json); if (nodeType == "FunctionDefinition") return createFunctionDefinition(_json); if (nodeType == "VariableDeclaration") return createVariableDeclaration(_json); if (nodeType == "ModifierDefinition") return createModifierDefinition(_json); if (nodeType == "ModifierInvocation") return createModifierInvocation(_json); if (nodeType == "EventDefinition") return createEventDefinition(_json); if (nodeType == "ElementaryTypeName") return createElementaryTypeName(_json); if (nodeType == "UserDefinedTypeName") return createUserDefinedTypeName(_json); if (nodeType == "FunctionTypeName") return createFunctionTypeName(_json); if (nodeType == "Mapping") return createMapping(_json); if (nodeType == "ArrayTypeName") return createArrayTypeName(_json); if (nodeType == "InlineAssembly") return createInlineAssembly(_json); if (nodeType == "Block") return createBlock(_json); if (nodeType == "PlaceholderStatement") return createPlaceholderStatement(_json); if (nodeType == "IfStatement") return createIfStatement(_json); if (nodeType == "TryCatchClause") return createTryCatchClause(_json); if (nodeType == "TryStatement") return createTryStatement(_json); if (nodeType == "WhileStatement") return createWhileStatement(_json, false); if (nodeType == "DoWhileStatement") return createWhileStatement(_json, true); if (nodeType == "ForStatement") return createForStatement(_json); if (nodeType == "Continue") return createContinue(_json); if (nodeType == "Break") return createBreak(_json); if (nodeType == "Return") return createReturn(_json); if (nodeType == "EmitStatement") return createEmitStatement(_json); if (nodeType == "Throw") return createThrow(_json); if (nodeType == "VariableDeclarationStatement") return createVariableDeclarationStatement(_json); if (nodeType == "ExpressionStatement") return createExpressionStatement(_json); if (nodeType == "Conditional") return createConditional(_json); if (nodeType == "Assignment") return createAssignment(_json); if (nodeType == "TupleExpression") return createTupleExpression(_json); if (nodeType == "UnaryOperation") return createUnaryOperation(_json); if (nodeType == "BinaryOperation") return createBinaryOperation(_json); if (nodeType == "FunctionCall") return createFunctionCall(_json); if (nodeType == "FunctionCallOptions") return createFunctionCallOptions(_json); if (nodeType == "NewExpression") return createNewExpression(_json); if (nodeType == "MemberAccess") return createMemberAccess(_json); if (nodeType == "IndexAccess") return createIndexAccess(_json); if (nodeType == "IndexRangeAccess") return createIndexRangeAccess(_json); if (nodeType == "Identifier") return createIdentifier(_json); if (nodeType == "ElementaryTypeNameExpression") return createElementaryTypeNameExpression(_json); if (nodeType == "Literal") return createLiteral(_json); if (nodeType == "StructuredDocumentation") return createDocumentation(_json); else astAssert(false, "Unknown type of ASTNode: " + nodeType); } // ============ functions to instantiate the AST-Nodes from Json-Nodes ============== ASTPointer<SourceUnit> ASTJsonImporter::createSourceUnit(Json::Value const& _node, string const& _srcName) { optional<string> license; if (_node.isMember("license") && !_node["license"].isNull()) license = _node["license"].asString(); vector<ASTPointer<ASTNode>> nodes; for (auto& child: member(_node, "nodes")) nodes.emplace_back(convertJsonToASTNode(child)); ASTPointer<SourceUnit> tmp = createASTNode<SourceUnit>(_node, license, nodes); tmp->annotation().path = _srcName; return tmp; } ASTPointer<PragmaDirective> ASTJsonImporter::createPragmaDirective(Json::Value const& _node) { vector<Token> tokens; vector<ASTString> literals; for (auto const& lit: member(_node, "literals")) { string l = lit.asString(); literals.push_back(l); tokens.push_back(scanSingleToken(l)); } return createASTNode<PragmaDirective>(_node, tokens, literals); } ASTPointer<ImportDirective> ASTJsonImporter::createImportDirective(Json::Value const& _node) { ASTPointer<ASTString> unitAlias = memberAsASTString(_node, "unitAlias"); ASTPointer<ASTString> path = memberAsASTString(_node, "file"); ImportDirective::SymbolAliasList symbolAliases; for (auto& tuple: member(_node, "symbolAliases")) { astAssert(tuple["local"].isNull() || tuple["local"].isString(), "expected 'local' to be a string or null!"); symbolAliases.push_back({ createIdentifier(tuple["foreign"]), tuple["local"].isNull() ? nullptr : make_shared<ASTString>(tuple["local"].asString()), createSourceLocation(tuple["foreign"])} ); } ASTPointer<ImportDirective> tmp = createASTNode<ImportDirective>( _node, path, unitAlias, move(symbolAliases) ); astAssert(_node["absolutePath"].isString(), "Expected 'absolutePath' to be a string!"); tmp->annotation().absolutePath = _node["absolutePath"].asString(); return tmp; } ASTPointer<ContractDefinition> ASTJsonImporter::createContractDefinition(Json::Value const& _node) { astAssert(_node["name"].isString(), "Expected 'name' to be a string!"); std::vector<ASTPointer<InheritanceSpecifier>> baseContracts; for (auto& base: _node["baseContracts"]) baseContracts.push_back(createInheritanceSpecifier(base)); std::vector<ASTPointer<ASTNode>> subNodes; for (auto& subnode: _node["nodes"]) subNodes.push_back(convertJsonToASTNode(subnode)); return createASTNode<ContractDefinition>( _node, make_shared<ASTString>(_node["name"].asString()), _node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")), baseContracts, subNodes, contractKind(_node), memberAsBool(_node, "abstract") ); } ASTPointer<InheritanceSpecifier> ASTJsonImporter::createInheritanceSpecifier(Json::Value const& _node) { std::vector<ASTPointer<Expression>> arguments; for (auto& arg: member(_node, "arguments")) arguments.push_back(convertJsonToASTNode<Expression>(arg)); return createASTNode<InheritanceSpecifier>( _node, createUserDefinedTypeName(member(_node, "baseName")), member(_node, "arguments").isNull() ? nullptr : make_unique<std::vector<ASTPointer<Expression>>>(arguments) ); } ASTPointer<UsingForDirective> ASTJsonImporter::createUsingForDirective(Json::Value const& _node) { return createASTNode<UsingForDirective>( _node, createUserDefinedTypeName(member(_node, "libraryName")), _node["typeName"].isNull() ? nullptr : convertJsonToASTNode<TypeName>(_node["typeName"]) ); } ASTPointer<ASTNode> ASTJsonImporter::createStructDefinition(Json::Value const& _node) { std::vector<ASTPointer<VariableDeclaration>> members; for (auto& member: _node["members"]) members.push_back(createVariableDeclaration(member)); return createASTNode<StructDefinition>( _node, memberAsASTString(_node, "name"), members ); } ASTPointer<EnumDefinition> ASTJsonImporter::createEnumDefinition(Json::Value const& _node) { std::vector<ASTPointer<EnumValue>> members; for (auto& member: _node["members"]) members.push_back(createEnumValue(member)); return createASTNode<EnumDefinition>( _node, memberAsASTString(_node, "name"), members ); } ASTPointer<EnumValue> ASTJsonImporter::createEnumValue(Json::Value const& _node) { return createASTNode<EnumValue>( _node, memberAsASTString(_node, "name") ); } ASTPointer<ParameterList> ASTJsonImporter::createParameterList(Json::Value const& _node) { std::vector<ASTPointer<VariableDeclaration>> parameters; for (auto& param: _node["parameters"]) parameters.push_back(createVariableDeclaration(param)); return createASTNode<ParameterList>( _node, parameters ); } ASTPointer<OverrideSpecifier> ASTJsonImporter::createOverrideSpecifier(Json::Value const& _node) { std::vector<ASTPointer<UserDefinedTypeName>> overrides; for (auto& param: _node["overrides"]) overrides.push_back(createUserDefinedTypeName(param)); return createASTNode<OverrideSpecifier>( _node, overrides ); } ASTPointer<FunctionDefinition> ASTJsonImporter::createFunctionDefinition(Json::Value const& _node) { astAssert(_node["kind"].isString(), "Expected 'kind' to be a string!"); Token kind; bool freeFunction = false; string kindStr = member(_node, "kind").asString(); if (kindStr == "constructor") kind = Token::Constructor; else if (kindStr == "function") kind = Token::Function; else if (kindStr == "fallback") kind = Token::Fallback; else if (kindStr == "receive") kind = Token::Receive; else if (kindStr == "freeFunction") { kind = Token::Function; freeFunction = true; } else astAssert(false, "Expected 'kind' to be one of [constructor, function, fallback, receive]"); std::vector<ASTPointer<ModifierInvocation>> modifiers; for (auto& mod: member(_node, "modifiers")) modifiers.push_back(createModifierInvocation(mod)); Visibility vis = Visibility::Default; if (!freeFunction) vis = visibility(_node); return createASTNode<FunctionDefinition>( _node, memberAsASTString(_node, "name"), vis, stateMutability(_node), freeFunction, kind, memberAsBool(_node, "virtual"), _node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")), _node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")), createParameterList(member(_node, "parameters")), modifiers, createParameterList(member(_node, "returnParameters")), memberAsBool(_node, "implemented") ? createBlock(member(_node, "body")) : nullptr ); } ASTPointer<VariableDeclaration> ASTJsonImporter::createVariableDeclaration(Json::Value const& _node) { astAssert(_node["name"].isString(), "Expected 'name' to be a string!"); VariableDeclaration::Mutability mutability{}; astAssert(member(_node, "mutability").isString(), "'mutability' expected to be string."); string const mutabilityStr = member(_node, "mutability").asString(); if (mutabilityStr == "constant") { mutability = VariableDeclaration::Mutability::Constant; astAssert(memberAsBool(_node, "constant"), ""); } else { astAssert(!memberAsBool(_node, "constant"), ""); if (mutabilityStr == "mutable") mutability = VariableDeclaration::Mutability::Mutable; else if (mutabilityStr == "immutable") mutability = VariableDeclaration::Mutability::Immutable; else astAssert(false, ""); } return createASTNode<VariableDeclaration>( _node, nullOrCast<TypeName>(member(_node, "typeName")), make_shared<ASTString>(member(_node, "name").asString()), nullOrCast<Expression>(member(_node, "value")), visibility(_node), _node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")), _node.isMember("indexed") ? memberAsBool(_node, "indexed") : false, mutability, _node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")), location(_node) ); } ASTPointer<ModifierDefinition> ASTJsonImporter::createModifierDefinition(Json::Value const& _node) { return createASTNode<ModifierDefinition>( _node, memberAsASTString(_node, "name"), _node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")), createParameterList(member(_node, "parameters")), memberAsBool(_node, "virtual"), _node["overrides"].isNull() ? nullptr : createOverrideSpecifier(member(_node, "overrides")), _node["body"].isNull() ? nullptr: createBlock(member(_node, "body")) ); } ASTPointer<ModifierInvocation> ASTJsonImporter::createModifierInvocation(Json::Value const& _node) { std::vector<ASTPointer<Expression>> arguments; for (auto& arg: member(_node, "arguments")) arguments.push_back(convertJsonToASTNode<Expression>(arg)); return createASTNode<ModifierInvocation>( _node, createIdentifier(member(_node, "modifierName")), member(_node, "arguments").isNull() ? nullptr : make_unique<std::vector<ASTPointer<Expression>>>(arguments) ); } ASTPointer<EventDefinition> ASTJsonImporter::createEventDefinition(Json::Value const& _node) { return createASTNode<EventDefinition>( _node, memberAsASTString(_node, "name"), _node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")), createParameterList(member(_node, "parameters")), memberAsBool(_node, "anonymous") ); } ASTPointer<ElementaryTypeName> ASTJsonImporter::createElementaryTypeName(Json::Value const& _node) { unsigned short firstNum; unsigned short secondNum; astAssert(_node["name"].isString(), "Expected 'name' to be a string!"); string name = member(_node, "name").asString(); Token token; tie(token, firstNum, secondNum) = TokenTraits::fromIdentifierOrKeyword(name); ElementaryTypeNameToken elem(token, firstNum, secondNum); std::optional<StateMutability> mutability = {}; if (_node.isMember("stateMutability")) mutability = stateMutability(_node); return createASTNode<ElementaryTypeName>(_node, elem, mutability); } ASTPointer<UserDefinedTypeName> ASTJsonImporter::createUserDefinedTypeName(Json::Value const& _node) { astAssert(_node["name"].isString(), "Expected 'name' to be a string!"); vector<ASTString> namePath; vector<string> strs; string nameString = member(_node, "name").asString(); boost::algorithm::split(strs, nameString, boost::is_any_of(".")); for (string s: strs) namePath.emplace_back(s); return createASTNode<UserDefinedTypeName>( _node, namePath ); } ASTPointer<FunctionTypeName> ASTJsonImporter::createFunctionTypeName(Json::Value const& _node) { return createASTNode<FunctionTypeName>( _node, createParameterList(member(_node, "parameterTypes")), createParameterList(member(_node, "returnParameterTypes")), visibility(_node), stateMutability(_node) ); } ASTPointer<Mapping> ASTJsonImporter::createMapping(Json::Value const& _node) { return createASTNode<Mapping>( _node, convertJsonToASTNode<TypeName>(member(_node, "keyType")), convertJsonToASTNode<TypeName>(member(_node, "valueType")) ); } ASTPointer<ArrayTypeName> ASTJsonImporter::createArrayTypeName(Json::Value const& _node) { return createASTNode<ArrayTypeName>( _node, convertJsonToASTNode<TypeName>(member(_node, "baseType")), nullOrCast<Expression>(member(_node, "length")) ); } ASTPointer<InlineAssembly> ASTJsonImporter::createInlineAssembly(Json::Value const& _node) { astAssert(_node["evmVersion"].isString(), "Expected evmVersion to be a string!"); auto evmVersion = langutil::EVMVersion::fromString(_node["evmVersion"].asString()); astAssert(evmVersion.has_value(), "Invalid EVM version!"); astAssert(m_evmVersion == evmVersion, "Imported tree evm version differs from configured evm version!"); yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(evmVersion.value()); shared_ptr<yul::Block> operations = make_shared<yul::Block>(AsmJsonImporter(m_currentSourceName).createBlock(member(_node, "AST"))); return createASTNode<InlineAssembly>( _node, nullOrASTString(_node, "documentation"), dialect, operations ); } ASTPointer<Block> ASTJsonImporter::createBlock(Json::Value const& _node) { std::vector<ASTPointer<Statement>> statements; for (auto& stat: member(_node, "statements")) statements.push_back(convertJsonToASTNode<Statement>(stat)); return createASTNode<Block>( _node, nullOrASTString(_node, "documentation"), statements ); } ASTPointer<PlaceholderStatement> ASTJsonImporter::createPlaceholderStatement(Json::Value const& _node) { return createASTNode<PlaceholderStatement>( _node, nullOrASTString(_node, "documentation") ); } ASTPointer<IfStatement> ASTJsonImporter::createIfStatement(Json::Value const& _node) { return createASTNode<IfStatement>( _node, nullOrASTString(_node, "documentation"), convertJsonToASTNode<Expression>(member(_node, "condition")), convertJsonToASTNode<Statement>(member(_node, "trueBody")), nullOrCast<Statement>(member(_node, "falseBody")) ); } ASTPointer<TryCatchClause> ASTJsonImporter::createTryCatchClause(Json::Value const& _node) { return createASTNode<TryCatchClause>( _node, memberAsASTString(_node, "errorName"), nullOrCast<ParameterList>(member(_node, "parameters")), convertJsonToASTNode<Block>(member(_node, "block")) ); } ASTPointer<TryStatement> ASTJsonImporter::createTryStatement(Json::Value const& _node) { vector<ASTPointer<TryCatchClause>> clauses; for (auto& param: _node["clauses"]) clauses.emplace_back(createTryCatchClause(param)); return createASTNode<TryStatement>( _node, nullOrASTString(_node, "documentation"), convertJsonToASTNode<Expression>(member(_node, "externalCall")), clauses ); } ASTPointer<WhileStatement> ASTJsonImporter::createWhileStatement(Json::Value const& _node, bool _isDoWhile=false) { return createASTNode<WhileStatement>( _node, nullOrASTString(_node, "documentation"), convertJsonToASTNode<Expression>(member(_node, "condition")), convertJsonToASTNode<Statement>(member(_node, "body")), _isDoWhile ); } ASTPointer<ForStatement> ASTJsonImporter::createForStatement(Json::Value const& _node) { return createASTNode<ForStatement>( _node, nullOrASTString(_node, "documentation"), nullOrCast<Statement>(member(_node, "initializationExpression")), nullOrCast<Expression>(member(_node, "condition")), nullOrCast<ExpressionStatement>(member(_node, "loopExpression")), convertJsonToASTNode<Statement>(member(_node, "body")) ); } ASTPointer<Continue> ASTJsonImporter::createContinue(Json::Value const& _node) { return createASTNode<Continue>( _node, nullOrASTString(_node, "documentation") ); } ASTPointer<Break> ASTJsonImporter::createBreak(Json::Value const& _node) { return createASTNode<Break>( _node, nullOrASTString(_node, "documentation") ); } ASTPointer<Return> ASTJsonImporter::createReturn(Json::Value const& _node) { return createASTNode<Return>( _node, nullOrASTString(_node, "documentation"), nullOrCast<Expression>(member(_node, "expression")) ); } ASTPointer<Throw> ASTJsonImporter::createThrow(Json::Value const& _node) { return createASTNode<Throw>( _node, nullOrASTString(_node, "documentation") ); } ASTPointer<EmitStatement> ASTJsonImporter::createEmitStatement(Json::Value const& _node) { return createASTNode<EmitStatement>( _node, nullOrASTString(_node, "documentation"), createFunctionCall(member(_node, "eventCall")) ); } ASTPointer<VariableDeclarationStatement> ASTJsonImporter::createVariableDeclarationStatement(Json::Value const& _node) { std::vector<ASTPointer<VariableDeclaration>> variables; for (auto& var: member(_node, "declarations")) variables.push_back(var.isNull() ? nullptr : createVariableDeclaration(var)); //unnamed components are empty pointers return createASTNode<VariableDeclarationStatement>( _node, nullOrASTString(_node, "documentation"), variables, nullOrCast<Expression>(member(_node, "initialValue")) ); } ASTPointer<ExpressionStatement> ASTJsonImporter::createExpressionStatement(Json::Value const& _node) { return createASTNode<ExpressionStatement>( _node, nullOrASTString(_node, "documentation"), convertJsonToASTNode<Expression>(member(_node, "expression")) ); } ASTPointer<Conditional> ASTJsonImporter::createConditional(Json::Value const& _node) { return createASTNode<Conditional>( _node, convertJsonToASTNode<Expression>(member(_node, "condition")), convertJsonToASTNode<Expression>(member(_node, "trueExpression")), convertJsonToASTNode<Expression>(member(_node, "falseExpression")) ); } ASTPointer<Assignment> ASTJsonImporter::createAssignment(Json::Value const& _node) { return createASTNode<Assignment>( _node, convertJsonToASTNode<Expression>(member(_node, "leftHandSide")), scanSingleToken(member(_node, "operator")), convertJsonToASTNode<Expression>(member(_node, "rightHandSide")) ); } ASTPointer<TupleExpression> ASTJsonImporter::createTupleExpression(Json::Value const& _node) { std::vector<ASTPointer<Expression>> components; for (auto& comp: member(_node, "components")) components.push_back(nullOrCast<Expression>(comp)); return createASTNode<TupleExpression>( _node, components, memberAsBool(_node, "isInlineArray") ); } ASTPointer<UnaryOperation> ASTJsonImporter::createUnaryOperation(Json::Value const& _node) { return createASTNode<UnaryOperation>( _node, scanSingleToken(member(_node, "operator")), convertJsonToASTNode<Expression>(member(_node, "subExpression")), memberAsBool(_node, "prefix") ); } ASTPointer<BinaryOperation> ASTJsonImporter::createBinaryOperation(Json::Value const& _node) { return createASTNode<BinaryOperation>( _node, convertJsonToASTNode<Expression>(member(_node, "leftExpression")), scanSingleToken(member(_node, "operator")), convertJsonToASTNode<Expression>(member(_node, "rightExpression")) ); } ASTPointer<FunctionCall> ASTJsonImporter::createFunctionCall(Json::Value const& _node) { std::vector<ASTPointer<Expression>> arguments; for (auto& arg: member(_node, "arguments")) arguments.push_back(convertJsonToASTNode<Expression>(arg)); std::vector<ASTPointer<ASTString>> names; for (auto& name: member(_node, "names")) { astAssert(name.isString(), "Expected 'names' members to be strings!"); names.push_back(make_shared<ASTString>(name.asString())); } return createASTNode<FunctionCall>( _node, convertJsonToASTNode<Expression>(member(_node, "expression")), arguments, names ); } ASTPointer<FunctionCallOptions> ASTJsonImporter::createFunctionCallOptions(Json::Value const& _node) { std::vector<ASTPointer<Expression>> options; for (auto& option: member(_node, "options")) options.push_back(convertJsonToASTNode<Expression>(option)); std::vector<ASTPointer<ASTString>> names; for (auto& name: member(_node, "names")) { astAssert(name.isString(), "Expected 'names' members to be strings!"); names.push_back(make_shared<ASTString>(name.asString())); } return createASTNode<FunctionCallOptions>( _node, convertJsonToASTNode<Expression>(member(_node, "expression")), options, names ); } ASTPointer<NewExpression> ASTJsonImporter::createNewExpression(Json::Value const& _node) { return createASTNode<NewExpression>( _node, convertJsonToASTNode<TypeName>(member(_node, "typeName")) ); } ASTPointer<MemberAccess> ASTJsonImporter::createMemberAccess(Json::Value const& _node) { return createASTNode<MemberAccess>( _node, convertJsonToASTNode<Expression>(member(_node, "expression")), memberAsASTString(_node, "memberName") ); } ASTPointer<IndexAccess> ASTJsonImporter::createIndexAccess(Json::Value const& _node) { return createASTNode<IndexAccess>( _node, convertJsonToASTNode<Expression>(member(_node, "baseExpression")), nullOrCast<Expression>(member(_node, "indexExpression")) ); } ASTPointer<IndexRangeAccess> ASTJsonImporter::createIndexRangeAccess(Json::Value const& _node) { return createASTNode<IndexRangeAccess>( _node, convertJsonToASTNode<Expression>(member(_node, "baseExpression")), nullOrCast<Expression>(member(_node, "startExpression")), nullOrCast<Expression>(member(_node, "endExpression")) ); } ASTPointer<Identifier> ASTJsonImporter::createIdentifier(Json::Value const& _node) { return createASTNode<Identifier>(_node, memberAsASTString(_node, "name")); } ASTPointer<ElementaryTypeNameExpression> ASTJsonImporter::createElementaryTypeNameExpression(Json::Value const& _node) { return createASTNode<ElementaryTypeNameExpression>( _node, createElementaryTypeName(member(_node, "typeName")) ); } ASTPointer<ASTNode> ASTJsonImporter::createLiteral(Json::Value const& _node) { static string const valStr = "value"; static string const hexValStr = "hexValue"; astAssert(member(_node, valStr).isString() || member(_node, hexValStr).isString(), "Literal-value is unset."); ASTPointer<ASTString> value = _node.isMember(hexValStr) ? make_shared<ASTString>(util::asString(util::fromHex(_node[hexValStr].asString()))) : make_shared<ASTString>(_node[valStr].asString()); return createASTNode<Literal>( _node, literalTokenKind(_node), value, member(_node, "subdenomination").isNull() ? Literal::SubDenomination::None : subdenomination(_node) ); } ASTPointer<StructuredDocumentation> ASTJsonImporter::createDocumentation(Json::Value const& _node) { static string const textString = "text"; astAssert(member(_node, textString).isString(), "'text' must be a string"); return createASTNode<StructuredDocumentation>( _node, make_shared<ASTString>(_node[textString].asString()) ); } // ===== helper functions ========== Json::Value ASTJsonImporter::member(Json::Value const& _node, string const& _name) { if (!_node.isMember(_name)) return Json::nullValue; return _node[_name]; } Token ASTJsonImporter::scanSingleToken(Json::Value const& _node) { langutil::Scanner scanner{langutil::CharStream(_node.asString(), "")}; astAssert(scanner.peekNextToken() == Token::EOS, "Token string is too long."); return scanner.currentToken(); } ASTPointer<ASTString> ASTJsonImporter::nullOrASTString(Json::Value const& _json, string const& _name) { return _json[_name].isString() ? memberAsASTString(_json, _name) : nullptr; } ASTPointer<ASTString> ASTJsonImporter::memberAsASTString(Json::Value const& _node, string const& _name) { Json::Value value = member(_node, _name); astAssert(value.isString(), "field " + _name + " must be of type string."); return make_shared<ASTString>(_node[_name].asString()); } bool ASTJsonImporter::memberAsBool(Json::Value const& _node, string const& _name) { Json::Value value = member(_node, _name); astAssert(value.isBool(), "field " + _name + " must be of type boolean."); return _node[_name].asBool(); } // =========== JSON to definition helpers ======================= ContractKind ASTJsonImporter::contractKind(Json::Value const& _node) { ContractKind kind; astAssert(!member(_node, "contractKind").isNull(), "'Contract-kind' can not be null."); if (_node["contractKind"].asString() == "interface") kind = ContractKind::Interface; else if (_node["contractKind"].asString() == "contract") kind = ContractKind::Contract; else if (_node["contractKind"].asString() == "library") kind = ContractKind::Library; else astAssert(false, "Unknown ContractKind"); return kind; } Token ASTJsonImporter::literalTokenKind(Json::Value const& _node) { astAssert(member(_node, "kind").isString(), "Token-'kind' expected to be a string."); Token tok; if (_node["kind"].asString() == "number") tok = Token::Number; else if (_node["kind"].asString() == "string") tok = Token::StringLiteral; else if (_node["kind"].asString() == "unicodeString") tok = Token::UnicodeStringLiteral; else if (_node["kind"].asString() == "hexString") tok = Token::HexStringLiteral; else if (_node["kind"].asString() == "bool") tok = (member(_node, "value").asString() == "true") ? Token::TrueLiteral : Token::FalseLiteral; else astAssert(false, "Unknown kind of literalString"); return tok; } Visibility ASTJsonImporter::visibility(Json::Value const& _node) { Json::Value visibility = member(_node, "visibility"); astAssert(visibility.isString(), "'visibility' expected to be a string."); string const visibilityStr = visibility.asString(); if (visibilityStr == "default") return Visibility::Default; else if (visibilityStr == "private") return Visibility::Private; else if ( visibilityStr == "internal") return Visibility::Internal; else if (visibilityStr == "public") return Visibility::Public; else if (visibilityStr == "external") return Visibility::External; else astAssert(false, "Unknown visibility declaration"); } VariableDeclaration::Location ASTJsonImporter::location(Json::Value const& _node) { Json::Value storageLoc = member(_node, "storageLocation"); astAssert(storageLoc.isString(), "'storageLocation' expected to be a string."); string const storageLocStr = storageLoc.asString(); if (storageLocStr == "default") return VariableDeclaration::Location::Unspecified; else if (storageLocStr == "storage") return VariableDeclaration::Location::Storage; else if (storageLocStr == "memory") return VariableDeclaration::Location::Memory; else if (storageLocStr == "calldata") return VariableDeclaration::Location::CallData; else astAssert(false, "Unknown location declaration"); } Literal::SubDenomination ASTJsonImporter::subdenomination(Json::Value const& _node) { Json::Value subDen = member(_node, "subdenomination"); if (subDen.isNull()) return Literal::SubDenomination::None; astAssert(subDen.isString(), "'subDenomination' expected to be string."); string const subDenStr = subDen.asString(); if (subDenStr == "wei") return Literal::SubDenomination::Wei; else if (subDenStr == "gwei") return Literal::SubDenomination::Gwei; else if (subDenStr == "ether") return Literal::SubDenomination::Ether; else if (subDenStr == "seconds") return Literal::SubDenomination::Second; else if (subDenStr == "minutes") return Literal::SubDenomination::Minute; else if (subDenStr == "hours") return Literal::SubDenomination::Hour; else if (subDenStr == "days") return Literal::SubDenomination::Day; else if (subDenStr == "weeks") return Literal::SubDenomination::Week; else if (subDenStr == "years") return Literal::SubDenomination::Year; else astAssert(false, "Unknown subdenomination"); } StateMutability ASTJsonImporter::stateMutability(Json::Value const& _node) { astAssert(member(_node, "stateMutability").isString(), "StateMutability' expected to be string."); string const mutabilityStr = member(_node, "stateMutability").asString(); if (mutabilityStr == "pure") return StateMutability::Pure; else if (mutabilityStr == "view") return StateMutability::View; else if (mutabilityStr == "nonpayable") return StateMutability::NonPayable; else if (mutabilityStr == "payable") return StateMutability::Payable; else astAssert(false, "Unknown stateMutability"); } }