diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 16 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 9 | ||||
-rw-r--r-- | libsolidity/ast/ASTAnnotations.h | 13 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.cpp | 860 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.h | 112 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 2 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerContext.cpp | 16 | ||||
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 36 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 6 | ||||
-rw-r--r-- | libsolidity/formal/Why3Translator.cpp | 2 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.cpp | 139 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmScope.h | 4 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmStack.h | 4 | ||||
-rw-r--r-- | libsolidity/interface/StandardCompiler.cpp | 3 |
14 files changed, 677 insertions, 545 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 38cdc1f8..8161a3a1 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1238,13 +1238,17 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) if (auto const* typeType = dynamic_cast<TypeType const*>(expressionType.get())) { - _functionCall.annotation().isStructConstructorCall = (typeType->actualType()->category() == Type::Category::Struct); - _functionCall.annotation().isTypeConversion = !_functionCall.annotation().isStructConstructorCall; + if (typeType->actualType()->category() == Type::Category::Struct) + _functionCall.annotation().kind = FunctionCallKind::StructConstructorCall; + else + _functionCall.annotation().kind = FunctionCallKind::TypeConversion; + } else - _functionCall.annotation().isStructConstructorCall = _functionCall.annotation().isTypeConversion = false; + _functionCall.annotation().kind = FunctionCallKind::FunctionCall; + solAssert(_functionCall.annotation().kind != FunctionCallKind::Unset, ""); - if (_functionCall.annotation().isTypeConversion) + if (_functionCall.annotation().kind == FunctionCallKind::TypeConversion) { TypeType const& t = dynamic_cast<TypeType const&>(*expressionType); TypePointer resultType = t.actualType(); @@ -1274,7 +1278,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) /// For error message: Struct members that were removed during conversion to memory. set<string> membersRemovedForStructConstructor; - if (_functionCall.annotation().isStructConstructorCall) + if (_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall) { TypeType const& t = dynamic_cast<TypeType const&>(*expressionType); auto const& structType = dynamic_cast<StructType const&>(*t.actualType()); @@ -1312,7 +1316,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) toString(parameterTypes.size()) + "."; // Extend error message in case we try to construct a struct with mapping member. - if (_functionCall.annotation().isStructConstructorCall && !membersRemovedForStructConstructor.empty()) + if (_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall && !membersRemovedForStructConstructor.empty()) { msg += " Members that have to be skipped in memory:"; for (auto const& member: membersRemovedForStructConstructor) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 02234ffc..71b81a69 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -583,8 +583,7 @@ public: bool isPayable() const { return m_isPayable; } std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; } std::vector<ASTPointer<VariableDeclaration>> const& returnParameters() const { return m_returnParameters->parameters(); } - Block const& body() const { return *m_body; } - + Block const& body() const { solAssert(m_body, ""); return *m_body; } virtual bool isVisibleInContract() const override { return Declaration::isVisibleInContract() && !isConstructor() && !name().empty(); @@ -1314,7 +1313,7 @@ private: /** * Tuple, parenthesized expression, or bracketed expression. - * Examples: (1, 2), (x,), (x), (), [1, 2], + * Examples: (1, 2), (x,), (x), (), [1, 2], * Individual components might be empty shared pointers (as in the second example). * The respective types in lvalue context are: 2-tuple, 2-tuple (with wildcard), type of x, 0-tuple * Not in lvalue context: 2-tuple, _1_-tuple, type of x, 0-tuple. @@ -1327,8 +1326,8 @@ public: std::vector<ASTPointer<Expression>> const& _components, bool _isArray ): - Expression(_location), - m_components(_components), + Expression(_location), + m_components(_components), m_isArray(_isArray) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index a7d89248..45a6dd1a 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -200,12 +200,17 @@ struct BinaryOperationAnnotation: ExpressionAnnotation TypePointer commonType; }; +enum class FunctionCallKind +{ + Unset, + FunctionCall, + TypeConversion, + StructConstructorCall +}; + struct FunctionCallAnnotation: ExpressionAnnotation { - /// Whether this is an explicit type conversion. - bool isTypeConversion = false; - /// Whether this is a struct constructor call. - bool isStructConstructorCall = false; + FunctionCallKind kind = FunctionCallKind::Unset; }; } diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 9ea23687..40c552a3 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -25,6 +25,8 @@ #include <libdevcore/UTF8.h> #include <libsolidity/ast/AST.h> #include <libsolidity/interface/Exceptions.h> +#include <libsolidity/inlineasm/AsmData.h> +#include <libsolidity/inlineasm/AsmPrinter.h> using namespace std; @@ -33,49 +35,86 @@ namespace dev namespace solidity { -void ASTJsonConverter::addJsonNode( +ASTJsonConverter::ASTJsonConverter(bool _legacy, map<string, unsigned> _sourceIndices): + m_legacy(_legacy), + m_sourceIndices(_sourceIndices) +{ +} + + +void ASTJsonConverter::setJsonNode( ASTNode const& _node, string const& _nodeName, - initializer_list<pair<string const, Json::Value const>> _attributes, - bool _hasChildren = false + initializer_list<pair<string, Json::Value>>&& _attributes ) { - ASTJsonConverter::addJsonNode( + ASTJsonConverter::setJsonNode( _node, _nodeName, - std::vector<pair<string const, Json::Value const>>(_attributes), - _hasChildren + std::vector<pair<string, Json::Value>>(std::move(_attributes)) ); } - -void ASTJsonConverter::addJsonNode( + +void ASTJsonConverter::setJsonNode( ASTNode const& _node, - string const& _nodeName, - std::vector<pair<string const, Json::Value const>> const& _attributes, - bool _hasChildren = false + string const& _nodeType, + std::vector<pair<string, Json::Value>>&& _attributes ) { - Json::Value node; - - node["id"] = Json::UInt64(_node.id()); - node["src"] = sourceLocationToString(_node.location()); - node["name"] = _nodeName; - if (_attributes.size() != 0) + m_currentValue = Json::objectValue; + m_currentValue["id"] = nodeId(_node); + m_currentValue["src"] = sourceLocationToString(_node.location()); + if (!m_legacy) { - Json::Value attrs; + m_currentValue["nodeType"] = _nodeType; for (auto& e: _attributes) - attrs[e.first] = e.second; - node["attributes"] = attrs; + m_currentValue[e.first] = std::move(e.second); } - - m_jsonNodePtrs.top()->append(node); - - if (_hasChildren) + else { - Json::Value& addedNode = (*m_jsonNodePtrs.top())[m_jsonNodePtrs.top()->size() - 1]; - Json::Value children(Json::arrayValue); - addedNode["children"] = children; - m_jsonNodePtrs.push(&addedNode["children"]); + m_currentValue["name"] = _nodeType; + Json::Value attrs(Json::objectValue); + if ( + //these nodeTypes need to have a children-node even if it is empty + (_nodeType == "VariableDeclaration") || + (_nodeType == "ParameterList") || + (_nodeType == "Block") || + (_nodeType == "InlineAssembly") || + (_nodeType == "Throw") + ) + { + Json::Value children(Json::arrayValue); + m_currentValue["children"] = children; + } + + for (auto& e: _attributes) + { + if ( + (!e.second.isNull()) && + ( + (e.second.isObject() && e.second.isMember("name")) || + (e.second.isArray() && e.second[0].isObject() && e.second[0].isMember("name")) || + (e.first == "declarations") // (in the case (_,x)= ... there's a nullpointer at [0] + ) + ) + { + if (e.second.isObject()) + m_currentValue["children"].append(std::move(e.second)); + if (e.second.isArray()) + for (auto& child: e.second) + if (!child.isNull()) + m_currentValue["children"].append(std::move(child)); + } + else + { + if (e.first == "typeDescriptions") + attrs["type"] = Json::Value(e.second["typeString"]); + else + attrs[e.first] = std::move(e.second); + } + } + if (!attrs.empty()) + m_currentValue["attributes"] = std::move(attrs); } } @@ -90,34 +129,89 @@ string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) return std::to_string(_location.start) + ":" + std::to_string(length) + ":" + std::to_string(sourceIndex); } -ASTJsonConverter::ASTJsonConverter( - ASTNode const& _ast, - map<string, unsigned> _sourceIndices -): m_ast(&_ast), m_sourceIndices(_sourceIndices) +string ASTJsonConverter::namePathToString(std::vector<ASTString> const& _namePath) const { + return boost::algorithm::join(_namePath, "."); } -void ASTJsonConverter::print(ostream& _stream) +Json::Value ASTJsonConverter::typePointerToJson(TypePointer _tp) { - process(); - _stream << m_astJson; + Json::Value typeDescriptions(Json::objectValue); + typeDescriptions["typeString"] = _tp ? Json::Value(_tp->toString()) : Json::nullValue; + typeDescriptions["typeIdentifier"] = _tp ? Json::Value(_tp->identifier()) : Json::nullValue; + return typeDescriptions; + +} +Json::Value ASTJsonConverter::typePointerToJson(std::shared_ptr<std::vector<TypePointer>> _tps) +{ + if (_tps) + { + Json::Value arguments(Json::arrayValue); + for (auto const& tp: *_tps) + arguments.append(typePointerToJson(tp)); + return arguments; + } + else + return Json::nullValue; } -Json::Value const& ASTJsonConverter::json() +void ASTJsonConverter::appendExpressionAttributes( + std::vector<pair<string, Json::Value>>& _attributes, + ExpressionAnnotation const& _annotation +) { - process(); - return m_astJson; + std::vector<pair<string, Json::Value>> exprAttributes = { + make_pair("typeDescriptions", typePointerToJson(_annotation.type)), + make_pair("isConstant", _annotation.isConstant), + make_pair("isPure", _annotation.isPure), + make_pair("isLValue", _annotation.isLValue), + make_pair("lValueRequested", _annotation.lValueRequested), + make_pair("argumentTypes", typePointerToJson(_annotation.argumentTypes)) + }; + _attributes += exprAttributes; } -bool ASTJsonConverter::visit(SourceUnit const&) +Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair<assembly::Identifier const* ,InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) { - Json::Value children(Json::arrayValue); + Json::Value tuple(Json::objectValue); + tuple["src"] = sourceLocationToString(_info.first->location); + tuple["declaration"] = idOrNull(_info.second.declaration); + tuple["isSlot"] = Json::Value(_info.second.isSlot); + tuple["isOffset"] = Json::Value(_info.second.isOffset); + tuple["valueSize"] = _info.second.valueSize; + return tuple; +} - m_astJson["name"] = "SourceUnit"; - m_astJson["children"] = children; - m_jsonNodePtrs.push(&m_astJson["children"]); +void ASTJsonConverter::print(ostream& _stream, ASTNode const& _node) +{ + _stream << toJson(_node); +} - return true; +Json::Value ASTJsonConverter::toJson(ASTNode const& _node) +{ + _node.accept(*this); + return std::move(m_currentValue); +} + +bool ASTJsonConverter::visit(SourceUnit const& _node) +{ + Json::Value exportedSymbols = Json::objectValue; + for (auto const& sym: _node.annotation().exportedSymbols) + { + exportedSymbols[sym.first] = Json::arrayValue; + for (Declaration const* overload: sym.second) + exportedSymbols[sym.first].append(nodeId(*overload)); + } + setJsonNode( + _node, + "SourceUnit", + { + make_pair("absolutePath", _node.annotation().path), + make_pair("exportedSymbols", move(exportedSymbols)), + make_pair("nodes", toJson(_node.nodes())) + } + ); + return false; } bool ASTJsonConverter::visit(PragmaDirective const& _node) @@ -125,313 +219,487 @@ bool ASTJsonConverter::visit(PragmaDirective const& _node) Json::Value literals(Json::arrayValue); for (auto const& literal: _node.literals()) literals.append(literal); - addJsonNode(_node, "PragmaDirective", { make_pair("literals", literals) }); - return true; + setJsonNode( _node, "PragmaDirective", { + make_pair("literals", std::move(literals)) + }); + return false; } bool ASTJsonConverter::visit(ImportDirective const& _node) { - addJsonNode(_node, "ImportDirective", { make_pair("file", _node.path())}); - return true; + std::vector<pair<string, Json::Value>> attributes = { + make_pair("file", _node.path()), + make_pair("absolutePath", _node.annotation().absolutePath), + make_pair(m_legacy ? "SourceUnit" : "sourceUnit", nodeId(*_node.annotation().sourceUnit)), + make_pair("scope", idOrNull(_node.scope())) + }; + attributes.push_back(make_pair("unitAlias", _node.name())); + Json::Value symbolAliases(Json::arrayValue); + for (auto const& symbolAlias: _node.symbolAliases()) + { + Json::Value tuple(Json::objectValue); + solAssert(symbolAlias.first, ""); + tuple["foreign"] = nodeId(*symbolAlias.first); + tuple["local"] = symbolAlias.second ? Json::Value(*symbolAlias.second) : Json::nullValue; + symbolAliases.append(tuple); + } + attributes.push_back(make_pair("symbolAliases", std::move(symbolAliases))); + setJsonNode(_node, "ImportDirective", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(ContractDefinition const& _node) { - Json::Value linearizedBaseContracts(Json::arrayValue); - for (auto const& baseContract: _node.annotation().linearizedBaseContracts) - linearizedBaseContracts.append(Json::UInt64(baseContract->id())); - addJsonNode(_node, "ContractDefinition", { + setJsonNode(_node, "ContractDefinition", { make_pair("name", _node.name()), - make_pair("isLibrary", _node.isLibrary()), + make_pair("contractKind", contractKind(_node.contractKind())), make_pair("fullyImplemented", _node.annotation().isFullyImplemented), - make_pair("linearizedBaseContracts", linearizedBaseContracts), - }, true); - return true; + make_pair("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)), + make_pair("baseContracts", toJson(_node.baseContracts())), + make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies)), + make_pair("nodes", toJson(_node.subNodes())), + make_pair("scope", idOrNull(_node.scope())) + }); + return false; } bool ASTJsonConverter::visit(InheritanceSpecifier const& _node) { - addJsonNode(_node, "InheritanceSpecifier", {}, true); - return true; + setJsonNode(_node, "InheritanceSpecifier", { + make_pair("baseName", toJson(_node.name())), + make_pair("arguments", toJson(_node.arguments())) + }); + return false; } bool ASTJsonConverter::visit(UsingForDirective const& _node) { - addJsonNode(_node, "UsingForDirective", {}, true); - return true; + setJsonNode(_node, "UsingForDirective", { + make_pair("libraryName", toJson(_node.libraryName())), + make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json::nullValue) + }); + return false; } bool ASTJsonConverter::visit(StructDefinition const& _node) { - addJsonNode(_node, "StructDefinition", { make_pair("name", _node.name()) }, true); - return true; + setJsonNode(_node, "StructDefinition", { + make_pair("name", _node.name()), + make_pair("visibility", visibility(_node.visibility())), + make_pair("canonicalName", _node.annotation().canonicalName), + make_pair("members", toJson(_node.members())), + make_pair("scope", idOrNull(_node.scope())) + }); + return false; } bool ASTJsonConverter::visit(EnumDefinition const& _node) { - addJsonNode(_node, "EnumDefinition", { make_pair("name", _node.name()) }, true); - return true; + setJsonNode(_node, "EnumDefinition", { + make_pair("name", _node.name()), + make_pair("canonicalName", _node.annotation().canonicalName), + make_pair("members", toJson(_node.members())) + }); + return false; } bool ASTJsonConverter::visit(EnumValue const& _node) { - addJsonNode(_node, "EnumValue", { make_pair("name", _node.name()) }); - return true; + setJsonNode(_node, "EnumValue", { + make_pair("name", _node.name()) + }); + return false; } bool ASTJsonConverter::visit(ParameterList const& _node) { - addJsonNode(_node, "ParameterList", {}, true); - return true; + setJsonNode(_node, "ParameterList", { + make_pair("parameters", toJson(_node.parameters())) + }); + return false; } bool ASTJsonConverter::visit(FunctionDefinition const& _node) { - addJsonNode(_node, "FunctionDefinition", { + std::vector<pair<string, Json::Value>> attributes = { make_pair("name", _node.name()), - make_pair("constant", _node.isDeclaredConst()), + make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.isDeclaredConst()), make_pair("payable", _node.isPayable()), - make_pair("visibility", visibility(_node.visibility())) - }, true); - return true; + make_pair("visibility", visibility(_node.visibility())), + make_pair("parameters", toJson(_node.parameterList())), + make_pair("isConstructor", _node.isConstructor()), + make_pair("returnParameters", toJson(*_node.returnParameterList())), + make_pair("modifiers", toJson(_node.modifiers())), + make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json::nullValue), + make_pair("implemented", _node.isImplemented()), + make_pair("scope", idOrNull(_node.scope())) + }; + setJsonNode(_node, "FunctionDefinition", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(VariableDeclaration const& _node) { - std::vector<pair<string const, Json::Value const>> attributes = { + std::vector<pair<string, Json::Value>> attributes = { make_pair("name", _node.name()), - make_pair("type", type(_node)), + make_pair("typeName", toJsonOrNull(_node.typeName())), make_pair("constant", _node.isConstant()), + make_pair("stateVariable", _node.isStateVariable()), make_pair("storageLocation", location(_node.referenceLocation())), - make_pair("visibility", visibility(_node.visibility())) - }; + make_pair("visibility", visibility(_node.visibility())), + make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue), + make_pair("scope", idOrNull(_node.scope())), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + }; if (m_inEvent) attributes.push_back(make_pair("indexed", _node.isIndexed())); - addJsonNode(_node, "VariableDeclaration", attributes, true); - return true; - + setJsonNode(_node, "VariableDeclaration", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(ModifierDefinition const& _node) { - addJsonNode(_node, "ModifierDefinition", { make_pair("name", _node.name()) }, true); - return true; + setJsonNode(_node, "ModifierDefinition", { + make_pair("name", _node.name()), + make_pair("visibility", visibility(_node.visibility())), + make_pair("parameters", toJson(_node.parameterList())), + make_pair("body", toJson(_node.body())) + }); + return false; } bool ASTJsonConverter::visit(ModifierInvocation const& _node) { - addJsonNode(_node, "ModifierInvocation", {}, true); - return true; + setJsonNode(_node, "ModifierInvocation", { + make_pair("modifierName", toJson(*_node.name())), + make_pair("arguments", toJson(_node.arguments())) + }); + return false; } bool ASTJsonConverter::visit(TypeName const&) { - return true; + solAssert(false, "AST node of abstract type used."); + return false; } bool ASTJsonConverter::visit(EventDefinition const& _node) { m_inEvent = true; - addJsonNode(_node, "EventDefinition", { make_pair("name", _node.name()) }, true); - return true; + setJsonNode(_node, "EventDefinition", { + make_pair("name", _node.name()), + make_pair("parameters", toJson(_node.parameterList())), + make_pair("anonymous", _node.isAnonymous()) + }); + return false; } bool ASTJsonConverter::visit(ElementaryTypeName const& _node) { - addJsonNode(_node, "ElementaryTypeName", { make_pair("name", _node.typeName().toString()) }); - return true; + setJsonNode(_node, "ElementaryTypeName", { + make_pair("name", _node.typeName().toString()), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + }); + return false; } bool ASTJsonConverter::visit(UserDefinedTypeName const& _node) { - addJsonNode(_node, "UserDefinedTypeName", { - make_pair("name", boost::algorithm::join(_node.namePath(), ".")) + setJsonNode(_node, "UserDefinedTypeName", { + make_pair("name", namePathToString(_node.namePath())), + make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), + make_pair("contractScope", idOrNull(_node.annotation().contractScope)), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) }); - return true; + return false; } bool ASTJsonConverter::visit(FunctionTypeName const& _node) { - addJsonNode(_node, "FunctionTypeName", { + setJsonNode(_node, "FunctionTypeName", { make_pair("payable", _node.isPayable()), make_pair("visibility", visibility(_node.visibility())), - make_pair("constant", _node.isDeclaredConst()) - }, true); - return true; + make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.isDeclaredConst()), + make_pair("parameterTypes", toJson(_node.parameterTypes())), + make_pair("returnParameterTypes", toJson(_node.returnParameterTypes())), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + }); + return false; } bool ASTJsonConverter::visit(Mapping const& _node) { - addJsonNode(_node, "Mapping", {}, true); - return true; + setJsonNode(_node, "Mapping", { + make_pair("keyType", toJson(_node.keyType())), + make_pair("valueType", toJson(_node.valueType())), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + }); + return false; } bool ASTJsonConverter::visit(ArrayTypeName const& _node) { - addJsonNode(_node, "ArrayTypeName", {}, true); - return true; + setJsonNode(_node, "ArrayTypeName", { + make_pair("baseType", toJson(_node.baseType())), + make_pair("length", toJsonOrNull(_node.length())), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) + }); + return false; } bool ASTJsonConverter::visit(InlineAssembly const& _node) { - addJsonNode(_node, "InlineAssembly", {}, true); - return true; + Json::Value externalReferences(Json::arrayValue); + for (auto const& it : _node.annotation().externalReferences) + { + if (it.first) + { + Json::Value tuple(Json::objectValue); + tuple[it.first->name] = inlineAssemblyIdentifierToJson(it); + externalReferences.append(tuple); + } + } + setJsonNode(_node, "InlineAssembly", { + make_pair("operations", Json::Value(assembly::AsmPrinter()(_node.operations()))), + make_pair("externalReferences", std::move(externalReferences)) + }); + return false; } bool ASTJsonConverter::visit(Block const& _node) { - addJsonNode(_node, "Block", {}, true); - return true; + setJsonNode(_node, "Block", { + make_pair("statements", toJson(_node.statements())) + }); + return false; } bool ASTJsonConverter::visit(PlaceholderStatement const& _node) { - addJsonNode(_node, "PlaceholderStatement", {}); - return true; + setJsonNode(_node, "PlaceholderStatement", {}); + return false; } bool ASTJsonConverter::visit(IfStatement const& _node) { - addJsonNode(_node, "IfStatement", {}, true); - return true; + setJsonNode(_node, "IfStatement", { + make_pair("condition", toJson(_node.condition())), + make_pair("trueBody", toJson(_node.trueStatement())), + make_pair("falseBody", toJsonOrNull(_node.falseStatement())) + }); + return false; } bool ASTJsonConverter::visit(WhileStatement const& _node) { - addJsonNode( + setJsonNode( _node, _node.isDoWhile() ? "DoWhileStatement" : "WhileStatement", - {}, - true); - return true; + { + make_pair("condition", toJson(_node.condition())), + make_pair("body", toJson(_node.body())) + } + ); + return false; } bool ASTJsonConverter::visit(ForStatement const& _node) { - addJsonNode(_node, "ForStatement", {}, true); - return true; + setJsonNode(_node, "ForStatement", { + make_pair("initializationExpression", toJsonOrNull(_node.initializationExpression())), + make_pair("condition", toJsonOrNull(_node.condition())), + make_pair("loopExpression", toJsonOrNull(_node.loopExpression())), + make_pair("body", toJson(_node.body())) + }); + return false; } bool ASTJsonConverter::visit(Continue const& _node) { - addJsonNode(_node, "Continue", {}); - return true; + setJsonNode(_node, "Continue", {}); + return false; } bool ASTJsonConverter::visit(Break const& _node) { - addJsonNode(_node, "Break", {}); - return true; + setJsonNode(_node, "Break", {}); + return false; } bool ASTJsonConverter::visit(Return const& _node) { - addJsonNode(_node, "Return", {}, true);; - return true; + setJsonNode(_node, "Return", { + make_pair("expression", toJsonOrNull(_node.expression())), + make_pair("functionReturnParameters", idOrNull(_node.annotation().functionReturnParameters)) + }); + return false; } bool ASTJsonConverter::visit(Throw const& _node) { - addJsonNode(_node, "Throw", {}, true);; - return true; + setJsonNode(_node, "Throw", {});; + return false; } bool ASTJsonConverter::visit(VariableDeclarationStatement const& _node) { - addJsonNode(_node, "VariableDeclarationStatement", {}, true); - return true; + Json::Value varDecs(Json::arrayValue); + for (auto const& v: _node.annotation().assignments) + varDecs.append(idOrNull(v)); + setJsonNode(_node, "VariableDeclarationStatement", { + make_pair("assignments", std::move(varDecs)), + make_pair("declarations", toJson(_node.declarations())), + make_pair("initialValue", toJsonOrNull(_node.initialValue())) + }); + return false; } bool ASTJsonConverter::visit(ExpressionStatement const& _node) { - addJsonNode(_node, "ExpressionStatement", {}, true); - return true; + setJsonNode(_node, "ExpressionStatement", { + make_pair("expression", toJson(_node.expression())) + }); + return false; } bool ASTJsonConverter::visit(Conditional const& _node) { - addJsonNode(_node, "Conditional", {}, true); - return true; + std::vector<pair<string, Json::Value>> attributes = { + make_pair("condition", toJson(_node.condition())), + make_pair("trueExpression", toJson(_node.trueExpression())), + make_pair("falseExpression", toJson(_node.falseExpression())) + }; + appendExpressionAttributes(attributes, _node.annotation()); + setJsonNode(_node, "Conditional", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(Assignment const& _node) { - addJsonNode(_node, "Assignment", - { make_pair("operator", Token::toString(_node.assignmentOperator())), - make_pair("type", type(_node)) }, - true); - return true; + std::vector<pair<string, Json::Value>> attributes = { + make_pair("operator", Token::toString(_node.assignmentOperator())), + make_pair("leftHandSide", toJson(_node.leftHandSide())), + make_pair("rightHandSide", toJson(_node.rightHandSide())) + }; + appendExpressionAttributes(attributes, _node.annotation()); + setJsonNode( _node, "Assignment", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(TupleExpression const& _node) { - addJsonNode(_node, "TupleExpression",{}, true); - return true; + std::vector<pair<string, Json::Value>> attributes = { + make_pair("isInlineArray", Json::Value(_node.isInlineArray())), + make_pair("components", toJson(_node.components())), + }; + appendExpressionAttributes(attributes, _node.annotation()); + setJsonNode(_node, "TupleExpression", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(UnaryOperation const& _node) { - addJsonNode(_node, "UnaryOperation", - { make_pair("prefix", _node.isPrefixOperation()), - make_pair("operator", Token::toString(_node.getOperator())), - make_pair("type", type(_node)) }, - true); - return true; + std::vector<pair<string, Json::Value>> attributes = { + make_pair("prefix", _node.isPrefixOperation()), + make_pair("operator", Token::toString(_node.getOperator())), + make_pair("subExpression", toJson(_node.subExpression())) + }; + appendExpressionAttributes(attributes, _node.annotation()); + setJsonNode(_node, "UnaryOperation", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(BinaryOperation const& _node) { - addJsonNode(_node, "BinaryOperation", { + std::vector<pair<string, Json::Value>> attributes = { make_pair("operator", Token::toString(_node.getOperator())), - make_pair("type", type(_node)) - }, true); - return true; + make_pair("leftExpression", toJson(_node.leftExpression())), + make_pair("rightExpression", toJson(_node.rightExpression())), + make_pair("commonType", typePointerToJson(_node.annotation().commonType)), + }; + appendExpressionAttributes(attributes, _node.annotation()); + setJsonNode(_node, "BinaryOperation", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(FunctionCall const& _node) { - addJsonNode(_node, "FunctionCall", { - make_pair("type_conversion", _node.annotation().isTypeConversion), - make_pair("type", type(_node)) - }, true); - return true; + Json::Value names(Json::arrayValue); + for (auto const& name: _node.names()) + names.append(Json::Value(*name)); + std::vector<pair<string, Json::Value>> attributes = { + make_pair("expression", toJson(_node.expression())), + make_pair("names", std::move(names)), + make_pair("arguments", toJson(_node.arguments())) + }; + if (m_legacy) + { + attributes.push_back(make_pair("isStructConstructorCall", _node.annotation().kind == FunctionCallKind::StructConstructorCall)); + attributes.push_back(make_pair("type_conversion", _node.annotation().kind == FunctionCallKind::TypeConversion)); + } + else + attributes.push_back(make_pair("kind", functionCallKind(_node.annotation().kind))); + appendExpressionAttributes(attributes, _node.annotation()); + setJsonNode(_node, "FunctionCall", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(NewExpression const& _node) { - addJsonNode(_node, "NewExpression", { make_pair("type", type(_node)) }, true); - return true; + std::vector<pair<string, Json::Value>> attributes = { + make_pair("typeName", toJson(_node.typeName())) + }; + appendExpressionAttributes(attributes, _node.annotation()); + setJsonNode(_node, "NewExpression", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(MemberAccess const& _node) { - addJsonNode(_node, "MemberAccess", { - make_pair("member_name", _node.memberName()), - make_pair("type", type(_node)) - }, true); - return true; + std::vector<pair<string, Json::Value>> attributes = { + make_pair(m_legacy ? "member_name" : "memberName", _node.memberName()), + make_pair("expression", toJson(_node.expression())), + make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), + }; + appendExpressionAttributes(attributes, _node.annotation()); + setJsonNode(_node, "MemberAccess", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(IndexAccess const& _node) { - addJsonNode(_node, "IndexAccess", { make_pair("type", type(_node)) }, true); - return true; + std::vector<pair<string, Json::Value>> attributes = { + make_pair("baseExpression", toJson(_node.baseExpression())), + make_pair("indexExpression", toJsonOrNull(_node.indexExpression())), + }; + appendExpressionAttributes(attributes, _node.annotation()); + setJsonNode(_node, "IndexAccess", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(Identifier const& _node) { - addJsonNode(_node, "Identifier", - { make_pair("value", _node.name()), make_pair("type", type(_node)) }); - return true; + Json::Value overloads(Json::arrayValue); + for (auto const& dec: _node.annotation().overloadedDeclarations) + overloads.append(nodeId(*dec)); + setJsonNode(_node, "Identifier", { + make_pair(m_legacy ? "value" : "name", _node.name()), + make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), + make_pair("overloadedDeclarations", overloads), + make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)), + make_pair("argumentTypes", typePointerToJson(_node.annotation().argumentTypes)) + }); + return false; } bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node) { - addJsonNode(_node, "ElementaryTypeNameExpression", { - make_pair("value", _node.typeName().toString()), - make_pair("type", type(_node)) - }); - return true; + std::vector<pair<string, Json::Value>> attributes = { + make_pair(m_legacy ? "value" : "typeName", _node.typeName().toString()) + }; + appendExpressionAttributes(attributes, _node.annotation()); + setJsonNode(_node, "ElementaryTypeNameExpression", std::move(attributes)); + return false; } bool ASTJsonConverter::visit(Literal const& _node) @@ -441,240 +709,26 @@ bool ASTJsonConverter::visit(Literal const& _node) if (!dev::validateUTF8(_node.value())) value = Json::nullValue; Token::Value subdenomination = Token::Value(_node.subDenomination()); - addJsonNode(_node, "Literal", { + std::vector<pair<string, Json::Value>> attributes = { make_pair("token", tokenString ? tokenString : Json::Value()), make_pair("value", value), - make_pair("hexvalue", toHex(_node.value())), + make_pair(m_legacy ? "hexvalue" : "hexValue", toHex(_node.value())), make_pair( "subdenomination", subdenomination == Token::Illegal ? Json::nullValue : Json::Value{Token::toString(subdenomination)} - ), - make_pair("type", type(_node)) - }); - return true; -} - -void ASTJsonConverter::endVisit(SourceUnit const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(PragmaDirective const&) -{ -} - -void ASTJsonConverter::endVisit(ImportDirective const&) -{ -} - -void ASTJsonConverter::endVisit(ContractDefinition const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(InheritanceSpecifier const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(UsingForDirective const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(StructDefinition const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(EnumDefinition const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(EnumValue const&) -{ -} - -void ASTJsonConverter::endVisit(ParameterList const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(FunctionDefinition const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(VariableDeclaration const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(ModifierDefinition const&) -{ - goUp(); + ) + }; + appendExpressionAttributes(attributes, _node.annotation()); + setJsonNode(_node, "Literal", std::move(attributes)); + return false; } -void ASTJsonConverter::endVisit(ModifierInvocation const&) -{ - goUp(); -} void ASTJsonConverter::endVisit(EventDefinition const&) { m_inEvent = false; - goUp(); -} - -void ASTJsonConverter::endVisit(TypeName const&) -{ -} - -void ASTJsonConverter::endVisit(ElementaryTypeName const&) -{ -} - -void ASTJsonConverter::endVisit(UserDefinedTypeName const&) -{ -} - -void ASTJsonConverter::endVisit(FunctionTypeName const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Mapping const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(ArrayTypeName const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(InlineAssembly const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Block const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(PlaceholderStatement const&) -{ -} - -void ASTJsonConverter::endVisit(IfStatement const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(WhileStatement const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(ForStatement const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Continue const&) -{ -} - -void ASTJsonConverter::endVisit(Break const&) -{ -} - -void ASTJsonConverter::endVisit(Return const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Throw const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(VariableDeclarationStatement const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(ExpressionStatement const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Conditional const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Assignment const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(TupleExpression const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(UnaryOperation const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(BinaryOperation const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(FunctionCall const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(NewExpression const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(MemberAccess const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(IndexAccess const&) -{ - goUp(); -} - -void ASTJsonConverter::endVisit(Identifier const&) -{ -} - -void ASTJsonConverter::endVisit(ElementaryTypeNameExpression const&) -{ -} - -void ASTJsonConverter::endVisit(Literal const&) -{ -} - -void ASTJsonConverter::process() -{ - if (!processed) - m_ast->accept(*this); - processed = true; } string ASTJsonConverter::visibility(Declaration::Visibility const& _visibility) @@ -709,6 +763,36 @@ string ASTJsonConverter::location(VariableDeclaration::Location _location) } } +string ASTJsonConverter::contractKind(ContractDefinition::ContractKind _kind) +{ + switch (_kind) + { + case ContractDefinition::ContractKind::Interface: + return "interface"; + case ContractDefinition::ContractKind::Contract: + return "contract"; + case ContractDefinition::ContractKind::Library: + return "library"; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of contract.")); + } +} + +string ASTJsonConverter::functionCallKind(FunctionCallKind _kind) +{ + switch (_kind) + { + case FunctionCallKind::FunctionCall: + return "functionCall"; + case FunctionCallKind::TypeConversion: + return "typeConversion"; + case FunctionCallKind::StructConstructorCall: + return "structConstructorCall"; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of function call .")); + } +} + string ASTJsonConverter::type(Expression const& _expression) { return _expression.annotation().type ? _expression.annotation().type->toString() : "Unknown"; diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index bd5e6560..5ee40536 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -42,15 +42,23 @@ class ASTJsonConverter: public ASTConstVisitor { public: /// Create a converter to JSON for the given abstract syntax tree. + /// @a _legacy if true, use legacy format /// @a _sourceIndices is used to abbreviate source names in source locations. explicit ASTJsonConverter( - ASTNode const& _ast, + bool _legacy, std::map<std::string, unsigned> _sourceIndices = std::map<std::string, unsigned>() ); /// Output the json representation of the AST to _stream. - void print(std::ostream& _stream); - Json::Value const& json(); - + void print(std::ostream& _stream, ASTNode const& _node); + Json::Value toJson(ASTNode const& _node); + template <class T> + Json::Value toJson(std::vector<ASTPointer<T>> const& _nodes) + { + Json::Value ret(Json::arrayValue); + for (auto const& n: _nodes) + ret.append(n ? toJson(*n) : Json::nullValue); + return ret; + } bool visit(SourceUnit const& _node) override; bool visit(PragmaDirective const& _node) override; bool visit(ImportDirective const& _node) override; @@ -97,82 +105,60 @@ public: bool visit(ElementaryTypeNameExpression const& _node) override; bool visit(Literal const& _node) override; - void endVisit(SourceUnit const&) override; - void endVisit(PragmaDirective const&) override; - void endVisit(ImportDirective const&) override; - void endVisit(ContractDefinition const&) override; - void endVisit(InheritanceSpecifier const&) override; - void endVisit(UsingForDirective const&) override; - void endVisit(StructDefinition const&) override; - void endVisit(EnumDefinition const&) override; - void endVisit(EnumValue const&) override; - void endVisit(ParameterList const&) override; - void endVisit(FunctionDefinition const&) override; - void endVisit(VariableDeclaration const&) override; - void endVisit(ModifierDefinition const&) override; - void endVisit(ModifierInvocation const&) override; void endVisit(EventDefinition const&) override; - void endVisit(TypeName const&) override; - void endVisit(ElementaryTypeName const&) override; - void endVisit(UserDefinedTypeName const&) override; - void endVisit(FunctionTypeName const&) override; - void endVisit(Mapping const&) override; - void endVisit(ArrayTypeName const&) override; - void endVisit(InlineAssembly const&) override; - void endVisit(Block const&) override; - void endVisit(PlaceholderStatement const&) override; - void endVisit(IfStatement const&) override; - void endVisit(WhileStatement const&) override; - void endVisit(ForStatement const&) override; - void endVisit(Continue const&) override; - void endVisit(Break const&) override; - void endVisit(Return const&) override; - void endVisit(Throw const&) override; - void endVisit(VariableDeclarationStatement const&) override; - void endVisit(ExpressionStatement const&) override; - void endVisit(Conditional const&) override; - void endVisit(Assignment const&) override; - void endVisit(TupleExpression const&) override; - void endVisit(UnaryOperation const&) override; - void endVisit(BinaryOperation const&) override; - void endVisit(FunctionCall const&) override; - void endVisit(NewExpression const&) override; - void endVisit(MemberAccess const&) override; - void endVisit(IndexAccess const&) override; - void endVisit(Identifier const&) override; - void endVisit(ElementaryTypeNameExpression const&) override; - void endVisit(Literal const&) override; private: - void process(); - void addJsonNode( + void setJsonNode( ASTNode const& _node, std::string const& _nodeName, - std::initializer_list<std::pair<std::string const, Json::Value const>> _attributes, - bool _hasChildren + std::initializer_list<std::pair<std::string, Json::Value>>&& _attributes ); - void addJsonNode( + void setJsonNode( ASTNode const& _node, std::string const& _nodeName, - std::vector<std::pair<std::string const, Json::Value const>> const& _attributes, - bool _hasChildren + std::vector<std::pair<std::string, Json::Value>>&& _attributes ); std::string sourceLocationToString(SourceLocation const& _location) const; + std::string namePathToString(std::vector<ASTString> const& _namePath) const; + Json::Value idOrNull(ASTNode const* _pt) + { + return _pt ? Json::Value(nodeId(*_pt)) : Json::nullValue; + } + Json::Value toJsonOrNull(ASTNode const* _node) + { + return _node ? toJson(*_node) : Json::nullValue; + } + Json::Value inlineAssemblyIdentifierToJson(std::pair<assembly::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info); std::string visibility(Declaration::Visibility const& _visibility); std::string location(VariableDeclaration::Location _location); + std::string contractKind(ContractDefinition::ContractKind _kind); + std::string functionCallKind(FunctionCallKind _kind); std::string type(Expression const& _expression); std::string type(VariableDeclaration const& _varDecl); - inline void goUp() + int nodeId(ASTNode const& _node) { - solAssert(!m_jsonNodePtrs.empty(), "Uneven json nodes stack. Internal error."); - m_jsonNodePtrs.pop(); + return _node.id(); } - + template<class Container> + Json::Value getContainerIds(Container const& container) + { + Json::Value tmp(Json::arrayValue); + for (auto const& element: container) + { + solAssert(element, ""); + tmp.append(nodeId(*element)); + } + return tmp; + } + Json::Value typePointerToJson(TypePointer _tp); + Json::Value typePointerToJson(std::shared_ptr<std::vector<TypePointer>> _tps); + void appendExpressionAttributes( + std::vector<std::pair<std::string, Json::Value>> &_attributes, + ExpressionAnnotation const& _annotation + ); + bool m_legacy = false; ///< if true, use legacy format bool m_inEvent = false; ///< whether we are currently inside an event or not - bool processed = false; - Json::Value m_astJson; - std::stack<Json::Value*> m_jsonNodePtrs; - ASTNode const* m_ast; + Json::Value m_currentValue; std::map<std::string, unsigned> m_sourceIndices; }; diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 41ee6498..cfee041e 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2183,6 +2183,8 @@ string FunctionType::identifier() const case Kind::ArrayPush: id += "arraypush"; break; case Kind::ByteArrayPush: id += "bytearraypush"; break; case Kind::ObjectCreation: id += "objectcreation"; break; + case Kind::Assert: id += "assert"; break; + case Kind::Require: id += "require";break; default: solAssert(false, "Unknown function location."); break; } if (isConstant()) diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 51dd9fd2..5c4f88c4 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -264,7 +264,7 @@ void CompilerContext::appendInlineAssembly( assembly = &replacedAssembly; } - unsigned startStackHeight = stackHeight(); + int startStackHeight = stackHeight(); assembly::ExternalIdentifierAccess identifierAccess; identifierAccess.resolve = [&]( @@ -278,26 +278,26 @@ void CompilerContext::appendInlineAssembly( identifierAccess.generateCode = [&]( assembly::Identifier const& _identifier, assembly::IdentifierContext _context, - eth::Assembly& _assembly + julia::AbstractAssembly& _assembly ) { auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name); solAssert(it != _localVariables.end(), ""); - unsigned stackDepth = _localVariables.end() - it; - int stackDiff = _assembly.deposit() - startStackHeight + stackDepth; + int stackDepth = _localVariables.end() - it; + int stackDiff = _assembly.stackHeight() - startStackHeight + stackDepth; if (_context == assembly::IdentifierContext::LValue) stackDiff -= 1; if (stackDiff < 1 || stackDiff > 16) BOOST_THROW_EXCEPTION( CompilerError() << - errinfo_comment("Stack too deep, try removing local variables.") + errinfo_comment("Stack too deep (" + to_string(stackDiff) + "), try removing local variables.") ); if (_context == assembly::IdentifierContext::RValue) - _assembly.append(dupInstruction(stackDiff)); + _assembly.appendInstruction(dupInstruction(stackDiff)); else { - _assembly.append(swapInstruction(stackDiff)); - _assembly.append(Instruction::POP); + _assembly.appendInstruction(swapInstruction(stackDiff)); + _assembly.appendInstruction(Instruction::POP); } }; diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 34ef13c0..41940e1a 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -530,7 +530,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) return size_t(-1); return ref->second.valueSize; }; - identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext _context, eth::Assembly& _assembly) + identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, assembly::IdentifierContext _context, julia::AbstractAssembly& _assembly) { auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier); solAssert(ref != _inlineAssembly.annotation().externalReferences.end(), ""); @@ -538,21 +538,25 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) solAssert(!!decl, ""); if (_context == assembly::IdentifierContext::RValue) { - int const depositBefore = _assembly.deposit(); + int const depositBefore = _assembly.stackHeight(); solAssert(!!decl->type(), "Type of declaration required but not yet determined."); if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(decl)) { solAssert(!ref->second.isOffset && !ref->second.isSlot, ""); functionDef = &m_context.resolveVirtualFunction(*functionDef); - _assembly.append(m_context.functionEntryLabel(*functionDef).pushTag()); + auto functionEntryLabel = m_context.functionEntryLabel(*functionDef).pushTag(); + solAssert(functionEntryLabel.data() <= std::numeric_limits<size_t>::max(), ""); + _assembly.appendLabelReference(size_t(functionEntryLabel.data())); // If there is a runtime context, we have to merge both labels into the same // stack slot in case we store it in storage. if (CompilerContext* rtc = m_context.runtimeContext()) { - _assembly.append(u256(1) << 32); - _assembly.append(Instruction::MUL); - _assembly.append(rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub())); - _assembly.append(Instruction::OR); + _assembly.appendConstant(u256(1) << 32); + _assembly.appendInstruction(Instruction::MUL); + auto runtimeEntryLabel = rtc->functionEntryLabel(*functionDef).toSubAssemblyTag(m_context.runtimeSub()); + solAssert(runtimeEntryLabel.data() <= std::numeric_limits<size_t>::max(), ""); + _assembly.appendLabelReference(size_t(runtimeEntryLabel.data())); + _assembly.appendInstruction(Instruction::OR); } } else if (auto variable = dynamic_cast<VariableDeclaration const*>(decl)) @@ -570,7 +574,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else if (m_context.isLocalVariable(decl)) { - int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable); + int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable); if (ref->second.isSlot || ref->second.isOffset) { solAssert(variable->type()->dataStoredIn(DataLocation::Storage), ""); @@ -587,7 +591,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) // only slot, offset is zero if (ref->second.isOffset) { - _assembly.append(u256(0)); + _assembly.appendConstant(u256(0)); return; } } @@ -601,7 +605,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) errinfo_comment("Stack too deep, try removing local variables.") ); solAssert(variable->type()->sizeOnStack() == 1, ""); - _assembly.append(dupInstruction(stackDiff)); + _assembly.appendInstruction(dupInstruction(stackDiff)); } else solAssert(false, ""); @@ -610,11 +614,11 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) { solAssert(!ref->second.isOffset && !ref->second.isSlot, ""); solAssert(contract->isLibrary(), ""); - _assembly.appendLibraryAddress(contract->fullyQualifiedName()); + _assembly.appendLinkerSymbol(contract->fullyQualifiedName()); } else solAssert(false, "Invalid declaration type."); - solAssert(_assembly.deposit() - depositBefore == int(ref->second.valueSize), ""); + solAssert(_assembly.stackHeight() - depositBefore == int(ref->second.valueSize), ""); } else { @@ -626,15 +630,15 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) "Can only assign to stack variables in inline assembly." ); solAssert(variable->type()->sizeOnStack() == 1, ""); - int stackDiff = _assembly.deposit() - m_context.baseStackOffsetOfVariable(*variable) - 1; + int stackDiff = _assembly.stackHeight() - m_context.baseStackOffsetOfVariable(*variable) - 1; if (stackDiff > 16 || stackDiff < 1) BOOST_THROW_EXCEPTION( CompilerError() << errinfo_sourceLocation(_inlineAssembly.location()) << - errinfo_comment("Stack too deep, try removing local variables.") + errinfo_comment("Stack too deep(" + to_string(stackDiff) + "), try removing local variables.") ); - _assembly.append(swapInstruction(stackDiff)); - _assembly.append(Instruction::POP); + _assembly.appendInstruction(swapInstruction(stackDiff)); + _assembly.appendInstruction(Instruction::POP); } }; solAssert(_inlineAssembly.annotation().analysisInfo, ""); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index f018b311..0aa82ea8 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -434,7 +434,7 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { CompilerContext::LocationSetter locationSetter(m_context, _functionCall); - if (_functionCall.annotation().isTypeConversion) + if (_functionCall.annotation().kind == FunctionCallKind::TypeConversion) { solAssert(_functionCall.arguments().size() == 1, ""); solAssert(_functionCall.names().empty(), ""); @@ -445,7 +445,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) } FunctionTypePointer functionType; - if (_functionCall.annotation().isStructConstructorCall) + if (_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall) { auto const& type = dynamic_cast<TypeType const&>(*_functionCall.expression().annotation().type); auto const& structType = dynamic_cast<StructType const&>(*type.actualType()); @@ -476,7 +476,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) solAssert(found, ""); } - if (_functionCall.annotation().isStructConstructorCall) + if (_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall) { TypeType const& type = dynamic_cast<TypeType const&>(*_functionCall.expression().annotation().type); auto const& structType = dynamic_cast<StructType const&>(*type.actualType()); diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp index b6f17907..77d3c217 100644 --- a/libsolidity/formal/Why3Translator.cpp +++ b/libsolidity/formal/Why3Translator.cpp @@ -582,7 +582,7 @@ bool Why3Translator::visit(BinaryOperation const& _binaryOperation) bool Why3Translator::visit(FunctionCall const& _node) { - if (_node.annotation().isTypeConversion || _node.annotation().isStructConstructorCall) + if (_node.annotation().kind == FunctionCallKind::TypeConversion || _node.annotation().kind == FunctionCallKind::StructConstructorCall) { error(_node, "Only ordinary function calls supported."); return true; diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp index 44e12b3e..b8af9dc6 100644 --- a/libsolidity/inlineasm/AsmCodeGen.cpp +++ b/libsolidity/inlineasm/AsmCodeGen.cpp @@ -32,6 +32,8 @@ #include <libevmasm/SourceLocation.h> #include <libevmasm/Instruction.h> +#include <libjulia/backends/AbstractAssembly.h> + #include <libdevcore/CommonIO.h> #include <boost/range/adaptor/reversed.hpp> @@ -48,14 +50,53 @@ using namespace dev::solidity::assembly; struct GeneratorState { - GeneratorState(ErrorList& _errors, AsmAnalysisInfo& _analysisInfo, eth::Assembly& _assembly): - errors(_errors), info(_analysisInfo), assembly(_assembly) {} + GeneratorState(ErrorList& _errors, AsmAnalysisInfo& _analysisInfo): + errors(_errors), info(_analysisInfo) {} + + ErrorList& errors; + AsmAnalysisInfo info; +}; - size_t newLabelId() +class EthAssemblyAdapter: public julia::AbstractAssembly +{ +public: + EthAssemblyAdapter(eth::Assembly& _assembly): + m_assembly(_assembly) + { + } + virtual void setSourceLocation(SourceLocation const& _location) override + { + m_assembly.setSourceLocation(_location); + } + virtual int stackHeight() const override { return m_assembly.deposit(); } + virtual void appendInstruction(solidity::Instruction _instruction) override + { + m_assembly.append(_instruction); + } + virtual void appendConstant(u256 const& _constant) override + { + m_assembly.append(_constant); + } + /// Append a label. + virtual void appendLabel(size_t _labelId) override + { + m_assembly.append(eth::AssemblyItem(eth::Tag, _labelId)); + } + /// Append a label reference. + virtual void appendLabelReference(size_t _labelId) override + { + m_assembly.append(eth::AssemblyItem(eth::PushTag, _labelId)); + } + virtual size_t newLabelId() override + { + return assemblyTagToIdentifier(m_assembly.newTag()); + } + virtual void appendLinkerSymbol(std::string const& _linkerSymbol) override { - return assemblyTagToIdentifier(assembly.newTag()); + m_assembly.appendLibraryAddress(_linkerSymbol); } +private: size_t assemblyTagToIdentifier(eth::AssemblyItem const& _tag) const { u256 id = _tag.data(); @@ -63,9 +104,7 @@ struct GeneratorState return size_t(id); } - ErrorList& errors; - AsmAnalysisInfo info; - eth::Assembly& assembly; + eth::Assembly& m_assembly; }; class CodeTransform: public boost::static_visitor<> @@ -76,81 +115,84 @@ public: /// @param _identifierAccess used to resolve identifiers external to the inline assembly explicit CodeTransform( GeneratorState& _state, + julia::AbstractAssembly& _assembly, assembly::Block const& _block, assembly::ExternalIdentifierAccess const& _identifierAccess = assembly::ExternalIdentifierAccess() - ): CodeTransform(_state, _block, _identifierAccess, _state.assembly.deposit()) + ): CodeTransform(_state, _assembly, _block, _identifierAccess, _assembly.stackHeight()) { } private: CodeTransform( GeneratorState& _state, + julia::AbstractAssembly& _assembly, assembly::Block const& _block, assembly::ExternalIdentifierAccess const& _identifierAccess, - int _initialDeposit + int _initialStackHeight ): m_state(_state), + m_assembly(_assembly), m_scope(*m_state.info.scopes.at(&_block)), m_identifierAccess(_identifierAccess), - m_initialDeposit(_initialDeposit) + m_initialStackHeight(_initialStackHeight) { - int blockStartDeposit = m_state.assembly.deposit(); + int blockStartStackHeight = m_assembly.stackHeight(); std::for_each(_block.statements.begin(), _block.statements.end(), boost::apply_visitor(*this)); - m_state.assembly.setSourceLocation(_block.location); + m_assembly.setSourceLocation(_block.location); // pop variables for (auto const& identifier: m_scope.identifiers) if (identifier.second.type() == typeid(Scope::Variable)) - m_state.assembly.append(solidity::Instruction::POP); + m_assembly.appendInstruction(solidity::Instruction::POP); - int deposit = m_state.assembly.deposit() - blockStartDeposit; + int deposit = m_assembly.stackHeight() - blockStartStackHeight; solAssert(deposit == 0, "Invalid stack height at end of block."); } public: void operator()(assembly::Instruction const& _instruction) { - m_state.assembly.setSourceLocation(_instruction.location); - m_state.assembly.append(_instruction.instruction); + m_assembly.setSourceLocation(_instruction.location); + m_assembly.appendInstruction(_instruction.instruction); checkStackHeight(&_instruction); } void operator()(assembly::Literal const& _literal) { - m_state.assembly.setSourceLocation(_literal.location); + m_assembly.setSourceLocation(_literal.location); if (_literal.kind == assembly::LiteralKind::Number) - m_state.assembly.append(u256(_literal.value)); + m_assembly.appendConstant(u256(_literal.value)); else if (_literal.kind == assembly::LiteralKind::Boolean) { if (_literal.value == "true") - m_state.assembly.append(u256(1)); + m_assembly.appendConstant(u256(1)); else - m_state.assembly.append(u256(0)); + m_assembly.appendConstant(u256(0)); } else { solAssert(_literal.value.size() <= 32, ""); - m_state.assembly.append(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft))); + m_assembly.appendConstant(u256(h256(_literal.value, h256::FromBinary, h256::AlignLeft))); } checkStackHeight(&_literal); } void operator()(assembly::Identifier const& _identifier) { - m_state.assembly.setSourceLocation(_identifier.location); + m_assembly.setSourceLocation(_identifier.location); // First search internals, then externals. if (m_scope.lookup(_identifier.name, Scope::NonconstVisitor( [=](Scope::Variable& _var) { if (int heightDiff = variableHeightDiff(_var, _identifier.location, false)) - m_state.assembly.append(solidity::dupInstruction(heightDiff)); + m_assembly.appendInstruction(solidity::dupInstruction(heightDiff)); else // Store something to balance the stack - m_state.assembly.append(u256(0)); + m_assembly.appendConstant(u256(0)); }, [=](Scope::Label& _label) { assignLabelIdIfUnset(_label); - m_state.assembly.append(eth::AssemblyItem(eth::PushTag, _label.id)); + m_assembly.appendLabelReference(*_label.id); }, [=](Scope::Function&) { @@ -164,14 +206,14 @@ public: m_identifierAccess.generateCode, "Identifier not found and no external access available." ); - m_identifierAccess.generateCode(_identifier, IdentifierContext::RValue, m_state.assembly); + m_identifierAccess.generateCode(_identifier, IdentifierContext::RValue, m_assembly); checkStackHeight(&_identifier); } void operator()(FunctionalInstruction const& _instr) { for (auto it = _instr.arguments.rbegin(); it != _instr.arguments.rend(); ++it) { - int height = m_state.assembly.deposit(); + int height = m_assembly.stackHeight(); boost::apply_visitor(*this, *it); expectDeposit(1, height); } @@ -184,31 +226,31 @@ public: } void operator()(Label const& _label) { - m_state.assembly.setSourceLocation(_label.location); + m_assembly.setSourceLocation(_label.location); solAssert(m_scope.identifiers.count(_label.name), ""); Scope::Label& label = boost::get<Scope::Label>(m_scope.identifiers.at(_label.name)); assignLabelIdIfUnset(label); - m_state.assembly.append(eth::AssemblyItem(eth::Tag, label.id)); + m_assembly.appendLabel(*label.id); checkStackHeight(&_label); } void operator()(assembly::Assignment const& _assignment) { - m_state.assembly.setSourceLocation(_assignment.location); + m_assembly.setSourceLocation(_assignment.location); generateAssignment(_assignment.variableName, _assignment.location); checkStackHeight(&_assignment); } void operator()(FunctionalAssignment const& _assignment) { - int height = m_state.assembly.deposit(); + int height = m_assembly.stackHeight(); boost::apply_visitor(*this, *_assignment.value); expectDeposit(1, height); - m_state.assembly.setSourceLocation(_assignment.location); + m_assembly.setSourceLocation(_assignment.location); generateAssignment(_assignment.variableName, _assignment.location); checkStackHeight(&_assignment); } void operator()(assembly::VariableDeclaration const& _varDecl) { - int height = m_state.assembly.deposit(); + int height = m_assembly.stackHeight(); boost::apply_visitor(*this, *_varDecl.value); expectDeposit(1, height); auto& var = boost::get<Scope::Variable>(m_scope.identifiers.at(_varDecl.variable.name)); @@ -217,7 +259,7 @@ public: } void operator()(assembly::Block const& _block) { - CodeTransform(m_state, _block, m_identifierAccess, m_initialDeposit); + CodeTransform(m_state, m_assembly, _block, m_identifierAccess, m_initialStackHeight); checkStackHeight(&_block); } void operator()(assembly::FunctionDefinition const&) @@ -233,8 +275,8 @@ private: { Scope::Variable const& _var = boost::get<Scope::Variable>(*var); if (int heightDiff = variableHeightDiff(_var, _location, true)) - m_state.assembly.append(solidity::swapInstruction(heightDiff - 1)); - m_state.assembly.append(solidity::Instruction::POP); + m_assembly.appendInstruction(solidity::swapInstruction(heightDiff - 1)); + m_assembly.appendInstruction(solidity::Instruction::POP); } else { @@ -242,7 +284,7 @@ private: m_identifierAccess.generateCode, "Identifier not found and no external access available." ); - m_identifierAccess.generateCode(_variableName, IdentifierContext::LValue, m_state.assembly); + m_identifierAccess.generateCode(_variableName, IdentifierContext::LValue, m_assembly); } } @@ -251,7 +293,7 @@ private: /// errors and the (positive) stack height difference otherwise. int variableHeightDiff(Scope::Variable const& _var, SourceLocation const& _location, bool _forSwap) { - int heightDiff = m_state.assembly.deposit() - _var.stackHeight; + int heightDiff = m_assembly.stackHeight() - _var.stackHeight; if (heightDiff <= (_forSwap ? 1 : 0) || heightDiff > (_forSwap ? 17 : 16)) { //@TODO move this to analysis phase. @@ -268,14 +310,14 @@ private: void expectDeposit(int _deposit, int _oldHeight) { - solAssert(m_state.assembly.deposit() == _oldHeight + _deposit, "Invalid stack deposit."); + solAssert(m_assembly.stackHeight() == _oldHeight + _deposit, "Invalid stack deposit."); } void checkStackHeight(void const* _astElement) { solAssert(m_state.info.stackHeightInfo.count(_astElement), "Stack height for AST element not found."); solAssert( - m_state.info.stackHeightInfo.at(_astElement) == m_state.assembly.deposit() - m_initialDeposit, + m_state.info.stackHeightInfo.at(_astElement) == m_assembly.stackHeight() - m_initialStackHeight, "Stack height mismatch between analysis and code generation phase." ); } @@ -283,15 +325,16 @@ private: /// Assigns the label's id to a value taken from eth::Assembly if it has not yet been set. void assignLabelIdIfUnset(Scope::Label& _label) { - if (_label.id == Scope::Label::unassignedLabelId) - _label.id = m_state.newLabelId(); + if (!_label.id) + _label.id.reset(m_assembly.newLabelId()); } GeneratorState& m_state; + julia::AbstractAssembly& m_assembly; Scope& m_scope; ExternalIdentifierAccess m_identifierAccess; - int const m_initialDeposit; + int const m_initialStackHeight; }; eth::Assembly assembly::CodeGenerator::assemble( @@ -301,8 +344,9 @@ eth::Assembly assembly::CodeGenerator::assemble( ) { eth::Assembly assembly; - GeneratorState state(m_errors, _analysisInfo, assembly); - CodeTransform(state, _parsedData, _identifierAccess); + GeneratorState state(m_errors, _analysisInfo); + EthAssemblyAdapter assemblyAdapter(assembly); + CodeTransform(state, assemblyAdapter, _parsedData, _identifierAccess); return assembly; } @@ -313,6 +357,7 @@ void assembly::CodeGenerator::assemble( ExternalIdentifierAccess const& _identifierAccess ) { - GeneratorState state(m_errors, _analysisInfo, _assembly); - CodeTransform(state, _parsedData, _identifierAccess); + GeneratorState state(m_errors, _analysisInfo); + EthAssemblyAdapter assemblyAdapter(_assembly); + CodeTransform(state, assemblyAdapter, _parsedData, _identifierAccess); } diff --git a/libsolidity/inlineasm/AsmScope.h b/libsolidity/inlineasm/AsmScope.h index dd45613d..70786dce 100644 --- a/libsolidity/inlineasm/AsmScope.h +++ b/libsolidity/inlineasm/AsmScope.h @@ -23,6 +23,7 @@ #include <libsolidity/interface/Exceptions.h> #include <boost/variant.hpp> +#include <boost/optional.hpp> #include <functional> #include <memory> @@ -75,8 +76,7 @@ struct Scope struct Label { - size_t id = unassignedLabelId; - static const size_t unassignedLabelId = 0; + boost::optional<size_t> id; }; struct Function diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h index 77a7e02a..e223ccc9 100644 --- a/libsolidity/inlineasm/AsmStack.h +++ b/libsolidity/inlineasm/AsmStack.h @@ -24,6 +24,8 @@ #include <libsolidity/interface/Exceptions.h> +#include <libjulia/backends/AbstractAssembly.h> + #include <string> #include <functional> @@ -51,7 +53,7 @@ struct ExternalIdentifierAccess /// Resolve a an external reference given by the identifier in the given context. /// @returns the size of the value (number of stack slots) or size_t(-1) if not found. Resolver resolve; - using CodeGenerator = std::function<void(assembly::Identifier const&, IdentifierContext, eth::Assembly&)>; + using CodeGenerator = std::function<void(assembly::Identifier const&, IdentifierContext, julia::AbstractAssembly&)>; /// Generate code for retrieving the value (rvalue context) or storing the value (lvalue context) /// of an identifier. The code should be appended to the assembly. In rvalue context, the value is supposed /// to be put onto the stack, in lvalue context, the value is assumed to be at the top of the stack. diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 503be57b..d5dbaa46 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -377,7 +377,8 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) { Json::Value sourceResult = Json::objectValue; sourceResult["id"] = sourceIndex++; - sourceResult["legacyAST"] = ASTJsonConverter(m_compilerStack.ast(source), m_compilerStack.sourceIndices()).json(); + sourceResult["ast"] = ASTJsonConverter(false, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(source)); + sourceResult["legacyAST"] = ASTJsonConverter(true, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(source)); output["sources"][source] = sourceResult; } |