Merge pull request #509 from chriseth/sol_jsonInterface

Provide interface for calls in JSON and some other formatting changes.
This commit is contained in:
Gav Wood 2014-11-14 12:07:33 +01:00
commit c4a65cf688
6 changed files with 156 additions and 16 deletions

15
AST.cpp
View File

@ -263,6 +263,21 @@ TypeError ASTNode::createTypeError(string const& _description)
return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description);
}
vector<FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() const
{
vector<FunctionDefinition const*> exportedFunctions;
for (ASTPointer<FunctionDefinition> const& f: m_definedFunctions)
if (f->isPublic() && f->getName() != getName())
exportedFunctions.push_back(f.get());
auto compareNames = [](FunctionDefinition const* _a, FunctionDefinition const* _b)
{
return _a->getName().compare(_b->getName()) < 0;
};
sort(exportedFunctions.begin(), exportedFunctions.end(), compareNames);
return exportedFunctions;
}
void Block::checkTypeRequirements()
{
for (shared_ptr<Statement> const& statement: m_statements)

2
AST.h
View File

@ -120,6 +120,8 @@ public:
std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; }
std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; }
/// Returns the functions that make up the calling interface in the intended order.
std::vector<FunctionDefinition const*> getInterfaceFunctions() const;
private:
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;

View File

@ -30,8 +30,8 @@ namespace dev
namespace solidity
{
ASTPrinter::ASTPrinter(ASTPointer<ASTNode> const& _ast, string const& _source):
m_indentation(0), m_source(_source), m_ast(_ast)
ASTPrinter::ASTPrinter(ASTNode& _ast, string const& _source):
m_indentation(0), m_source(_source), m_ast(&_ast)
{
}
@ -430,8 +430,8 @@ void ASTPrinter::printSourcePart(ASTNode const& _node)
if (!m_source.empty())
{
Location const& location(_node.getLocation());
*m_ostream << getIndentation() << " Source: |"
<< m_source.substr(location.start, location.end - location.start) << "|" << endl;
*m_ostream << getIndentation() << " Source: "
<< escaped(m_source.substr(location.start, location.end - location.start), false) << endl;
}
}

View File

@ -38,7 +38,7 @@ class ASTPrinter: public ASTVisitor
public:
/// Create a printer for the given abstract syntax tree. If the source is specified,
/// the corresponding parts of the source are printed with each node.
ASTPrinter(ASTPointer<ASTNode> const& _ast, std::string const& _source = std::string());
ASTPrinter(ASTNode& _ast, std::string const& _source = std::string());
/// Output the string representation of the AST to _stream.
void print(std::ostream& _stream);
@ -114,7 +114,7 @@ private:
int m_indentation;
std::string m_source;
ASTPointer<ASTNode> m_ast;
ASTNode* m_ast;
std::ostream* m_ostream;
};

View File

@ -34,17 +34,101 @@ namespace dev
namespace solidity
{
bytes CompilerStack::compile(std::string const& _sourceCode, shared_ptr<Scanner> _scanner,
bool _optimize)
void CompilerStack::setSource(string const& _sourceCode)
{
if (!_scanner)
_scanner = make_shared<Scanner>();
_scanner->reset(CharStream(_sourceCode));
ASTPointer<ContractDefinition> contract = Parser().parse(_scanner);
NameAndTypeResolver().resolveNamesAndTypes(*contract);
return Compiler::compile(*contract, _optimize);
reset();
m_scanner = make_shared<Scanner>(CharStream(_sourceCode));
}
void CompilerStack::parse()
{
if (!m_scanner)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Source not available."));
m_contractASTNode = Parser().parse(m_scanner);
NameAndTypeResolver().resolveNamesAndTypes(*m_contractASTNode);
m_parseSuccessful = true;
}
void CompilerStack::parse(string const& _sourceCode)
{
setSource(_sourceCode);
parse();
}
bytes const& CompilerStack::compile(bool _optimize)
{
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);
return m_bytecode = m_compiler->getAssembledBytecode(_optimize);
}
bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize)
{
parse(_sourceCode);
return compile(_optimize);
}
void CompilerStack::streamAssembly(ostream& _outStream)
{
if (!m_compiler || m_bytecode.empty())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
m_compiler->streamAssembly(_outStream);
}
string const& CompilerStack::getInterface()
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
if (m_interface.empty())
{
stringstream interface;
interface << '[';
vector<FunctionDefinition const*> exportedFunctions = m_contractASTNode->getInterfaceFunctions();
unsigned functionsCount = exportedFunctions.size();
for (FunctionDefinition const* f: exportedFunctions)
{
auto streamVariables = [&](vector<ASTPointer<VariableDeclaration>> const& _vars)
{
unsigned varCount = _vars.size();
for (ASTPointer<VariableDeclaration> const& var: _vars)
{
interface << "{"
<< "\"name\":" << escaped(var->getName(), false) << ","
<< "\"type\":" << escaped(var->getType()->toString(), false)
<< "}";
if (--varCount > 0)
interface << ",";
}
};
interface << '{'
<< "\"name\":" << escaped(f->getName(), false) << ","
<< "\"inputs\":[";
streamVariables(f->getParameters());
interface << "],"
<< "\"outputs\":[";
streamVariables(f->getReturnParameters());
interface << "]"
<< "}";
if (--functionsCount > 0)
interface << ",";
}
interface << ']';
m_interface = interface.str();
}
return m_interface;
}
bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize)
{
CompilerStack stack;
return stack.compile(_sourceCode, _optimize);
}
}
}

View File

@ -22,6 +22,7 @@
#pragma once
#include <ostream>
#include <string>
#include <memory>
#include <libdevcore/Common.h>
@ -30,13 +31,51 @@ namespace dev {
namespace solidity {
class Scanner; // forward
class ContractDefinition; // forward
class Compiler; // forward
/**
* Easy to use and self-contained Solidity compiler with as few header dependencies as possible.
* 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
{
public:
CompilerStack() {}
void reset() { *this = CompilerStack(); }
void setSource(std::string const& _sourceCode);
void parse();
void parse(std::string const& _sourceCode);
/// Compiles the contract that was previously parsed.
bytes const& compile(bool _optimize = false);
/// Parses and compiles the given source code.
bytes const& compile(std::string const& _sourceCode, bool _optimize = false);
bytes const& getBytecode() const { return m_bytecode; }
/// Streams a verbose version of the assembly to @a _outStream.
/// Prerequisite: Successful compilation.
void streamAssembly(std::ostream& _outStream);
/// Returns a string representing the contract interface in JSON.
/// Prerequisite: Successful call to parse or compile.
std::string const& getInterface();
/// 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; }
/// 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.
static bytes compile(std::string const& _sourceCode, std::shared_ptr<Scanner> _scanner = std::shared_ptr<Scanner>(), bool _optimize = false);
static bytes staticCompile(std::string const& _sourceCode, bool _optimize = false);
private:
std::shared_ptr<Scanner> m_scanner;
std::shared_ptr<ContractDefinition> m_contractASTNode;
bool m_parseSuccessful;
std::string m_interface;
std::shared_ptr<Compiler> m_compiler;
bytes m_bytecode;
};
}