mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge branch 'develop' into build_enhancement
This commit is contained in:
commit
6afb6757d7
69
AST.cpp
69
AST.cpp
@ -33,6 +33,19 @@ namespace dev
|
|||||||
namespace solidity
|
namespace solidity
|
||||||
{
|
{
|
||||||
|
|
||||||
|
void SourceUnit::accept(ASTVisitor& _visitor)
|
||||||
|
{
|
||||||
|
if (_visitor.visit(*this))
|
||||||
|
listAccept(m_nodes, _visitor);
|
||||||
|
_visitor.endVisit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportDirective::accept(ASTVisitor& _visitor)
|
||||||
|
{
|
||||||
|
_visitor.visit(*this);
|
||||||
|
_visitor.endVisit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
void ContractDefinition::accept(ASTVisitor& _visitor)
|
void ContractDefinition::accept(ASTVisitor& _visitor)
|
||||||
{
|
{
|
||||||
if (_visitor.visit(*this))
|
if (_visitor.visit(*this))
|
||||||
@ -57,34 +70,6 @@ void StructDefinition::checkValidityOfMembers()
|
|||||||
checkRecursion();
|
checkRecursion();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StructDefinition::checkMemberTypes()
|
|
||||||
{
|
|
||||||
for (ASTPointer<VariableDeclaration> const& member: getMembers())
|
|
||||||
if (!member->getType()->canBeStored())
|
|
||||||
BOOST_THROW_EXCEPTION(member->createTypeError("Type cannot be used in struct."));
|
|
||||||
}
|
|
||||||
|
|
||||||
void StructDefinition::checkRecursion()
|
|
||||||
{
|
|
||||||
set<StructDefinition const*> definitionsSeen;
|
|
||||||
vector<StructDefinition const*> queue = {this};
|
|
||||||
while (!queue.empty())
|
|
||||||
{
|
|
||||||
StructDefinition const* def = queue.back();
|
|
||||||
queue.pop_back();
|
|
||||||
if (definitionsSeen.count(def))
|
|
||||||
BOOST_THROW_EXCEPTION(ParserError() << errinfo_sourceLocation(def->getLocation())
|
|
||||||
<< errinfo_comment("Recursive struct definition."));
|
|
||||||
definitionsSeen.insert(def);
|
|
||||||
for (ASTPointer<VariableDeclaration> const& member: def->getMembers())
|
|
||||||
if (member->getType()->getCategory() == Type::Category::STRUCT)
|
|
||||||
{
|
|
||||||
UserDefinedTypeName const& typeName = dynamic_cast<UserDefinedTypeName&>(*member->getTypeName());
|
|
||||||
queue.push_back(&dynamic_cast<StructDefinition const&>(*typeName.getReferencedDeclaration()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ParameterList::accept(ASTVisitor& _visitor)
|
void ParameterList::accept(ASTVisitor& _visitor)
|
||||||
{
|
{
|
||||||
if (_visitor.visit(*this))
|
if (_visitor.visit(*this))
|
||||||
@ -312,6 +297,34 @@ vector<FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() co
|
|||||||
return exportedFunctions;
|
return exportedFunctions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StructDefinition::checkMemberTypes()
|
||||||
|
{
|
||||||
|
for (ASTPointer<VariableDeclaration> const& member: getMembers())
|
||||||
|
if (!member->getType()->canBeStored())
|
||||||
|
BOOST_THROW_EXCEPTION(member->createTypeError("Type cannot be used in struct."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StructDefinition::checkRecursion()
|
||||||
|
{
|
||||||
|
set<StructDefinition const*> definitionsSeen;
|
||||||
|
vector<StructDefinition const*> queue = {this};
|
||||||
|
while (!queue.empty())
|
||||||
|
{
|
||||||
|
StructDefinition const* def = queue.back();
|
||||||
|
queue.pop_back();
|
||||||
|
if (definitionsSeen.count(def))
|
||||||
|
BOOST_THROW_EXCEPTION(ParserError() << errinfo_sourceLocation(def->getLocation())
|
||||||
|
<< errinfo_comment("Recursive struct definition."));
|
||||||
|
definitionsSeen.insert(def);
|
||||||
|
for (ASTPointer<VariableDeclaration> const& member: def->getMembers())
|
||||||
|
if (member->getType()->getCategory() == Type::Category::STRUCT)
|
||||||
|
{
|
||||||
|
UserDefinedTypeName const& typeName = dynamic_cast<UserDefinedTypeName&>(*member->getTypeName());
|
||||||
|
queue.push_back(&dynamic_cast<StructDefinition const&>(*typeName.getReferencedDeclaration()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FunctionDefinition::checkTypeRequirements()
|
void FunctionDefinition::checkTypeRequirements()
|
||||||
{
|
{
|
||||||
for (ASTPointer<VariableDeclaration> const& var: getParameters() + getReturnParameters())
|
for (ASTPointer<VariableDeclaration> const& var: getParameters() + getReturnParameters())
|
||||||
|
36
AST.h
36
AST.h
@ -79,6 +79,42 @@ private:
|
|||||||
Location m_location;
|
Location m_location;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source unit containing import directives and contract definitions.
|
||||||
|
*/
|
||||||
|
class SourceUnit: public ASTNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SourceUnit(Location const& _location, std::vector<ASTPointer<ASTNode>> const& _nodes):
|
||||||
|
ASTNode(_location), m_nodes(_nodes) {}
|
||||||
|
|
||||||
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
|
|
||||||
|
std::vector<ASTPointer<ASTNode>> getNodes() const { return m_nodes; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<ASTPointer<ASTNode>> m_nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import directive for referencing other files / source objects.
|
||||||
|
* Example: import "abc.sol"
|
||||||
|
* Source objects are identified by a string which can be a file name but does not have to be.
|
||||||
|
*/
|
||||||
|
class ImportDirective: public ASTNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImportDirective(Location const& _location, ASTPointer<ASTString> const& _identifier):
|
||||||
|
ASTNode(_location), m_identifier(_identifier) {}
|
||||||
|
|
||||||
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
|
|
||||||
|
ASTString const& getIdentifier() const { return *m_identifier; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ASTPointer<ASTString> m_identifier;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract AST class for a declaration (contract, function, struct, variable).
|
* Abstract AST class for a declaration (contract, function, struct, variable).
|
||||||
*/
|
*/
|
||||||
|
@ -34,6 +34,8 @@ namespace solidity
|
|||||||
{
|
{
|
||||||
|
|
||||||
class ASTNode;
|
class ASTNode;
|
||||||
|
class SourceUnit;
|
||||||
|
class ImportDirective;
|
||||||
class Declaration;
|
class Declaration;
|
||||||
class ContractDefinition;
|
class ContractDefinition;
|
||||||
class StructDefinition;
|
class StructDefinition;
|
||||||
|
@ -43,6 +43,13 @@ void ASTPrinter::print(ostream& _stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ASTPrinter::visit(ImportDirective& _node)
|
||||||
|
{
|
||||||
|
writeLine("ImportDirective \"" + _node.getIdentifier() + "\"");
|
||||||
|
printSourcePart(_node);
|
||||||
|
return goDeeper();
|
||||||
|
}
|
||||||
|
|
||||||
bool ASTPrinter::visit(ContractDefinition& _node)
|
bool ASTPrinter::visit(ContractDefinition& _node)
|
||||||
{
|
{
|
||||||
writeLine("ContractDefinition \"" + _node.getName() + "\"");
|
writeLine("ContractDefinition \"" + _node.getName() + "\"");
|
||||||
@ -270,7 +277,7 @@ bool ASTPrinter::visit(Literal& _node)
|
|||||||
return goDeeper();
|
return goDeeper();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTPrinter::endVisit(ASTNode&)
|
void ASTPrinter::endVisit(ImportDirective&)
|
||||||
{
|
{
|
||||||
m_indentation--;
|
m_indentation--;
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ public:
|
|||||||
/// Output the string representation of the AST to _stream.
|
/// Output the string representation of the AST to _stream.
|
||||||
void print(std::ostream& _stream);
|
void print(std::ostream& _stream);
|
||||||
|
|
||||||
|
bool visit(ImportDirective& _node) override;
|
||||||
bool visit(ContractDefinition& _node) override;
|
bool visit(ContractDefinition& _node) override;
|
||||||
bool visit(StructDefinition& _node) override;
|
bool visit(StructDefinition& _node) override;
|
||||||
bool visit(ParameterList& _node) override;
|
bool visit(ParameterList& _node) override;
|
||||||
@ -73,7 +74,7 @@ public:
|
|||||||
bool visit(ElementaryTypeNameExpression& _node) override;
|
bool visit(ElementaryTypeNameExpression& _node) override;
|
||||||
bool visit(Literal& _node) override;
|
bool visit(Literal& _node) override;
|
||||||
|
|
||||||
void endVisit(ASTNode& _node) override;
|
void endVisit(ImportDirective&) override;
|
||||||
void endVisit(ContractDefinition&) override;
|
void endVisit(ContractDefinition&) override;
|
||||||
void endVisit(StructDefinition&) override;
|
void endVisit(StructDefinition&) override;
|
||||||
void endVisit(ParameterList&) override;
|
void endVisit(ParameterList&) override;
|
||||||
|
@ -42,6 +42,8 @@ class ASTVisitor
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual bool visit(ASTNode&) { return true; }
|
virtual bool visit(ASTNode&) { return true; }
|
||||||
|
virtual bool visit(SourceUnit&) { return true; }
|
||||||
|
virtual bool visit(ImportDirective&) { return true; }
|
||||||
virtual bool visit(ContractDefinition&) { return true; }
|
virtual bool visit(ContractDefinition&) { return true; }
|
||||||
virtual bool visit(StructDefinition&) { return true; }
|
virtual bool visit(StructDefinition&) { return true; }
|
||||||
virtual bool visit(ParameterList&) { return true; }
|
virtual bool visit(ParameterList&) { return true; }
|
||||||
@ -74,6 +76,8 @@ public:
|
|||||||
virtual bool visit(Literal&) { return true; }
|
virtual bool visit(Literal&) { return true; }
|
||||||
|
|
||||||
virtual void endVisit(ASTNode&) { }
|
virtual void endVisit(ASTNode&) { }
|
||||||
|
virtual void endVisit(SourceUnit&) { }
|
||||||
|
virtual void endVisit(ImportDirective&) { }
|
||||||
virtual void endVisit(ContractDefinition&) { }
|
virtual void endVisit(ContractDefinition&) { }
|
||||||
virtual void endVisit(StructDefinition&) { }
|
virtual void endVisit(StructDefinition&) { }
|
||||||
virtual void endVisit(ParameterList&) { }
|
virtual void endVisit(ParameterList&) { }
|
||||||
|
10
BaseTypes.h
10
BaseTypes.h
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
@ -35,19 +37,19 @@ namespace solidity
|
|||||||
*/
|
*/
|
||||||
struct Location
|
struct Location
|
||||||
{
|
{
|
||||||
Location(int _start, int _end): start(_start), end(_end) { }
|
Location(int _start, int _end, std::shared_ptr<std::string const> _sourceName):
|
||||||
|
start(_start), end(_end), sourceName(_sourceName) { }
|
||||||
Location(): start(-1), end(-1) { }
|
Location(): start(-1), end(-1) { }
|
||||||
|
|
||||||
bool IsValid() const { return start >= 0 && end >= start; }
|
|
||||||
|
|
||||||
int start;
|
int start;
|
||||||
int end;
|
int end;
|
||||||
|
std::shared_ptr<std::string const> sourceName;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Stream output for Location (used e.g. in boost exceptions).
|
/// Stream output for Location (used e.g. in boost exceptions).
|
||||||
inline std::ostream& operator<<(std::ostream& _out, Location const& _location)
|
inline std::ostream& operator<<(std::ostream& _out, Location const& _location)
|
||||||
{
|
{
|
||||||
return _out << "[" << _location.start << "," << _location.end << ")";
|
return _out << *_location.sourceName << "[" << _location.start << "," << _location.end << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -36,22 +36,43 @@ namespace dev
|
|||||||
namespace solidity
|
namespace solidity
|
||||||
{
|
{
|
||||||
|
|
||||||
CompilerStack::CompilerStack(): m_interfaceHandler(make_shared<InterfaceHandler>()) {}
|
void CompilerStack::addSource(string const& _name, string const& _content)
|
||||||
|
{
|
||||||
|
if (m_sources.count(_name))
|
||||||
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Source by given name already exists."));
|
||||||
|
|
||||||
|
reset(true);
|
||||||
|
m_sources[_name].scanner = make_shared<Scanner>(CharStream(_content), _name);
|
||||||
|
}
|
||||||
|
|
||||||
void CompilerStack::setSource(string const& _sourceCode)
|
void CompilerStack::setSource(string const& _sourceCode)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
m_scanner = make_shared<Scanner>(CharStream(_sourceCode));
|
addSource("", _sourceCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerStack::parse()
|
void CompilerStack::parse()
|
||||||
{
|
{
|
||||||
if (!m_scanner)
|
for (auto& sourcePair: m_sources)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Source not available."));
|
{
|
||||||
m_contractASTNode = Parser().parse(m_scanner);
|
sourcePair.second.scanner->reset();
|
||||||
|
sourcePair.second.ast = Parser().parse(sourcePair.second.scanner);
|
||||||
|
}
|
||||||
|
resolveImports();
|
||||||
|
|
||||||
m_globalContext = make_shared<GlobalContext>();
|
m_globalContext = make_shared<GlobalContext>();
|
||||||
m_globalContext->setCurrentContract(*m_contractASTNode);
|
NameAndTypeResolver resolver(m_globalContext->getDeclarations());
|
||||||
NameAndTypeResolver(m_globalContext->getDeclarations()).resolveNamesAndTypes(*m_contractASTNode);
|
for (Source const* source: m_sourceOrder)
|
||||||
|
resolver.registerDeclarations(*source->ast);
|
||||||
|
for (Source const* source: m_sourceOrder)
|
||||||
|
for (ASTPointer<ASTNode> const& node: source->ast->getNodes())
|
||||||
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
|
{
|
||||||
|
m_globalContext->setCurrentContract(*contract);
|
||||||
|
resolver.updateDeclaration(*m_globalContext->getCurrentThis());
|
||||||
|
resolver.resolveNamesAndTypes(*contract);
|
||||||
|
m_contracts[contract->getName()].contract = contract;
|
||||||
|
}
|
||||||
m_parseSuccessful = true;
|
m_parseSuccessful = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,54 +82,90 @@ void CompilerStack::parse(string const& _sourceCode)
|
|||||||
parse();
|
parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes const& CompilerStack::compile(bool _optimize)
|
vector<string> CompilerStack::getContractNames()
|
||||||
{
|
{
|
||||||
if (!m_parseSuccessful)
|
if (!m_parseSuccessful)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
||||||
m_bytecode.clear();
|
vector<string> contractNames;
|
||||||
m_compiler = make_shared<Compiler>();
|
for (auto const& contract: m_contracts)
|
||||||
m_compiler->compileContract(*m_contractASTNode, m_globalContext->getMagicVariables());
|
contractNames.push_back(contract.first);
|
||||||
return m_bytecode = m_compiler->getAssembledBytecode(_optimize);
|
return contractNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerStack::compile(bool _optimize)
|
||||||
|
{
|
||||||
|
if (!m_parseSuccessful)
|
||||||
|
parse();
|
||||||
|
for (Source const* source: m_sourceOrder)
|
||||||
|
for (ASTPointer<ASTNode> const& node: source->ast->getNodes())
|
||||||
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
|
{
|
||||||
|
m_globalContext->setCurrentContract(*contract);
|
||||||
|
shared_ptr<Compiler> compiler = make_shared<Compiler>();
|
||||||
|
compiler->compileContract(*contract, m_globalContext->getMagicVariables());
|
||||||
|
Contract& compiledContract = m_contracts[contract->getName()];
|
||||||
|
compiledContract.bytecode = compiler->getAssembledBytecode(_optimize);
|
||||||
|
compiledContract.compiler = move(compiler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize)
|
bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize)
|
||||||
{
|
{
|
||||||
parse(_sourceCode);
|
parse(_sourceCode);
|
||||||
return compile(_optimize);
|
compile(_optimize);
|
||||||
|
return getBytecode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerStack::streamAssembly(ostream& _outStream)
|
bytes const& CompilerStack::getBytecode(string const& _contractName)
|
||||||
{
|
{
|
||||||
if (!m_compiler || m_bytecode.empty())
|
return getContract(_contractName).bytecode;
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
|
|
||||||
m_compiler->streamAssembly(_outStream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const& CompilerStack::getJsonDocumentation(DocumentationType _type)
|
void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName)
|
||||||
|
{
|
||||||
|
getContract(_contractName).compiler->streamAssembly(_outStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
string const& CompilerStack::getInterface(std::string const& _contractName)
|
||||||
|
{
|
||||||
|
return getJsonDocumentation(_contractName, DocumentationType::ABI_INTERFACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const& CompilerStack::getJsonDocumentation(std::string const& _contractName, DocumentationType _type)
|
||||||
{
|
{
|
||||||
if (!m_parseSuccessful)
|
if (!m_parseSuccessful)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
||||||
|
|
||||||
auto createDocIfNotThere = [this, _type](std::unique_ptr<string>& _doc)
|
Contract& contract = getContract(_contractName);
|
||||||
{
|
|
||||||
if (!_doc)
|
|
||||||
_doc = m_interfaceHandler->getDocumentation(m_contractASTNode, _type);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
std::unique_ptr<string>* doc;
|
||||||
switch (_type)
|
switch (_type)
|
||||||
{
|
{
|
||||||
case DocumentationType::NATSPEC_USER:
|
case DocumentationType::NATSPEC_USER:
|
||||||
createDocIfNotThere(m_userDocumentation);
|
doc = &contract.userDocumentation;
|
||||||
return *m_userDocumentation;
|
break;
|
||||||
case DocumentationType::NATSPEC_DEV:
|
case DocumentationType::NATSPEC_DEV:
|
||||||
createDocIfNotThere(m_devDocumentation);
|
doc = &contract.devDocumentation;
|
||||||
return *m_devDocumentation;
|
break;
|
||||||
case DocumentationType::ABI_INTERFACE:
|
case DocumentationType::ABI_INTERFACE:
|
||||||
createDocIfNotThere(m_interface);
|
doc = &contract.interface;
|
||||||
return *m_interface;
|
break;
|
||||||
|
default:
|
||||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type."));
|
||||||
|
}
|
||||||
|
if (!*doc)
|
||||||
|
*doc = contract.interfaceHandler->getDocumentation(*contract.contract, _type);
|
||||||
|
return *(*doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type."));
|
Scanner const& CompilerStack::getScanner(string const& _sourceName)
|
||||||
|
{
|
||||||
|
return *getSource(_sourceName).scanner;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceUnit& CompilerStack::getAST(string const& _sourceName)
|
||||||
|
{
|
||||||
|
return *getSource(_sourceName).ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize)
|
bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize)
|
||||||
@ -117,7 +174,70 @@ bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimiz
|
|||||||
return stack.compile(_sourceCode, _optimize);
|
return stack.compile(_sourceCode, _optimize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompilerStack::reset(bool _keepSources)
|
||||||
|
{
|
||||||
|
m_parseSuccessful = false;
|
||||||
|
if (_keepSources)
|
||||||
|
for (auto sourcePair: m_sources)
|
||||||
|
sourcePair.second.reset();
|
||||||
|
else
|
||||||
|
m_sources.clear();
|
||||||
|
m_globalContext.reset();
|
||||||
|
m_sourceOrder.clear();
|
||||||
|
m_contracts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerStack::resolveImports()
|
||||||
|
{
|
||||||
|
// topological sorting (depth first search) of the import graph, cutting potential cycles
|
||||||
|
vector<Source const*> sourceOrder;
|
||||||
|
set<Source const*> sourcesSeen;
|
||||||
|
|
||||||
|
function<void(Source const*)> toposort = [&](Source const* _source)
|
||||||
|
{
|
||||||
|
if (sourcesSeen.count(_source))
|
||||||
|
return;
|
||||||
|
sourcesSeen.insert(_source);
|
||||||
|
for (ASTPointer<ASTNode> const& node: _source->ast->getNodes())
|
||||||
|
if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
|
||||||
|
{
|
||||||
|
string const& id = import->getIdentifier();
|
||||||
|
if (!m_sources.count(id))
|
||||||
|
BOOST_THROW_EXCEPTION(ParserError()
|
||||||
|
<< errinfo_sourceLocation(import->getLocation())
|
||||||
|
<< errinfo_comment("Source not found."));
|
||||||
|
toposort(&m_sources[id]);
|
||||||
|
}
|
||||||
|
sourceOrder.push_back(_source);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto const& sourcePair: m_sources)
|
||||||
|
toposort(&sourcePair.second);
|
||||||
|
|
||||||
|
swap(m_sourceOrder, sourceOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompilerStack::Contract& CompilerStack::getContract(string const& _contractName)
|
||||||
|
{
|
||||||
|
if (m_contracts.empty())
|
||||||
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
|
||||||
|
if (_contractName.empty())
|
||||||
|
return m_contracts.begin()->second;
|
||||||
|
auto it = m_contracts.find(_contractName);
|
||||||
|
if (it == m_contracts.end())
|
||||||
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract " + _contractName + " not found."));
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompilerStack::Source& CompilerStack::getSource(string const& _sourceName)
|
||||||
|
{
|
||||||
|
auto it = m_sources.find(_sourceName);
|
||||||
|
if (it == m_sources.end())
|
||||||
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Given source file not found."));
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompilerStack::Contract::Contract(): interfaceHandler(make_shared<InterfaceHandler>()) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <boost/noncopyable.hpp>
|
||||||
#include <libdevcore/Common.h>
|
#include <libdevcore/Common.h>
|
||||||
|
|
||||||
namespace dev {
|
namespace dev {
|
||||||
@ -33,6 +34,7 @@ namespace solidity {
|
|||||||
// forward declarations
|
// forward declarations
|
||||||
class Scanner;
|
class Scanner;
|
||||||
class ContractDefinition;
|
class ContractDefinition;
|
||||||
|
class SourceUnit;
|
||||||
class Compiler;
|
class Compiler;
|
||||||
class GlobalContext;
|
class GlobalContext;
|
||||||
class InterfaceHandler;
|
class InterfaceHandler;
|
||||||
@ -49,36 +51,44 @@ enum class DocumentationType: uint8_t
|
|||||||
* It holds state and can be used to either step through the compilation stages (and abort e.g.
|
* It holds state and can be used to either step through the compilation stages (and abort e.g.
|
||||||
* before compilation to bytecode) or run the whole compilation in one call.
|
* before compilation to bytecode) or run the whole compilation in one call.
|
||||||
*/
|
*/
|
||||||
class CompilerStack
|
class CompilerStack: boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CompilerStack();
|
CompilerStack(): m_parseSuccessful(false) {}
|
||||||
void reset() { *this = CompilerStack(); }
|
|
||||||
|
/// Adds a source object (e.g. file) to the parser. After this, parse has to be called again.
|
||||||
|
void addSource(std::string const& _name, std::string const& _content);
|
||||||
void setSource(std::string const& _sourceCode);
|
void setSource(std::string const& _sourceCode);
|
||||||
|
/// Parses all source units that were added
|
||||||
void parse();
|
void parse();
|
||||||
|
/// Sets the given source code as the only source unit and parses it.
|
||||||
void parse(std::string const& _sourceCode);
|
void parse(std::string const& _sourceCode);
|
||||||
/// Compiles the contract that was previously parsed.
|
/// Returns a list of the contract names in the sources.
|
||||||
bytes const& compile(bool _optimize = false);
|
std::vector<std::string> getContractNames();
|
||||||
|
|
||||||
|
/// Compiles the source units that were previously added and parsed.
|
||||||
|
void compile(bool _optimize = false);
|
||||||
/// Parses and compiles the given source code.
|
/// Parses and compiles the given source code.
|
||||||
|
/// @returns the compiled bytecode
|
||||||
bytes const& compile(std::string const& _sourceCode, bool _optimize = false);
|
bytes const& compile(std::string const& _sourceCode, bool _optimize = false);
|
||||||
|
|
||||||
bytes const& getBytecode() const { return m_bytecode; }
|
bytes const& getBytecode(std::string const& _contractName = "");
|
||||||
/// Streams a verbose version of the assembly to @a _outStream.
|
/// Streams a verbose version of the assembly to @a _outStream.
|
||||||
/// Prerequisite: Successful compilation.
|
/// Prerequisite: Successful compilation.
|
||||||
void streamAssembly(std::ostream& _outStream);
|
void streamAssembly(std::ostream& _outStream, std::string const& _contractName = "");
|
||||||
|
|
||||||
/// Returns a string representing the contract interface in JSON.
|
/// Returns a string representing the contract interface in JSON.
|
||||||
/// Prerequisite: Successful call to parse or compile.
|
/// Prerequisite: Successful call to parse or compile.
|
||||||
std::string const& getInterface();
|
std::string const& getInterface(std::string const& _contractName = "");
|
||||||
/// Returns a string representing the contract's documentation in JSON.
|
/// Returns a string representing the contract's documentation in JSON.
|
||||||
/// Prerequisite: Successful call to parse or compile.
|
/// Prerequisite: Successful call to parse or compile.
|
||||||
/// @param type The type of the documentation to get.
|
/// @param type The type of the documentation to get.
|
||||||
/// Can be one of 3 types defined at @c documentation_type
|
/// Can be one of 3 types defined at @c DocumentationType
|
||||||
std::string const& getJsonDocumentation(DocumentationType type);
|
std::string const& getJsonDocumentation(std::string const& _contractName, DocumentationType _type);
|
||||||
|
|
||||||
/// Returns the previously used scanner, useful for counting lines during error reporting.
|
/// Returns the previously used scanner, useful for counting lines during error reporting.
|
||||||
Scanner const& getScanner() const { return *m_scanner; }
|
Scanner const& getScanner(std::string const& _sourceName = "");
|
||||||
ContractDefinition& getAST() const { return *m_contractASTNode; }
|
SourceUnit& getAST(std::string const& _sourceName = "");
|
||||||
|
|
||||||
/// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for
|
/// Compile the given @a _sourceCode to bytecode. If a scanner is provided, it is used for
|
||||||
/// scanning the source code - this is useful for printing exception information.
|
/// scanning the source code - this is useful for printing exception information.
|
||||||
@ -101,16 +111,41 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Scanner> m_scanner;
|
/**
|
||||||
std::shared_ptr<GlobalContext> m_globalContext;
|
* Information pertaining to one source unit, filled gradually during parsing and compilation.
|
||||||
std::shared_ptr<ContractDefinition> m_contractASTNode;
|
*/
|
||||||
|
struct Source
|
||||||
|
{
|
||||||
|
std::shared_ptr<Scanner> scanner;
|
||||||
|
std::shared_ptr<SourceUnit> ast;
|
||||||
|
std::string interface;
|
||||||
|
void reset() { scanner.reset(); ast.reset(); interface.clear(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Contract
|
||||||
|
{
|
||||||
|
ContractDefinition* contract;
|
||||||
|
std::shared_ptr<Compiler> compiler;
|
||||||
|
bytes bytecode;
|
||||||
|
std::shared_ptr<InterfaceHandler> interfaceHandler;
|
||||||
|
std::unique_ptr<std::string> interface;
|
||||||
|
std::unique_ptr<std::string> userDocumentation;
|
||||||
|
std::unique_ptr<std::string> devDocumentation;
|
||||||
|
|
||||||
|
Contract();
|
||||||
|
};
|
||||||
|
|
||||||
|
void reset(bool _keepSources = false);
|
||||||
|
void resolveImports();
|
||||||
|
|
||||||
|
Contract& getContract(std::string const& _contractName = "");
|
||||||
|
Source& getSource(std::string const& _sourceName = "");
|
||||||
|
|
||||||
bool m_parseSuccessful;
|
bool m_parseSuccessful;
|
||||||
std::unique_ptr<std::string> m_interface;
|
std::map<std::string, Source> m_sources;
|
||||||
std::unique_ptr<std::string> m_userDocumentation;
|
std::shared_ptr<GlobalContext> m_globalContext;
|
||||||
std::unique_ptr<std::string> m_devDocumentation;
|
std::vector<Source const*> m_sourceOrder;
|
||||||
std::shared_ptr<Compiler> m_compiler;
|
std::map<std::string, Contract> m_contracts;
|
||||||
std::shared_ptr<InterfaceHandler> m_interfaceHandler;
|
|
||||||
bytes m_bytecode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,9 @@ namespace dev
|
|||||||
namespace solidity
|
namespace solidity
|
||||||
{
|
{
|
||||||
|
|
||||||
bool DeclarationContainer::registerDeclaration(Declaration& _declaration)
|
bool DeclarationContainer::registerDeclaration(Declaration& _declaration, bool _update)
|
||||||
{
|
{
|
||||||
if (m_declarations.find(_declaration.getName()) != m_declarations.end())
|
if (!_update && m_declarations.find(_declaration.getName()) != m_declarations.end())
|
||||||
return false;
|
return false;
|
||||||
m_declarations[_declaration.getName()] = &_declaration;
|
m_declarations[_declaration.getName()] = &_declaration;
|
||||||
return true;
|
return true;
|
||||||
|
@ -43,7 +43,7 @@ public:
|
|||||||
m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {}
|
m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {}
|
||||||
/// Registers the declaration in the scope unless its name is already declared. Returns true iff
|
/// Registers the declaration in the scope unless its name is already declared. Returns true iff
|
||||||
/// it was not yet declared.
|
/// it was not yet declared.
|
||||||
bool registerDeclaration(Declaration& _declaration);
|
bool registerDeclaration(Declaration& _declaration, bool _update = false);
|
||||||
Declaration* resolveName(ASTString const& _name, bool _recursive = false) const;
|
Declaration* resolveName(ASTString const& _name, bool _recursive = false) const;
|
||||||
Declaration* getEnclosingDeclaration() const { return m_enclosingDeclaration; }
|
Declaration* getEnclosingDeclaration() const { return m_enclosingDeclaration; }
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@ struct CompilerError: virtual Exception {};
|
|||||||
struct InternalCompilerError: virtual Exception {};
|
struct InternalCompilerError: virtual Exception {};
|
||||||
struct DocstringParsingError: virtual Exception {};
|
struct DocstringParsingError: virtual Exception {};
|
||||||
|
|
||||||
typedef boost::error_info<struct tag_sourcePosition, int> errinfo_sourcePosition;
|
|
||||||
typedef boost::error_info<struct tag_sourceLocation, Location> errinfo_sourceLocation;
|
typedef boost::error_info<struct tag_sourceLocation, Location> errinfo_sourceLocation;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,6 @@ vector<Declaration*> GlobalContext::getDeclarations() const
|
|||||||
declarations.reserve(m_magicVariables.size() + 1);
|
declarations.reserve(m_magicVariables.size() + 1);
|
||||||
for (ASTPointer<Declaration> const& variable: m_magicVariables)
|
for (ASTPointer<Declaration> const& variable: m_magicVariables)
|
||||||
declarations.push_back(variable.get());
|
declarations.push_back(variable.get());
|
||||||
declarations.push_back(getCurrentThis());
|
|
||||||
return declarations;
|
return declarations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,12 +47,14 @@ class GlobalContext: private boost::noncopyable
|
|||||||
public:
|
public:
|
||||||
GlobalContext();
|
GlobalContext();
|
||||||
void setCurrentContract(ContractDefinition const& _contract);
|
void setCurrentContract(ContractDefinition const& _contract);
|
||||||
|
MagicVariableDeclaration* getCurrentThis() const;
|
||||||
|
|
||||||
|
/// @returns all magic variables.
|
||||||
std::vector<MagicVariableDeclaration const*> getMagicVariables() const;
|
std::vector<MagicVariableDeclaration const*> getMagicVariables() const;
|
||||||
|
/// @returns a vector of all implicit global declarations excluding "this".
|
||||||
std::vector<Declaration*> getDeclarations() const;
|
std::vector<Declaration*> getDeclarations() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MagicVariableDeclaration* getCurrentThis() const;
|
|
||||||
std::vector<std::shared_ptr<MagicVariableDeclaration>> m_magicVariables;
|
std::vector<std::shared_ptr<MagicVariableDeclaration>> m_magicVariables;
|
||||||
ContractDefinition const* m_currentContract;
|
ContractDefinition const* m_currentContract;
|
||||||
std::map<ContractDefinition const*, std::shared_ptr<MagicVariableDeclaration>> mutable m_thisPointer;
|
std::map<ContractDefinition const*, std::shared_ptr<MagicVariableDeclaration>> mutable m_thisPointer;
|
||||||
|
@ -15,7 +15,7 @@ InterfaceHandler::InterfaceHandler()
|
|||||||
m_lastTag = DocTagType::NONE;
|
m_lastTag = DocTagType::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<std::string> InterfaceHandler::getDocumentation(std::shared_ptr<ContractDefinition> _contractDef,
|
std::unique_ptr<std::string> InterfaceHandler::getDocumentation(ContractDefinition& _contractDef,
|
||||||
DocumentationType _type)
|
DocumentationType _type)
|
||||||
{
|
{
|
||||||
switch(_type)
|
switch(_type)
|
||||||
@ -32,11 +32,11 @@ std::unique_ptr<std::string> InterfaceHandler::getDocumentation(std::shared_ptr<
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<std::string> InterfaceHandler::getABIInterface(std::shared_ptr<ContractDefinition> _contractDef)
|
std::unique_ptr<std::string> InterfaceHandler::getABIInterface(ContractDefinition& _contractDef)
|
||||||
{
|
{
|
||||||
Json::Value methods(Json::arrayValue);
|
Json::Value methods(Json::arrayValue);
|
||||||
|
|
||||||
for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions())
|
for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
|
||||||
{
|
{
|
||||||
Json::Value method;
|
Json::Value method;
|
||||||
Json::Value inputs(Json::arrayValue);
|
Json::Value inputs(Json::arrayValue);
|
||||||
@ -63,12 +63,12 @@ std::unique_ptr<std::string> InterfaceHandler::getABIInterface(std::shared_ptr<C
|
|||||||
return std::unique_ptr<std::string>(new std::string(m_writer.write(methods)));
|
return std::unique_ptr<std::string>(new std::string(m_writer.write(methods)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(std::shared_ptr<ContractDefinition> _contractDef)
|
std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefinition& _contractDef)
|
||||||
{
|
{
|
||||||
Json::Value doc;
|
Json::Value doc;
|
||||||
Json::Value methods(Json::objectValue);
|
Json::Value methods(Json::objectValue);
|
||||||
|
|
||||||
for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions())
|
for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
|
||||||
{
|
{
|
||||||
Json::Value user;
|
Json::Value user;
|
||||||
auto strPtr = f->getDocumentation();
|
auto strPtr = f->getDocumentation();
|
||||||
@ -88,14 +88,14 @@ std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(std::shared_
|
|||||||
return std::unique_ptr<std::string>(new std::string(m_writer.write(doc)));
|
return std::unique_ptr<std::string>(new std::string(m_writer.write(doc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(std::shared_ptr<ContractDefinition> _contractDef)
|
std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefinition& _contractDef)
|
||||||
{
|
{
|
||||||
// LTODO: Somewhere in this function warnings for mismatch of param names
|
// LTODO: Somewhere in this function warnings for mismatch of param names
|
||||||
// should be thrown
|
// should be thrown
|
||||||
Json::Value doc;
|
Json::Value doc;
|
||||||
Json::Value methods(Json::objectValue);
|
Json::Value methods(Json::objectValue);
|
||||||
|
|
||||||
for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions())
|
for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
|
||||||
{
|
{
|
||||||
Json::Value method;
|
Json::Value method;
|
||||||
auto strPtr = f->getDocumentation();
|
auto strPtr = f->getDocumentation();
|
||||||
|
@ -59,23 +59,23 @@ public:
|
|||||||
/// types provided by @c DocumentationType
|
/// types provided by @c DocumentationType
|
||||||
/// @return A unique pointer contained string with the json
|
/// @return A unique pointer contained string with the json
|
||||||
/// representation of provided type
|
/// representation of provided type
|
||||||
std::unique_ptr<std::string> getDocumentation(std::shared_ptr<ContractDefinition> _contractDef,
|
std::unique_ptr<std::string> getDocumentation(ContractDefinition& _contractDef,
|
||||||
DocumentationType _type);
|
DocumentationType _type);
|
||||||
/// Get the ABI Interface of the contract
|
/// Get the ABI Interface of the contract
|
||||||
/// @param _contractDef The contract definition
|
/// @param _contractDef The contract definition
|
||||||
/// @return A unique pointer contained string with the json
|
/// @return A unique pointer contained string with the json
|
||||||
/// representation of the contract's ABI Interface
|
/// representation of the contract's ABI Interface
|
||||||
std::unique_ptr<std::string> getABIInterface(std::shared_ptr<ContractDefinition> _contractDef);
|
std::unique_ptr<std::string> getABIInterface(ContractDefinition& _contractDef);
|
||||||
/// Get the User documentation of the contract
|
/// Get the User documentation of the contract
|
||||||
/// @param _contractDef The contract definition
|
/// @param _contractDef The contract definition
|
||||||
/// @return A unique pointer contained string with the json
|
/// @return A unique pointer contained string with the json
|
||||||
/// representation of the contract's user documentation
|
/// representation of the contract's user documentation
|
||||||
std::unique_ptr<std::string> getUserDocumentation(std::shared_ptr<ContractDefinition> _contractDef);
|
std::unique_ptr<std::string> getUserDocumentation(ContractDefinition& _contractDef);
|
||||||
/// Get the Developer's documentation of the contract
|
/// Get the Developer's documentation of the contract
|
||||||
/// @param _contractDef The contract definition
|
/// @param _contractDef The contract definition
|
||||||
/// @return A unique pointer contained string with the json
|
/// @return A unique pointer contained string with the json
|
||||||
/// representation of the contract's developer documentation
|
/// representation of the contract's developer documentation
|
||||||
std::unique_ptr<std::string> getDevDocumentation(std::shared_ptr<ContractDefinition> _contractDef);
|
std::unique_ptr<std::string> getDevDocumentation(ContractDefinition& _contractDef);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resetUser();
|
void resetUser();
|
||||||
|
@ -38,9 +38,14 @@ NameAndTypeResolver::NameAndTypeResolver(std::vector<Declaration*> const& _globa
|
|||||||
m_scopes[nullptr].registerDeclaration(*declaration);
|
m_scopes[nullptr].registerDeclaration(*declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit)
|
||||||
|
{
|
||||||
|
// The helper registers all declarations in m_scopes as a side-effect of its construction.
|
||||||
|
DeclarationRegistrationHelper registrar(m_scopes, _sourceUnit);
|
||||||
|
}
|
||||||
|
|
||||||
void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
||||||
{
|
{
|
||||||
DeclarationRegistrationHelper registrar(m_scopes, _contract);
|
|
||||||
m_currentScope = &m_scopes[&_contract];
|
m_currentScope = &m_scopes[&_contract];
|
||||||
for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs())
|
for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs())
|
||||||
ReferencesResolver resolver(*structDef, *this, nullptr);
|
ReferencesResolver resolver(*structDef, *this, nullptr);
|
||||||
@ -65,6 +70,12 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
m_currentScope = &m_scopes[nullptr];
|
m_currentScope = &m_scopes[nullptr];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NameAndTypeResolver::updateDeclaration(Declaration& _declaration)
|
||||||
|
{
|
||||||
|
m_scopes[nullptr].registerDeclaration(_declaration, true);
|
||||||
|
_declaration.setScope(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
Declaration* NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const
|
Declaration* NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const
|
||||||
{
|
{
|
||||||
auto iterator = m_scopes.find(_scope);
|
auto iterator = m_scopes.find(_scope);
|
||||||
|
@ -42,7 +42,13 @@ class NameAndTypeResolver: private boost::noncopyable
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit NameAndTypeResolver(std::vector<Declaration*> const& _globals);
|
explicit NameAndTypeResolver(std::vector<Declaration*> const& _globals);
|
||||||
|
/// Registers all declarations found in the source unit.
|
||||||
|
void registerDeclarations(SourceUnit& _sourceUnit);
|
||||||
|
/// Resolves all names and types referenced from the given contract.
|
||||||
void resolveNamesAndTypes(ContractDefinition& _contract);
|
void resolveNamesAndTypes(ContractDefinition& _contract);
|
||||||
|
/// Updates the given global declaration (used for "this"). Not to be used with declarations
|
||||||
|
/// that create their own scope.
|
||||||
|
void updateDeclaration(Declaration& _declaration);
|
||||||
|
|
||||||
/// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted,
|
/// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted,
|
||||||
/// the global scope is used (i.e. the one containing only the contract).
|
/// the global scope is used (i.e. the one containing only the contract).
|
||||||
|
86
Parser.cpp
86
Parser.cpp
@ -20,30 +20,27 @@
|
|||||||
* Solidity parser.
|
* Solidity parser.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include <libdevcore/Log.h>
|
#include <libdevcore/Log.h>
|
||||||
#include <libsolidity/BaseTypes.h>
|
#include <libsolidity/BaseTypes.h>
|
||||||
#include <libsolidity/Parser.h>
|
#include <libsolidity/Parser.h>
|
||||||
#include <libsolidity/Scanner.h>
|
#include <libsolidity/Scanner.h>
|
||||||
#include <libsolidity/Exceptions.h>
|
#include <libsolidity/Exceptions.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
namespace dev
|
namespace dev
|
||||||
{
|
{
|
||||||
namespace solidity
|
namespace solidity
|
||||||
{
|
{
|
||||||
|
|
||||||
ASTPointer<ContractDefinition> Parser::parse(std::shared_ptr<Scanner> const& _scanner)
|
|
||||||
{
|
|
||||||
m_scanner = _scanner;
|
|
||||||
return parseContractDefinition();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// AST node factory that also tracks the begin and end position of an AST node
|
/// AST node factory that also tracks the begin and end position of an AST node
|
||||||
/// while it is being parsed
|
/// while it is being parsed
|
||||||
class Parser::ASTNodeFactory
|
class Parser::ASTNodeFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ASTNodeFactory(Parser const& _parser): m_parser(_parser), m_location(_parser.getPosition(), -1) {}
|
ASTNodeFactory(Parser const& _parser):
|
||||||
|
m_parser(_parser), m_location(_parser.getPosition(), -1, _parser.getSourceName()) {}
|
||||||
|
|
||||||
void markEndPosition() { m_location.end = m_parser.getEndPosition(); }
|
void markEndPosition() { m_location.end = m_parser.getEndPosition(); }
|
||||||
void setLocationEmpty() { m_location.end = m_location.start; }
|
void setLocationEmpty() { m_location.end = m_location.start; }
|
||||||
@ -55,7 +52,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (m_location.end < 0)
|
if (m_location.end < 0)
|
||||||
markEndPosition();
|
markEndPosition();
|
||||||
return std::make_shared<NodeType>(m_location, std::forward<Args>(_args)...);
|
return make_shared<NodeType>(m_location, forward<Args>(_args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -63,6 +60,33 @@ private:
|
|||||||
Location m_location;
|
Location m_location;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
|
||||||
|
{
|
||||||
|
m_scanner = _scanner;
|
||||||
|
ASTNodeFactory nodeFactory(*this);
|
||||||
|
vector<ASTPointer<ASTNode>> nodes;
|
||||||
|
while (_scanner->getCurrentToken() != Token::EOS)
|
||||||
|
{
|
||||||
|
switch (m_scanner->getCurrentToken())
|
||||||
|
{
|
||||||
|
case Token::IMPORT:
|
||||||
|
nodes.push_back(parseImportDirective());
|
||||||
|
break;
|
||||||
|
case Token::CONTRACT:
|
||||||
|
nodes.push_back(parseContractDefinition());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BOOST_THROW_EXCEPTION(createParserError(std::string("Expected import directive or contract definition.")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeFactory.createNode<SourceUnit>(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const string> const& Parser::getSourceName() const
|
||||||
|
{
|
||||||
|
return m_scanner->getSourceName();
|
||||||
|
}
|
||||||
|
|
||||||
int Parser::getPosition() const
|
int Parser::getPosition() const
|
||||||
{
|
{
|
||||||
return m_scanner->getCurrentLocation().start;
|
return m_scanner->getCurrentLocation().start;
|
||||||
@ -73,15 +97,27 @@ int Parser::getEndPosition() const
|
|||||||
return m_scanner->getCurrentLocation().end;
|
return m_scanner->getCurrentLocation().end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASTPointer<ImportDirective> Parser::parseImportDirective()
|
||||||
|
{
|
||||||
|
ASTNodeFactory nodeFactory(*this);
|
||||||
|
expectToken(Token::IMPORT);
|
||||||
|
if (m_scanner->getCurrentToken() != Token::STRING_LITERAL)
|
||||||
|
BOOST_THROW_EXCEPTION(createParserError("Expected string literal (URL)."));
|
||||||
|
ASTPointer<ASTString> url = getLiteralAndAdvance();
|
||||||
|
nodeFactory.markEndPosition();
|
||||||
|
expectToken(Token::SEMICOLON);
|
||||||
|
return nodeFactory.createNode<ImportDirective>(url);
|
||||||
|
}
|
||||||
|
|
||||||
ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
||||||
{
|
{
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
expectToken(Token::CONTRACT);
|
expectToken(Token::CONTRACT);
|
||||||
ASTPointer<ASTString> name = expectIdentifierToken();
|
ASTPointer<ASTString> name = expectIdentifierToken();
|
||||||
expectToken(Token::LBRACE);
|
expectToken(Token::LBRACE);
|
||||||
std::vector<ASTPointer<StructDefinition>> structs;
|
vector<ASTPointer<StructDefinition>> structs;
|
||||||
std::vector<ASTPointer<VariableDeclaration>> stateVariables;
|
vector<ASTPointer<VariableDeclaration>> stateVariables;
|
||||||
std::vector<ASTPointer<FunctionDefinition>> functions;
|
vector<ASTPointer<FunctionDefinition>> functions;
|
||||||
bool visibilityIsPublic = true;
|
bool visibilityIsPublic = true;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@ -110,7 +146,6 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
|
|||||||
}
|
}
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
expectToken(Token::RBRACE);
|
expectToken(Token::RBRACE);
|
||||||
expectToken(Token::EOS);
|
|
||||||
return nodeFactory.createNode<ContractDefinition>(name, structs, stateVariables, functions);
|
return nodeFactory.createNode<ContractDefinition>(name, structs, stateVariables, functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +154,7 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
|
|||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
ASTPointer<ASTString> docstring;
|
ASTPointer<ASTString> docstring;
|
||||||
if (m_scanner->getCurrentCommentLiteral() != "")
|
if (m_scanner->getCurrentCommentLiteral() != "")
|
||||||
docstring = std::make_shared<ASTString>(m_scanner->getCurrentCommentLiteral());
|
docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral());
|
||||||
|
|
||||||
expectToken(Token::FUNCTION);
|
expectToken(Token::FUNCTION);
|
||||||
ASTPointer<ASTString> name(expectIdentifierToken());
|
ASTPointer<ASTString> name(expectIdentifierToken());
|
||||||
@ -142,7 +177,7 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
|
|||||||
// create an empty parameter list at a zero-length location
|
// create an empty parameter list at a zero-length location
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
nodeFactory.setLocationEmpty();
|
nodeFactory.setLocationEmpty();
|
||||||
returnParameters = nodeFactory.createNode<ParameterList>(std::vector<ASTPointer<VariableDeclaration>>());
|
returnParameters = nodeFactory.createNode<ParameterList>(vector<ASTPointer<VariableDeclaration>>());
|
||||||
}
|
}
|
||||||
ASTPointer<Block> block = parseBlock();
|
ASTPointer<Block> block = parseBlock();
|
||||||
nodeFactory.setEndPositionFromNode(block);
|
nodeFactory.setEndPositionFromNode(block);
|
||||||
@ -156,7 +191,7 @@ ASTPointer<StructDefinition> Parser::parseStructDefinition()
|
|||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
expectToken(Token::STRUCT);
|
expectToken(Token::STRUCT);
|
||||||
ASTPointer<ASTString> name = expectIdentifierToken();
|
ASTPointer<ASTString> name = expectIdentifierToken();
|
||||||
std::vector<ASTPointer<VariableDeclaration>> members;
|
vector<ASTPointer<VariableDeclaration>> members;
|
||||||
expectToken(Token::LBRACE);
|
expectToken(Token::LBRACE);
|
||||||
while (m_scanner->getCurrentToken() != Token::RBRACE)
|
while (m_scanner->getCurrentToken() != Token::RBRACE)
|
||||||
{
|
{
|
||||||
@ -228,7 +263,7 @@ ASTPointer<Mapping> Parser::parseMapping()
|
|||||||
ASTPointer<ParameterList> Parser::parseParameterList(bool _allowEmpty)
|
ASTPointer<ParameterList> Parser::parseParameterList(bool _allowEmpty)
|
||||||
{
|
{
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
std::vector<ASTPointer<VariableDeclaration>> parameters;
|
vector<ASTPointer<VariableDeclaration>> parameters;
|
||||||
expectToken(Token::LPAREN);
|
expectToken(Token::LPAREN);
|
||||||
if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN)
|
if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN)
|
||||||
{
|
{
|
||||||
@ -249,7 +284,7 @@ ASTPointer<Block> Parser::parseBlock()
|
|||||||
{
|
{
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
expectToken(Token::LBRACE);
|
expectToken(Token::LBRACE);
|
||||||
std::vector<ASTPointer<Statement>> statements;
|
vector<ASTPointer<Statement>> statements;
|
||||||
while (m_scanner->getCurrentToken() != Token::RBRACE)
|
while (m_scanner->getCurrentToken() != Token::RBRACE)
|
||||||
statements.push_back(parseStatement());
|
statements.push_back(parseStatement());
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
@ -447,7 +482,7 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression()
|
|||||||
case Token::LPAREN:
|
case Token::LPAREN:
|
||||||
{
|
{
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
std::vector<ASTPointer<Expression>> arguments = parseFunctionCallArguments();
|
vector<ASTPointer<Expression>> arguments = parseFunctionCallArguments();
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
expectToken(Token::RPAREN);
|
expectToken(Token::RPAREN);
|
||||||
expression = nodeFactory.createNode<FunctionCall>(expression, arguments);
|
expression = nodeFactory.createNode<FunctionCall>(expression, arguments);
|
||||||
@ -503,9 +538,9 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
|
|||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
|
vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
|
||||||
{
|
{
|
||||||
std::vector<ASTPointer<Expression>> arguments;
|
vector<ASTPointer<Expression>> arguments;
|
||||||
if (m_scanner->getCurrentToken() != Token::RPAREN)
|
if (m_scanner->getCurrentToken() != Token::RPAREN)
|
||||||
{
|
{
|
||||||
arguments.push_back(parseExpression());
|
arguments.push_back(parseExpression());
|
||||||
@ -521,7 +556,7 @@ std::vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
|
|||||||
void Parser::expectToken(Token::Value _value)
|
void Parser::expectToken(Token::Value _value)
|
||||||
{
|
{
|
||||||
if (m_scanner->getCurrentToken() != _value)
|
if (m_scanner->getCurrentToken() != _value)
|
||||||
BOOST_THROW_EXCEPTION(createParserError(std::string("Expected token ") + std::string(Token::getName(_value))));
|
BOOST_THROW_EXCEPTION(createParserError(string("Expected token ") + string(Token::getName(_value))));
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,14 +578,15 @@ ASTPointer<ASTString> Parser::expectIdentifierToken()
|
|||||||
|
|
||||||
ASTPointer<ASTString> Parser::getLiteralAndAdvance()
|
ASTPointer<ASTString> Parser::getLiteralAndAdvance()
|
||||||
{
|
{
|
||||||
ASTPointer<ASTString> identifier = std::make_shared<ASTString>(m_scanner->getCurrentLiteral());
|
ASTPointer<ASTString> identifier = make_shared<ASTString>(m_scanner->getCurrentLiteral());
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParserError Parser::createParserError(std::string const& _description) const
|
ParserError Parser::createParserError(string const& _description) const
|
||||||
{
|
{
|
||||||
return ParserError() << errinfo_sourcePosition(getPosition()) << errinfo_comment(_description);
|
return ParserError() << errinfo_sourceLocation(Location(getPosition(), getPosition(), getSourceName()))
|
||||||
|
<< errinfo_comment(_description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
4
Parser.h
4
Parser.h
@ -34,7 +34,8 @@ class Scanner;
|
|||||||
class Parser
|
class Parser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ASTPointer<ContractDefinition> parse(std::shared_ptr<Scanner> const& _scanner);
|
ASTPointer<SourceUnit> parse(std::shared_ptr<Scanner> const& _scanner);
|
||||||
|
std::shared_ptr<std::string const> const& getSourceName() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class ASTNodeFactory;
|
class ASTNodeFactory;
|
||||||
@ -46,6 +47,7 @@ private:
|
|||||||
|
|
||||||
///@{
|
///@{
|
||||||
///@name Parsing functions for the AST nodes
|
///@name Parsing functions for the AST nodes
|
||||||
|
ASTPointer<ImportDirective> parseImportDirective();
|
||||||
ASTPointer<ContractDefinition> parseContractDefinition();
|
ASTPointer<ContractDefinition> parseContractDefinition();
|
||||||
ASTPointer<FunctionDefinition> parseFunctionDefinition(bool _isPublic);
|
ASTPointer<FunctionDefinition> parseFunctionDefinition(bool _isPublic);
|
||||||
ASTPointer<StructDefinition> parseStructDefinition();
|
ASTPointer<StructDefinition> parseStructDefinition();
|
||||||
|
11
Scanner.cpp
11
Scanner.cpp
@ -143,17 +143,22 @@ private:
|
|||||||
}; // end of LiteralScope class
|
}; // end of LiteralScope class
|
||||||
|
|
||||||
|
|
||||||
void Scanner::reset(CharStream const& _source)
|
void Scanner::reset(CharStream const& _source, string const& _sourceName)
|
||||||
{
|
{
|
||||||
m_source = _source;
|
m_source = _source;
|
||||||
|
m_sourceName = make_shared<string const>(_sourceName);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scanner::reset()
|
||||||
|
{
|
||||||
|
m_source.reset();
|
||||||
m_char = m_source.get();
|
m_char = m_source.get();
|
||||||
skipWhitespace();
|
skipWhitespace();
|
||||||
scanToken();
|
scanToken();
|
||||||
|
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Scanner::scanHexByte(char& o_scannedByte)
|
bool Scanner::scanHexByte(char& o_scannedByte)
|
||||||
{
|
{
|
||||||
char x = 0;
|
char x = 0;
|
||||||
|
14
Scanner.h
14
Scanner.h
@ -79,6 +79,8 @@ public:
|
|||||||
char advanceAndGet(size_t _chars=1);
|
char advanceAndGet(size_t _chars=1);
|
||||||
char rollback(size_t _amount);
|
char rollback(size_t _amount);
|
||||||
|
|
||||||
|
void reset() { m_pos = 0; }
|
||||||
|
|
||||||
///@{
|
///@{
|
||||||
///@name Error printing helper functions
|
///@name Error printing helper functions
|
||||||
/// Functions that help pretty-printing parse errors
|
/// Functions that help pretty-printing parse errors
|
||||||
@ -99,11 +101,12 @@ class Scanner
|
|||||||
friend class LiteralScope;
|
friend class LiteralScope;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Scanner() { reset(CharStream()); }
|
explicit Scanner(CharStream const& _source = CharStream(), std::string const& _sourceName = "") { reset(_source, _sourceName); }
|
||||||
explicit Scanner(CharStream const& _source) { reset(_source); }
|
|
||||||
|
|
||||||
/// Resets the scanner as if newly constructed with _input as input.
|
/// Resets the scanner as if newly constructed with _source and _sourceName as input.
|
||||||
void reset(CharStream const& _source);
|
void reset(CharStream const& _source, std::string const& _sourceName);
|
||||||
|
/// Resets scanner to the start of input.
|
||||||
|
void reset();
|
||||||
|
|
||||||
/// Returns the next token and advances input
|
/// Returns the next token and advances input
|
||||||
Token::Value next();
|
Token::Value next();
|
||||||
@ -139,6 +142,8 @@ public:
|
|||||||
std::string const& peekLiteral() const { return m_nextToken.literal; }
|
std::string const& peekLiteral() const { return m_nextToken.literal; }
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
|
std::shared_ptr<std::string const> const& getSourceName() const { return m_sourceName; }
|
||||||
|
|
||||||
///@{
|
///@{
|
||||||
///@name Error printing helper functions
|
///@name Error printing helper functions
|
||||||
/// Functions that help pretty-printing parse errors
|
/// Functions that help pretty-printing parse errors
|
||||||
@ -203,6 +208,7 @@ private:
|
|||||||
TokenDesc m_nextToken; // desc for next token (one token look-ahead)
|
TokenDesc m_nextToken; // desc for next token (one token look-ahead)
|
||||||
|
|
||||||
CharStream m_source;
|
CharStream m_source;
|
||||||
|
std::shared_ptr<std::string const> m_sourceName;
|
||||||
|
|
||||||
/// one character look-ahead, equals 0 at end of input
|
/// one character look-ahead, equals 0 at end of input
|
||||||
char m_char;
|
char m_char;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <libsolidity/SourceReferenceFormatter.h>
|
#include <libsolidity/SourceReferenceFormatter.h>
|
||||||
|
#include <libsolidity/CompilerStack.h>
|
||||||
#include <libsolidity/Scanner.h>
|
#include <libsolidity/Scanner.h>
|
||||||
#include <libsolidity/Exceptions.h>
|
#include <libsolidity/Exceptions.h>
|
||||||
|
|
||||||
@ -38,7 +39,6 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
|
|||||||
int startLine;
|
int startLine;
|
||||||
int startColumn;
|
int startColumn;
|
||||||
tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start);
|
tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start);
|
||||||
_stream << "starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n";
|
|
||||||
int endLine;
|
int endLine;
|
||||||
int endColumn;
|
int endColumn;
|
||||||
tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end);
|
tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end);
|
||||||
@ -58,37 +58,28 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
|
|||||||
<< "Spanning multiple lines.\n";
|
<< "Spanning multiple lines.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void SourceReferenceFormatter::printSourcePosition(ostream& _stream,
|
|
||||||
int _position,
|
|
||||||
const Scanner& _scanner)
|
|
||||||
{
|
|
||||||
int line;
|
|
||||||
int column;
|
|
||||||
tie(line, column) = _scanner.translatePositionToLineColumn(_position);
|
|
||||||
_stream << "at line " << (line + 1) << ", column " << (column + 1) << endl
|
|
||||||
<< _scanner.getLineAtPosition(_position) << endl
|
|
||||||
<< string(column, ' ') << "^" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SourceReferenceFormatter::printExceptionInformation(ostream& _stream,
|
void SourceReferenceFormatter::printExceptionInformation(ostream& _stream,
|
||||||
Exception const& _exception,
|
Exception const& _exception,
|
||||||
string const& _name,
|
string const& _name,
|
||||||
Scanner const& _scanner)
|
CompilerStack& _compiler)
|
||||||
{
|
{
|
||||||
|
Location const* location = boost::get_error_info<errinfo_sourceLocation>(_exception);
|
||||||
|
Scanner const* scanner;
|
||||||
|
|
||||||
|
if (location)
|
||||||
|
{
|
||||||
|
scanner = &_compiler.getScanner(*location->sourceName);
|
||||||
|
int startLine;
|
||||||
|
int startColumn;
|
||||||
|
tie(startLine, startColumn) = scanner->translatePositionToLineColumn(location->start);
|
||||||
|
_stream << *location->sourceName << ":" << (startLine + 1) << ":" << (startColumn + 1) << ": ";
|
||||||
|
}
|
||||||
_stream << _name;
|
_stream << _name;
|
||||||
if (string const* description = boost::get_error_info<errinfo_comment>(_exception))
|
if (string const* description = boost::get_error_info<errinfo_comment>(_exception))
|
||||||
_stream << ": " << *description;
|
_stream << ": " << *description << endl;
|
||||||
|
|
||||||
if (int const* position = boost::get_error_info<errinfo_sourcePosition>(_exception))
|
if (location)
|
||||||
{
|
printSourceLocation(_stream, *location, *scanner);
|
||||||
_stream << " ";
|
|
||||||
printSourcePosition(_stream, *position, _scanner);
|
|
||||||
}
|
|
||||||
if (Location const* location = boost::get_error_info<errinfo_sourceLocation>(_exception))
|
|
||||||
{
|
|
||||||
_stream << " ";
|
|
||||||
printSourceLocation(_stream, *location, _scanner);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,14 +34,14 @@ namespace solidity
|
|||||||
{
|
{
|
||||||
|
|
||||||
class Scanner; // forward
|
class Scanner; // forward
|
||||||
|
class CompilerStack; // forward
|
||||||
|
|
||||||
struct SourceReferenceFormatter
|
struct SourceReferenceFormatter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void printSourceLocation(std::ostream& _stream, Location const& _location, Scanner const& _scanner);
|
static void printSourceLocation(std::ostream& _stream, Location const& _location, Scanner const& _scanner);
|
||||||
static void printSourcePosition(std::ostream& _stream, int _position, Scanner const& _scanner);
|
|
||||||
static void printExceptionInformation(std::ostream& _stream, Exception const& _exception,
|
static void printExceptionInformation(std::ostream& _stream, Exception const& _exception,
|
||||||
std::string const& _name, Scanner const& _scanner);
|
std::string const& _name, CompilerStack& _compiler);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user