aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarek Kotewicz <marek.kotewicz@gmail.com>2014-12-08 20:56:30 +0800
committerMarek Kotewicz <marek.kotewicz@gmail.com>2014-12-08 20:56:30 +0800
commit6afb6757d785fab414915ab11c1784b585669143 (patch)
tree862171b42c5f76365d6ae0e3c50d3e1c4111343d
parentddf473aa0b3684ac2c3ad9f6135e3be6cb2b06e7 (diff)
parent260a1529a758fb7b75840e05d8c0be18975ff3b2 (diff)
downloaddexon-solidity-6afb6757d785fab414915ab11c1784b585669143.tar
dexon-solidity-6afb6757d785fab414915ab11c1784b585669143.tar.gz
dexon-solidity-6afb6757d785fab414915ab11c1784b585669143.tar.bz2
dexon-solidity-6afb6757d785fab414915ab11c1784b585669143.tar.lz
dexon-solidity-6afb6757d785fab414915ab11c1784b585669143.tar.xz
dexon-solidity-6afb6757d785fab414915ab11c1784b585669143.tar.zst
dexon-solidity-6afb6757d785fab414915ab11c1784b585669143.zip
Merge branch 'develop' into build_enhancement
-rw-r--r--AST.cpp69
-rw-r--r--AST.h36
-rw-r--r--ASTForward.h2
-rw-r--r--ASTPrinter.cpp9
-rw-r--r--ASTPrinter.h3
-rw-r--r--ASTVisitor.h4
-rw-r--r--BaseTypes.h10
-rw-r--r--CompilerStack.cpp180
-rw-r--r--CompilerStack.h77
-rw-r--r--DeclarationContainer.cpp4
-rw-r--r--DeclarationContainer.h2
-rw-r--r--Exceptions.h1
-rw-r--r--GlobalContext.cpp3
-rw-r--r--GlobalContext.h4
-rw-r--r--InterfaceHandler.cpp14
-rw-r--r--InterfaceHandler.h8
-rw-r--r--NameAndTypeResolver.cpp13
-rw-r--r--NameAndTypeResolver.h6
-rw-r--r--Parser.cpp86
-rw-r--r--Parser.h4
-rw-r--r--Scanner.cpp11
-rw-r--r--Scanner.h14
-rw-r--r--SourceReferenceFormatter.cpp41
-rw-r--r--SourceReferenceFormatter.h4
24 files changed, 441 insertions, 164 deletions
diff --git a/AST.cpp b/AST.cpp
index 4bd0b2c0..697ffe8e 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -33,6 +33,19 @@ namespace dev
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)
{
if (_visitor.visit(*this))
@@ -57,34 +70,6 @@ void StructDefinition::checkValidityOfMembers()
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)
{
if (_visitor.visit(*this))
@@ -312,6 +297,34 @@ vector<FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() co
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()
{
for (ASTPointer<VariableDeclaration> const& var: getParameters() + getReturnParameters())
diff --git a/AST.h b/AST.h
index d29e84a0..10616022 100644
--- a/AST.h
+++ b/AST.h
@@ -80,6 +80,42 @@ private:
};
/**
+ * 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).
*/
class Declaration: public ASTNode
diff --git a/ASTForward.h b/ASTForward.h
index a369c8a7..8b4bac1c 100644
--- a/ASTForward.h
+++ b/ASTForward.h
@@ -34,6 +34,8 @@ namespace solidity
{
class ASTNode;
+class SourceUnit;
+class ImportDirective;
class Declaration;
class ContractDefinition;
class StructDefinition;
diff --git a/ASTPrinter.cpp b/ASTPrinter.cpp
index 987ad11c..3d09fd9a 100644
--- a/ASTPrinter.cpp
+++ b/ASTPrinter.cpp
@@ -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)
{
writeLine("ContractDefinition \"" + _node.getName() + "\"");
@@ -270,7 +277,7 @@ bool ASTPrinter::visit(Literal& _node)
return goDeeper();
}
-void ASTPrinter::endVisit(ASTNode&)
+void ASTPrinter::endVisit(ImportDirective&)
{
m_indentation--;
}
diff --git a/ASTPrinter.h b/ASTPrinter.h
index e0757fbc..1a18fc4a 100644
--- a/ASTPrinter.h
+++ b/ASTPrinter.h
@@ -42,6 +42,7 @@ public:
/// Output the string representation of the AST to _stream.
void print(std::ostream& _stream);
+ bool visit(ImportDirective& _node) override;
bool visit(ContractDefinition& _node) override;
bool visit(StructDefinition& _node) override;
bool visit(ParameterList& _node) override;
@@ -73,7 +74,7 @@ public:
bool visit(ElementaryTypeNameExpression& _node) override;
bool visit(Literal& _node) override;
- void endVisit(ASTNode& _node) override;
+ void endVisit(ImportDirective&) override;
void endVisit(ContractDefinition&) override;
void endVisit(StructDefinition&) override;
void endVisit(ParameterList&) override;
diff --git a/ASTVisitor.h b/ASTVisitor.h
index 6e579f35..bf1ccc41 100644
--- a/ASTVisitor.h
+++ b/ASTVisitor.h
@@ -42,6 +42,8 @@ class ASTVisitor
{
public:
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(StructDefinition&) { return true; }
virtual bool visit(ParameterList&) { return true; }
@@ -74,6 +76,8 @@ public:
virtual bool visit(Literal&) { return true; }
virtual void endVisit(ASTNode&) { }
+ virtual void endVisit(SourceUnit&) { }
+ virtual void endVisit(ImportDirective&) { }
virtual void endVisit(ContractDefinition&) { }
virtual void endVisit(StructDefinition&) { }
virtual void endVisit(ParameterList&) { }
diff --git a/BaseTypes.h b/BaseTypes.h
index d1ffd7bb..a8fd77c8 100644
--- a/BaseTypes.h
+++ b/BaseTypes.h
@@ -22,6 +22,8 @@
#pragma once
+#include <memory>
+#include <string>
#include <ostream>
namespace dev
@@ -35,19 +37,19 @@ namespace solidity
*/
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) { }
- bool IsValid() const { return start >= 0 && end >= start; }
-
int start;
int end;
+ std::shared_ptr<std::string const> sourceName;
};
/// Stream output for Location (used e.g. in boost exceptions).
inline std::ostream& operator<<(std::ostream& _out, Location const& _location)
{
- return _out << "[" << _location.start << "," << _location.end << ")";
+ return _out << *_location.sourceName << "[" << _location.start << "," << _location.end << ")";
}
}
diff --git a/CompilerStack.cpp b/CompilerStack.cpp
index 01bf99d9..41ae5603 100644
--- a/CompilerStack.cpp
+++ b/CompilerStack.cpp
@@ -36,22 +36,43 @@ namespace dev
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)
{
reset();
- m_scanner = make_shared<Scanner>(CharStream(_sourceCode));
+ addSource("", _sourceCode);
}
void CompilerStack::parse()
{
- if (!m_scanner)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Source not available."));
- m_contractASTNode = Parser().parse(m_scanner);
+ for (auto& sourcePair: m_sources)
+ {
+ sourcePair.second.scanner->reset();
+ sourcePair.second.ast = Parser().parse(sourcePair.second.scanner);
+ }
+ resolveImports();
+
m_globalContext = make_shared<GlobalContext>();
- m_globalContext->setCurrentContract(*m_contractASTNode);
- NameAndTypeResolver(m_globalContext->getDeclarations()).resolveNamesAndTypes(*m_contractASTNode);
+ NameAndTypeResolver resolver(m_globalContext->getDeclarations());
+ 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;
}
@@ -61,54 +82,90 @@ void CompilerStack::parse(string const& _sourceCode)
parse();
}
-bytes const& CompilerStack::compile(bool _optimize)
+vector<string> CompilerStack::getContractNames()
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
- m_bytecode.clear();
- m_compiler = make_shared<Compiler>();
- m_compiler->compileContract(*m_contractASTNode, m_globalContext->getMagicVariables());
- return m_bytecode = m_compiler->getAssembledBytecode(_optimize);
+ vector<string> contractNames;
+ for (auto const& contract: m_contracts)
+ contractNames.push_back(contract.first);
+ 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)
{
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())
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
- m_compiler->streamAssembly(_outStream);
+ return getContract(_contractName).bytecode;
}
-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)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
- auto createDocIfNotThere = [this, _type](std::unique_ptr<string>& _doc)
- {
- if (!_doc)
- _doc = m_interfaceHandler->getDocumentation(m_contractASTNode, _type);
- };
+ Contract& contract = getContract(_contractName);
+ std::unique_ptr<string>* doc;
switch (_type)
{
case DocumentationType::NATSPEC_USER:
- createDocIfNotThere(m_userDocumentation);
- return *m_userDocumentation;
+ doc = &contract.userDocumentation;
+ break;
case DocumentationType::NATSPEC_DEV:
- createDocIfNotThere(m_devDocumentation);
- return *m_devDocumentation;
+ doc = &contract.devDocumentation;
+ break;
case DocumentationType::ABI_INTERFACE:
- createDocIfNotThere(m_interface);
- return *m_interface;
+ doc = &contract.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)
@@ -117,7 +174,70 @@ bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimiz
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>()) {}
}
}
diff --git a/CompilerStack.h b/CompilerStack.h
index 6286eb7f..6f036d3f 100644
--- a/CompilerStack.h
+++ b/CompilerStack.h
@@ -25,6 +25,7 @@
#include <ostream>
#include <string>
#include <memory>
+#include <boost/noncopyable.hpp>
#include <libdevcore/Common.h>
namespace dev {
@@ -33,6 +34,7 @@ namespace solidity {
// forward declarations
class Scanner;
class ContractDefinition;
+class SourceUnit;
class Compiler;
class GlobalContext;
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.
* before compilation to bytecode) or run the whole compilation in one call.
*/
-class CompilerStack
+class CompilerStack: boost::noncopyable
{
public:
- CompilerStack();
- void reset() { *this = CompilerStack(); }
+ CompilerStack(): m_parseSuccessful(false) {}
+
+ /// 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);
+ /// Parses all source units that were added
void parse();
+ /// Sets the given source code as the only source unit and parses it.
void parse(std::string const& _sourceCode);
- /// Compiles the contract that was previously parsed.
- bytes const& compile(bool _optimize = false);
+ /// Returns a list of the contract names in the sources.
+ 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.
+ /// @returns the compiled bytecode
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.
/// 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.
/// 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.
/// Prerequisite: Successful call to parse or compile.
/// @param type The type of the documentation to get.
- /// Can be one of 3 types defined at @c documentation_type
- std::string const& getJsonDocumentation(DocumentationType type);
+ /// Can be one of 3 types defined at @c DocumentationType
+ std::string const& getJsonDocumentation(std::string const& _contractName, DocumentationType _type);
/// Returns the previously used scanner, useful for counting lines during error reporting.
- Scanner const& getScanner() const { return *m_scanner; }
- ContractDefinition& getAST() const { return *m_contractASTNode; }
+ Scanner const& getScanner(std::string const& _sourceName = "");
+ SourceUnit& getAST(std::string const& _sourceName = "");
/// 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.
@@ -101,16 +111,41 @@ public:
}
private:
- std::shared_ptr<Scanner> m_scanner;
- std::shared_ptr<GlobalContext> m_globalContext;
- std::shared_ptr<ContractDefinition> m_contractASTNode;
+ /**
+ * Information pertaining to one source unit, filled gradually during parsing and compilation.
+ */
+ 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;
- std::unique_ptr<std::string> m_interface;
- std::unique_ptr<std::string> m_userDocumentation;
- std::unique_ptr<std::string> m_devDocumentation;
- std::shared_ptr<Compiler> m_compiler;
- std::shared_ptr<InterfaceHandler> m_interfaceHandler;
- bytes m_bytecode;
+ std::map<std::string, Source> m_sources;
+ std::shared_ptr<GlobalContext> m_globalContext;
+ std::vector<Source const*> m_sourceOrder;
+ std::map<std::string, Contract> m_contracts;
};
}
diff --git a/DeclarationContainer.cpp b/DeclarationContainer.cpp
index 6ea9c28c..c0dea757 100644
--- a/DeclarationContainer.cpp
+++ b/DeclarationContainer.cpp
@@ -28,9 +28,9 @@ namespace dev
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;
m_declarations[_declaration.getName()] = &_declaration;
return true;
diff --git a/DeclarationContainer.h b/DeclarationContainer.h
index db681289..e1b363e0 100644
--- a/DeclarationContainer.h
+++ b/DeclarationContainer.h
@@ -43,7 +43,7 @@ public:
m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {}
/// Registers the declaration in the scope unless its name is already declared. Returns true iff
/// 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* getEnclosingDeclaration() const { return m_enclosingDeclaration; }
diff --git a/Exceptions.h b/Exceptions.h
index 8298c981..14f91977 100644
--- a/Exceptions.h
+++ b/Exceptions.h
@@ -38,7 +38,6 @@ struct CompilerError: virtual Exception {};
struct InternalCompilerError: 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;
}
diff --git a/GlobalContext.cpp b/GlobalContext.cpp
index b54b93c0..2d384a15 100644
--- a/GlobalContext.cpp
+++ b/GlobalContext.cpp
@@ -74,11 +74,10 @@ vector<Declaration*> GlobalContext::getDeclarations() const
declarations.reserve(m_magicVariables.size() + 1);
for (ASTPointer<Declaration> const& variable: m_magicVariables)
declarations.push_back(variable.get());
- declarations.push_back(getCurrentThis());
return declarations;
}
-MagicVariableDeclaration*GlobalContext::getCurrentThis() const
+MagicVariableDeclaration* GlobalContext::getCurrentThis() const
{
if (!m_thisPointer[m_currentContract])
m_thisPointer[m_currentContract] = make_shared<MagicVariableDeclaration>(
diff --git a/GlobalContext.h b/GlobalContext.h
index 0166734c..ddbd049c 100644
--- a/GlobalContext.h
+++ b/GlobalContext.h
@@ -47,12 +47,14 @@ class GlobalContext: private boost::noncopyable
public:
GlobalContext();
void setCurrentContract(ContractDefinition const& _contract);
+ MagicVariableDeclaration* getCurrentThis() const;
+ /// @returns all magic variables.
std::vector<MagicVariableDeclaration const*> getMagicVariables() const;
+ /// @returns a vector of all implicit global declarations excluding "this".
std::vector<Declaration*> getDeclarations() const;
private:
- MagicVariableDeclaration* getCurrentThis() const;
std::vector<std::shared_ptr<MagicVariableDeclaration>> m_magicVariables;
ContractDefinition const* m_currentContract;
std::map<ContractDefinition const*, std::shared_ptr<MagicVariableDeclaration>> mutable m_thisPointer;
diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp
index 18c053cb..c3e62cad 100644
--- a/InterfaceHandler.cpp
+++ b/InterfaceHandler.cpp
@@ -15,7 +15,7 @@ InterfaceHandler::InterfaceHandler()
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)
{
switch(_type)
@@ -32,11 +32,11 @@ std::unique_ptr<std::string> InterfaceHandler::getDocumentation(std::shared_ptr<
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);
- for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions())
+ for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
{
Json::Value method;
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)));
}
-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 methods(Json::objectValue);
- for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions())
+ for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
{
Json::Value user;
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)));
}
-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
// should be thrown
Json::Value doc;
Json::Value methods(Json::objectValue);
- for (FunctionDefinition const* f: _contractDef->getInterfaceFunctions())
+ for (FunctionDefinition const* f: _contractDef.getInterfaceFunctions())
{
Json::Value method;
auto strPtr = f->getDocumentation();
diff --git a/InterfaceHandler.h b/InterfaceHandler.h
index a31cd5c1..4fa63fcd 100644
--- a/InterfaceHandler.h
+++ b/InterfaceHandler.h
@@ -59,23 +59,23 @@ public:
/// types provided by @c DocumentationType
/// @return A unique pointer contained string with the json
/// 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);
/// Get the ABI Interface of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// 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
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// 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
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// 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:
void resetUser();
diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp
index d473348b..3715df6a 100644
--- a/NameAndTypeResolver.cpp
+++ b/NameAndTypeResolver.cpp
@@ -38,9 +38,14 @@ NameAndTypeResolver::NameAndTypeResolver(std::vector<Declaration*> const& _globa
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)
{
- DeclarationRegistrationHelper registrar(m_scopes, _contract);
m_currentScope = &m_scopes[&_contract];
for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs())
ReferencesResolver resolver(*structDef, *this, nullptr);
@@ -65,6 +70,12 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
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
{
auto iterator = m_scopes.find(_scope);
diff --git a/NameAndTypeResolver.h b/NameAndTypeResolver.h
index 797eca60..816d8006 100644
--- a/NameAndTypeResolver.h
+++ b/NameAndTypeResolver.h
@@ -42,7 +42,13 @@ class NameAndTypeResolver: private boost::noncopyable
{
public:
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);
+ /// 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,
/// the global scope is used (i.e. the one containing only the contract).
diff --git a/Parser.cpp b/Parser.cpp
index 0506bc3e..ddab489b 100644
--- a/Parser.cpp
+++ b/Parser.cpp
@@ -20,30 +20,27 @@
* Solidity parser.
*/
+#include <vector>
#include <libdevcore/Log.h>
#include <libsolidity/BaseTypes.h>
#include <libsolidity/Parser.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Exceptions.h>
+using namespace std;
+
namespace dev
{
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
/// while it is being parsed
class Parser::ASTNodeFactory
{
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 setLocationEmpty() { m_location.end = m_location.start; }
@@ -55,7 +52,7 @@ public:
{
if (m_location.end < 0)
markEndPosition();
- return std::make_shared<NodeType>(m_location, std::forward<Args>(_args)...);
+ return make_shared<NodeType>(m_location, forward<Args>(_args)...);
}
private:
@@ -63,6 +60,33 @@ private:
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
{
return m_scanner->getCurrentLocation().start;
@@ -73,15 +97,27 @@ int Parser::getEndPosition() const
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()
{
ASTNodeFactory nodeFactory(*this);
expectToken(Token::CONTRACT);
ASTPointer<ASTString> name = expectIdentifierToken();
expectToken(Token::LBRACE);
- std::vector<ASTPointer<StructDefinition>> structs;
- std::vector<ASTPointer<VariableDeclaration>> stateVariables;
- std::vector<ASTPointer<FunctionDefinition>> functions;
+ vector<ASTPointer<StructDefinition>> structs;
+ vector<ASTPointer<VariableDeclaration>> stateVariables;
+ vector<ASTPointer<FunctionDefinition>> functions;
bool visibilityIsPublic = true;
while (true)
{
@@ -110,7 +146,6 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
}
nodeFactory.markEndPosition();
expectToken(Token::RBRACE);
- expectToken(Token::EOS);
return nodeFactory.createNode<ContractDefinition>(name, structs, stateVariables, functions);
}
@@ -119,7 +154,7 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
ASTNodeFactory nodeFactory(*this);
ASTPointer<ASTString> docstring;
if (m_scanner->getCurrentCommentLiteral() != "")
- docstring = std::make_shared<ASTString>(m_scanner->getCurrentCommentLiteral());
+ docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral());
expectToken(Token::FUNCTION);
ASTPointer<ASTString> name(expectIdentifierToken());
@@ -142,7 +177,7 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic)
// create an empty parameter list at a zero-length location
ASTNodeFactory nodeFactory(*this);
nodeFactory.setLocationEmpty();
- returnParameters = nodeFactory.createNode<ParameterList>(std::vector<ASTPointer<VariableDeclaration>>());
+ returnParameters = nodeFactory.createNode<ParameterList>(vector<ASTPointer<VariableDeclaration>>());
}
ASTPointer<Block> block = parseBlock();
nodeFactory.setEndPositionFromNode(block);
@@ -156,7 +191,7 @@ ASTPointer<StructDefinition> Parser::parseStructDefinition()
ASTNodeFactory nodeFactory(*this);
expectToken(Token::STRUCT);
ASTPointer<ASTString> name = expectIdentifierToken();
- std::vector<ASTPointer<VariableDeclaration>> members;
+ vector<ASTPointer<VariableDeclaration>> members;
expectToken(Token::LBRACE);
while (m_scanner->getCurrentToken() != Token::RBRACE)
{
@@ -228,7 +263,7 @@ ASTPointer<Mapping> Parser::parseMapping()
ASTPointer<ParameterList> Parser::parseParameterList(bool _allowEmpty)
{
ASTNodeFactory nodeFactory(*this);
- std::vector<ASTPointer<VariableDeclaration>> parameters;
+ vector<ASTPointer<VariableDeclaration>> parameters;
expectToken(Token::LPAREN);
if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN)
{
@@ -249,7 +284,7 @@ ASTPointer<Block> Parser::parseBlock()
{
ASTNodeFactory nodeFactory(*this);
expectToken(Token::LBRACE);
- std::vector<ASTPointer<Statement>> statements;
+ vector<ASTPointer<Statement>> statements;
while (m_scanner->getCurrentToken() != Token::RBRACE)
statements.push_back(parseStatement());
nodeFactory.markEndPosition();
@@ -447,7 +482,7 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression()
case Token::LPAREN:
{
m_scanner->next();
- std::vector<ASTPointer<Expression>> arguments = parseFunctionCallArguments();
+ vector<ASTPointer<Expression>> arguments = parseFunctionCallArguments();
nodeFactory.markEndPosition();
expectToken(Token::RPAREN);
expression = nodeFactory.createNode<FunctionCall>(expression, arguments);
@@ -503,9 +538,9 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
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)
{
arguments.push_back(parseExpression());
@@ -521,7 +556,7 @@ std::vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
void Parser::expectToken(Token::Value _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();
}
@@ -543,14 +578,15 @@ ASTPointer<ASTString> Parser::expectIdentifierToken()
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();
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);
}
diff --git a/Parser.h b/Parser.h
index 307a0d6a..52a374e0 100644
--- a/Parser.h
+++ b/Parser.h
@@ -34,7 +34,8 @@ class Scanner;
class Parser
{
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:
class ASTNodeFactory;
@@ -46,6 +47,7 @@ private:
///@{
///@name Parsing functions for the AST nodes
+ ASTPointer<ImportDirective> parseImportDirective();
ASTPointer<ContractDefinition> parseContractDefinition();
ASTPointer<FunctionDefinition> parseFunctionDefinition(bool _isPublic);
ASTPointer<StructDefinition> parseStructDefinition();
diff --git a/Scanner.cpp b/Scanner.cpp
index 2f5f8d37..08bf744d 100644
--- a/Scanner.cpp
+++ b/Scanner.cpp
@@ -143,17 +143,22 @@ private:
}; // end of LiteralScope class
-void Scanner::reset(CharStream const& _source)
+void Scanner::reset(CharStream const& _source, string const& _sourceName)
{
m_source = _source;
+ m_sourceName = make_shared<string const>(_sourceName);
+ reset();
+}
+
+void Scanner::reset()
+{
+ m_source.reset();
m_char = m_source.get();
skipWhitespace();
scanToken();
-
next();
}
-
bool Scanner::scanHexByte(char& o_scannedByte)
{
char x = 0;
diff --git a/Scanner.h b/Scanner.h
index 49ac3651..18b1f5d3 100644
--- a/Scanner.h
+++ b/Scanner.h
@@ -79,6 +79,8 @@ public:
char advanceAndGet(size_t _chars=1);
char rollback(size_t _amount);
+ void reset() { m_pos = 0; }
+
///@{
///@name Error printing helper functions
/// Functions that help pretty-printing parse errors
@@ -99,11 +101,12 @@ class Scanner
friend class LiteralScope;
public:
- Scanner() { reset(CharStream()); }
- explicit Scanner(CharStream const& _source) { reset(_source); }
+ explicit Scanner(CharStream const& _source = CharStream(), std::string const& _sourceName = "") { reset(_source, _sourceName); }
- /// Resets the scanner as if newly constructed with _input as input.
- void reset(CharStream const& _source);
+ /// Resets the scanner as if newly constructed with _source and _sourceName as input.
+ 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
Token::Value next();
@@ -139,6 +142,8 @@ public:
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
/// Functions that help pretty-printing parse errors
@@ -203,6 +208,7 @@ private:
TokenDesc m_nextToken; // desc for next token (one token look-ahead)
CharStream m_source;
+ std::shared_ptr<std::string const> m_sourceName;
/// one character look-ahead, equals 0 at end of input
char m_char;
diff --git a/SourceReferenceFormatter.cpp b/SourceReferenceFormatter.cpp
index d3f2152a..1a7d12a9 100644
--- a/SourceReferenceFormatter.cpp
+++ b/SourceReferenceFormatter.cpp
@@ -21,6 +21,7 @@
*/
#include <libsolidity/SourceReferenceFormatter.h>
+#include <libsolidity/CompilerStack.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Exceptions.h>
@@ -38,7 +39,6 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
int startLine;
int startColumn;
tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start);
- _stream << "starting at line " << (startLine + 1) << ", column " << (startColumn + 1) << "\n";
int endLine;
int endColumn;
tie(endLine, endColumn) = _scanner.translatePositionToLineColumn(_location.end);
@@ -58,37 +58,28 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
<< "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,
Exception const& _exception,
string const& _name,
- Scanner const& _scanner)
+ CompilerStack& _compiler)
{
- _stream << _name;
- if (string const* description = boost::get_error_info<errinfo_comment>(_exception))
- _stream << ": " << *description;
+ Location const* location = boost::get_error_info<errinfo_sourceLocation>(_exception);
+ Scanner const* scanner;
- if (int const* position = boost::get_error_info<errinfo_sourcePosition>(_exception))
+ if (location)
{
- _stream << " ";
- printSourcePosition(_stream, *position, _scanner);
- }
- if (Location const* location = boost::get_error_info<errinfo_sourceLocation>(_exception))
- {
- _stream << " ";
- printSourceLocation(_stream, *location, _scanner);
+ 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;
+ if (string const* description = boost::get_error_info<errinfo_comment>(_exception))
+ _stream << ": " << *description << endl;
+
+ if (location)
+ printSourceLocation(_stream, *location, *scanner);
}
}
diff --git a/SourceReferenceFormatter.h b/SourceReferenceFormatter.h
index 4736066f..9b556704 100644
--- a/SourceReferenceFormatter.h
+++ b/SourceReferenceFormatter.h
@@ -34,14 +34,14 @@ namespace solidity
{
class Scanner; // forward
+class CompilerStack; // forward
struct SourceReferenceFormatter
{
public:
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,
- std::string const& _name, Scanner const& _scanner);
+ std::string const& _name, CompilerStack& _compiler);
};
}