mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			157 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| 	This file is part of solidity.
 | |
| 
 | |
| 	solidity is free software: you can redistribute it and/or modify
 | |
| 	it under the terms of the GNU General Public License as published by
 | |
| 	the Free Software Foundation, either version 3 of the License, or
 | |
| 	(at your option) any later version.
 | |
| 
 | |
| 	solidity is distributed in the hope that it will be useful,
 | |
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| 	GNU General Public License for more details.
 | |
| 
 | |
| 	You should have received a copy of the GNU General Public License
 | |
| 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | |
| */
 | |
| // SPDX-License-Identifier: GPL-3.0
 | |
| /**
 | |
|  * Yul interpreter.
 | |
|  */
 | |
| 
 | |
| #include <test/tools/yulInterpreter/Inspector.h>
 | |
| 
 | |
| #include <boost/algorithm/string/predicate.hpp>
 | |
| #include <boost/algorithm/string.hpp>
 | |
| 
 | |
| using namespace solidity;
 | |
| using namespace solidity::yul;
 | |
| using namespace solidity::yul::test;
 | |
| 
 | |
| using namespace std;
 | |
| 
 | |
| namespace
 | |
| {
 | |
| 
 | |
| void printVariable(YulString const& _name, u256 const& _value)
 | |
| {
 | |
| 	cout << "\t" << _name.str() << " = " << _value.str();
 | |
| 
 | |
| 	if (_value != 0)
 | |
| 		cout << " (" << toCompactHexWithPrefix(_value) << ")";
 | |
| 
 | |
| 	cout << endl;
 | |
| }
 | |
| 
 | |
| }
 | |
| 
 | |
| void InspectedInterpreter::run(
 | |
| 	std::shared_ptr<Inspector> _inspector,
 | |
| 	InterpreterState& _state,
 | |
| 	Dialect const& _dialect,
 | |
| 	Block const& _ast,
 | |
| 	bool _disableExternalCalls,
 | |
| 	bool _disableMemoryTrace
 | |
| )
 | |
| {
 | |
| 	Scope scope;
 | |
| 	InspectedInterpreter{_inspector, _state, _dialect, scope, _disableExternalCalls, _disableMemoryTrace}(_ast);
 | |
| }
 | |
| 
 | |
| Inspector::NodeAction Inspector::queryUser(DebugData const& _data, map<YulString, u256> const& _variables)
 | |
| {
 | |
| 	if (m_stepMode == NodeAction::RunNode)
 | |
| 	{
 | |
| 		// Output instructions that are being skipped/run
 | |
| 		cout << "Running " << currentSource(_data) << endl;
 | |
| 
 | |
| 		return NodeAction::StepThroughNode;
 | |
| 	}
 | |
| 
 | |
| 	string input;
 | |
| 
 | |
| 	while (true)
 | |
| 	{
 | |
| 		// Output sourcecode about to run.
 | |
| 		cout << "> " << currentSource(_data) << endl;
 | |
| 
 | |
| 		// Ask user for action
 | |
| 		cout << endl
 | |
| 			<< "(s)tep/(n)ext/(i)nspect/(p)rint/all (v)ariables?"
 | |
| 			<< endl
 | |
| 			<< "# ";
 | |
| 
 | |
| 		cout.flush();
 | |
| 
 | |
| 		getline(cin, input);
 | |
| 		boost::algorithm::trim(input);
 | |
| 
 | |
| 		// Imitate GDB and repeat last cmd for empty string input.
 | |
| 		if (input == "")
 | |
| 			input = m_lastInput;
 | |
| 		else
 | |
| 			m_lastInput = input;
 | |
| 
 | |
| 		if (input == "next" || input == "n")
 | |
| 			return NodeAction::RunNode;
 | |
| 		else if (input == "step" || input == "s")
 | |
| 			return NodeAction::StepThroughNode;
 | |
| 		else if (input == "inspect" || input == "i")
 | |
| 			m_state.dumpTraceAndState(cout, false);
 | |
| 		else if (input == "variables" || input == "v")
 | |
| 		{
 | |
| 			for (auto &&[yulStr, val]: _variables)
 | |
| 				printVariable(yulStr, val);
 | |
| 			cout << endl;
 | |
| 		}
 | |
| 		else if (
 | |
| 			boost::starts_with(input, "print") ||
 | |
| 			boost::starts_with(input, "p")
 | |
| 		)
 | |
| 		{
 | |
| 			size_t whitespacePos = input.find(' ');
 | |
| 
 | |
| 			if (whitespacePos == string::npos)
 | |
| 				cout << "Error parsing command! Expected variable name." << endl;
 | |
| 
 | |
| 			string const varname = input.substr(whitespacePos + 1);
 | |
| 
 | |
| 			vector<string> candidates;
 | |
| 
 | |
| 			bool found = false;
 | |
| 			for (auto &&[yulStr, val]: _variables)
 | |
| 				if (yulStr.str() == varname)
 | |
| 				{
 | |
| 					printVariable(yulStr, val);
 | |
| 					found = true;
 | |
| 					break;
 | |
| 				}
 | |
| 
 | |
| 			if (!found)
 | |
| 				cout << varname << " not found." << endl;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| std::string Inspector::currentSource(DebugData const& _data) const
 | |
| {
 | |
| 	return m_source.substr(
 | |
| 		static_cast<size_t>(_data.nativeLocation.start),
 | |
| 		static_cast<size_t>(_data.nativeLocation.end - _data.nativeLocation.start)
 | |
| 	);
 | |
| }
 | |
| 
 | |
| u256 InspectedInterpreter::evaluate(Expression const& _expression)
 | |
| {
 | |
| 	InspectedExpressionEvaluator ev(m_inspector, m_state, m_dialect, *m_scope, m_variables, m_disableExternalCalls, m_disableMemoryTrace);
 | |
| 	ev.visit(_expression);
 | |
| 	return ev.value();
 | |
| }
 | |
| 
 | |
| std::vector<u256> InspectedInterpreter::evaluateMulti(Expression const& _expression)
 | |
| {
 | |
| 	InspectedExpressionEvaluator ev(m_inspector, m_state, m_dialect, *m_scope, m_variables, m_disableExternalCalls, m_disableMemoryTrace);
 | |
| 	ev.visit(_expression);
 | |
| 	return ev.values();
 | |
| }
 |