mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge pull request #12221 from ethereum/yulOptiNonInteractive
Non-interactive mode for yulopti.
This commit is contained in:
		
						commit
						4a49e6e48f
					
				| @ -111,7 +111,10 @@ void OptimiserSuite::run( | |||||||
| 	)(*_object.code)); | 	)(*_object.code)); | ||||||
| 	Block& ast = *_object.code; | 	Block& ast = *_object.code; | ||||||
| 
 | 
 | ||||||
| 	OptimiserSuite suite(_dialect, reservedIdentifiers, Debug::None, ast, _expectedExecutionsPerDeployment); | 	NameDispenser dispenser{_dialect, ast, reservedIdentifiers}; | ||||||
|  | 	OptimiserStepContext context{_dialect, dispenser, reservedIdentifiers, _expectedExecutionsPerDeployment}; | ||||||
|  | 
 | ||||||
|  | 	OptimiserSuite suite(context, Debug::None); | ||||||
| 
 | 
 | ||||||
| 	// Some steps depend on properties ensured by FunctionHoister, BlockFlattener, FunctionGrouper and
 | 	// Some steps depend on properties ensured by FunctionHoister, BlockFlattener, FunctionGrouper and
 | ||||||
| 	// ForLoopInitRewriter. Run them first to be able to run arbitrary sequences safely.
 | 	// ForLoopInitRewriter. Run them first to be able to run arbitrary sequences safely.
 | ||||||
| @ -162,7 +165,7 @@ void OptimiserSuite::run( | |||||||
| 			ast.statements.erase(ast.statements.begin()); | 			ast.statements.erase(ast.statements.begin()); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	suite.m_dispenser.reset(ast); | 	dispenser.reset(ast); | ||||||
| 	NameSimplifier::run(suite.m_context, ast); | 	NameSimplifier::run(suite.m_context, ast); | ||||||
| 	VarNameCleaner::run(suite.m_context, ast); | 	VarNameCleaner::run(suite.m_context, ast); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -59,6 +59,8 @@ public: | |||||||
| 		PrintStep, | 		PrintStep, | ||||||
| 		PrintChanges | 		PrintChanges | ||||||
| 	}; | 	}; | ||||||
|  | 	OptimiserSuite(OptimiserStepContext& _context, Debug _debug = Debug::None): m_context(_context), m_debug(_debug) {} | ||||||
|  | 
 | ||||||
| 	/// The value nullopt for `_expectedExecutionsPerDeployment` represents creation code.
 | 	/// The value nullopt for `_expectedExecutionsPerDeployment` represents creation code.
 | ||||||
| 	static void run( | 	static void run( | ||||||
| 		Dialect const& _dialect, | 		Dialect const& _dialect, | ||||||
| @ -82,20 +84,7 @@ public: | |||||||
| 	static std::map<char, std::string> const& stepAbbreviationToNameMap(); | 	static std::map<char, std::string> const& stepAbbreviationToNameMap(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	OptimiserSuite( | 	OptimiserStepContext& m_context; | ||||||
| 		Dialect const& _dialect, |  | ||||||
| 		std::set<YulString> const& _externallyUsedIdentifiers, |  | ||||||
| 		Debug _debug, |  | ||||||
| 		Block& _ast, |  | ||||||
| 		std::optional<size_t> expectedExecutionsPerDeployment |  | ||||||
| 	): |  | ||||||
| 		m_dispenser{_dialect, _ast, _externallyUsedIdentifiers}, |  | ||||||
| 		m_context{_dialect, m_dispenser, _externallyUsedIdentifiers, expectedExecutionsPerDeployment}, |  | ||||||
| 		m_debug(_debug) |  | ||||||
| 	{} |  | ||||||
| 
 |  | ||||||
| 	NameDispenser m_dispenser; |  | ||||||
| 	OptimiserStepContext m_context; |  | ||||||
| 	Debug m_debug; | 	Debug m_debug; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -76,58 +76,66 @@ namespace po = boost::program_options; | |||||||
| class YulOpti | class YulOpti | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	void printErrors() | 	static void printErrors(CharStream const& _charStream, ErrorList const& _errors) | ||||||
| 	{ | 	{ | ||||||
| 		SourceReferenceFormatter{ | 		SourceReferenceFormatter{ | ||||||
| 			cerr, | 			cerr, | ||||||
| 			SingletonCharStreamProvider(*m_charStream), | 			SingletonCharStreamProvider(_charStream), | ||||||
| 			true, | 			true, | ||||||
| 			false | 			false | ||||||
| 		}.printErrorInformation(m_errors); | 		}.printErrorInformation(_errors); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool parse(string const& _input) | 	void parse(string const& _input) | ||||||
| 	{ | 	{ | ||||||
| 		ErrorReporter errorReporter(m_errors); | 		ErrorList errors; | ||||||
| 		m_charStream = make_shared<CharStream>(_input, ""); | 		ErrorReporter errorReporter(errors); | ||||||
| 		m_ast = yul::Parser(errorReporter, m_dialect).parse(*m_charStream); | 		CharStream _charStream(_input, ""); | ||||||
| 		if (!m_ast || !errorReporter.errors().empty()) | 		try | ||||||
| 		{ | 		{ | ||||||
| 			cerr << "Error parsing source." << endl; | 			m_ast = yul::Parser(errorReporter, m_dialect).parse(_charStream); | ||||||
| 			printErrors(); | 			if (!m_ast || !errorReporter.errors().empty()) | ||||||
| 			return false; | 			{ | ||||||
|  | 				cerr << "Error parsing source." << endl; | ||||||
|  | 				printErrors(_charStream, errors); | ||||||
|  | 				throw std::runtime_error("Could not parse source."); | ||||||
|  | 			} | ||||||
|  | 			m_analysisInfo = make_unique<yul::AsmAnalysisInfo>(); | ||||||
|  | 			AsmAnalyzer analyzer( | ||||||
|  | 				*m_analysisInfo, | ||||||
|  | 				errorReporter, | ||||||
|  | 				m_dialect | ||||||
|  | 			); | ||||||
|  | 			if (!analyzer.analyze(*m_ast) || !errorReporter.errors().empty()) | ||||||
|  | 			{ | ||||||
|  | 				cerr << "Error analyzing source." << endl; | ||||||
|  | 				printErrors(_charStream, errors); | ||||||
|  | 				throw std::runtime_error("Could not analyze source."); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 		m_analysisInfo = make_shared<yul::AsmAnalysisInfo>(); | 		catch(...) | ||||||
| 		AsmAnalyzer analyzer( |  | ||||||
| 			*m_analysisInfo, |  | ||||||
| 			errorReporter, |  | ||||||
| 			m_dialect |  | ||||||
| 		); |  | ||||||
| 		if (!analyzer.analyze(*m_ast) || !errorReporter.errors().empty()) |  | ||||||
| 		{ | 		{ | ||||||
| 			cerr << "Error analyzing source." << endl; | 			cerr << "Fatal error during parsing: " << endl; | ||||||
| 			printErrors(); | 			printErrors(_charStream, errors); | ||||||
| 			return false; | 			throw; | ||||||
| 		} | 		} | ||||||
| 		return true; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void printUsageBanner( | 	void printUsageBanner( | ||||||
| 		map<char, string> const& _optimizationSteps, |  | ||||||
| 		map<char, string> const& _extraOptions, | 		map<char, string> const& _extraOptions, | ||||||
| 		size_t _columns | 		size_t _columns | ||||||
| 	) | 	) | ||||||
| 	{ | 	{ | ||||||
| 		yulAssert(_columns > 0); | 		yulAssert(_columns > 0); | ||||||
| 
 | 		auto const& optimiserSteps = OptimiserSuite::stepAbbreviationToNameMap(); | ||||||
| 		auto hasShorterString = [](auto const& a, auto const& b) { return a.second.size() < b.second.size(); }; | 		auto hasShorterString = [](auto const& a, auto const& b) { return a.second.size() < b.second.size(); }; | ||||||
| 		size_t longestDescriptionLength = std::max( | 		size_t longestDescriptionLength = std::max( | ||||||
| 			max_element(_optimizationSteps.begin(), _optimizationSteps.end(), hasShorterString)->second.size(), | 			max_element(optimiserSteps.begin(), optimiserSteps.end(), hasShorterString)->second.size(), | ||||||
| 			max_element(_extraOptions.begin(), _extraOptions.end(), hasShorterString)->second.size() | 			max_element(_extraOptions.begin(), _extraOptions.end(), hasShorterString)->second.size() | ||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		vector<string> overlappingAbbreviations = | 		vector<string> overlappingAbbreviations = | ||||||
| 			ranges::views::set_intersection(_extraOptions | ranges::views::keys, _optimizationSteps | ranges::views::keys) | | 			ranges::views::set_intersection(_extraOptions | ranges::views::keys, optimiserSteps | ranges::views::keys) | | ||||||
| 			ranges::views::transform([](char _abbreviation){ return string(1, _abbreviation); }) | | 			ranges::views::transform([](char _abbreviation){ return string(1, _abbreviation); }) | | ||||||
| 			ranges::to<vector>(); | 			ranges::to<vector>(); | ||||||
| 
 | 
 | ||||||
| @ -141,7 +149,7 @@ public: | |||||||
| 		); | 		); | ||||||
| 
 | 
 | ||||||
| 		vector<tuple<char, string>> sortedOptions = | 		vector<tuple<char, string>> sortedOptions = | ||||||
| 			ranges::views::concat(_optimizationSteps, _extraOptions) | | 			ranges::views::concat(optimiserSteps, _extraOptions) | | ||||||
| 			ranges::to<vector<tuple<char, string>>>() | | 			ranges::to<vector<tuple<char, string>>>() | | ||||||
| 			ranges::actions::sort([](tuple<char, string> const& _a, tuple<char, string> const& _b) { | 			ranges::actions::sort([](tuple<char, string> const& _a, tuple<char, string> const& _b) { | ||||||
| 				return ( | 				return ( | ||||||
| @ -162,24 +170,28 @@ public: | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void runInteractive(string source) | 	void disambiguate() | ||||||
| 	{ | 	{ | ||||||
| 		bool disambiguated = false; | 		*m_ast = std::get<yul::Block>(Disambiguator(m_dialect, *m_analysisInfo)(*m_ast)); | ||||||
|  | 		m_analysisInfo.reset(); | ||||||
|  | 		m_nameDispenser.reset(*m_ast); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void runSteps(string _source, string _steps) | ||||||
|  | 	{ | ||||||
|  | 		parse(_source); | ||||||
|  | 		disambiguate(); | ||||||
|  | 		OptimiserSuite{m_context}.runSequence(_steps, *m_ast); | ||||||
|  | 		cout << AsmPrinter{m_dialect}(*m_ast) << endl; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void runInteractive(string _source, bool _disambiguated = false) | ||||||
|  | 	{ | ||||||
|  | 		bool disambiguated = _disambiguated; | ||||||
| 		while (true) | 		while (true) | ||||||
| 		{ | 		{ | ||||||
| 			cout << "----------------------" << endl; | 			parse(_source); | ||||||
| 			cout << source << endl; | 			disambiguated = disambiguated || (disambiguate(), true); | ||||||
| 			if (!parse(source)) |  | ||||||
| 				return; |  | ||||||
| 			set<YulString> reservedIdentifiers; |  | ||||||
| 			if (!disambiguated) |  | ||||||
| 			{ |  | ||||||
| 				*m_ast = std::get<yul::Block>(Disambiguator(m_dialect, *m_analysisInfo)(*m_ast)); |  | ||||||
| 				m_analysisInfo.reset(); |  | ||||||
| 				m_nameDispenser = make_shared<NameDispenser>(m_dialect, *m_ast, reservedIdentifiers); |  | ||||||
| 				disambiguated = true; |  | ||||||
| 			} |  | ||||||
| 			map<char, string> const& abbreviationMap = OptimiserSuite::stepAbbreviationToNameMap(); |  | ||||||
| 			map<char, string> const& extraOptions = { | 			map<char, string> const& extraOptions = { | ||||||
| 				// QUIT starts with a non-letter character on purpose to get it to show up on top of the list
 | 				// QUIT starts with a non-letter character on purpose to get it to show up on top of the list
 | ||||||
| 				{'#', ">>> QUIT <<<"}, | 				{'#', ">>> QUIT <<<"}, | ||||||
| @ -187,99 +199,159 @@ public: | |||||||
| 				{';', "StackCompressor"} | 				{';', "StackCompressor"} | ||||||
| 			}; | 			}; | ||||||
| 
 | 
 | ||||||
| 			printUsageBanner(abbreviationMap, extraOptions, 4); | 			printUsageBanner(extraOptions, 4); | ||||||
| 			cout << "? "; | 			cout << "? "; | ||||||
| 			cout.flush(); | 			cout.flush(); | ||||||
| 			// TODO: handle EOF properly.
 |  | ||||||
| 			char option = static_cast<char>(readStandardInputChar()); | 			char option = static_cast<char>(readStandardInputChar()); | ||||||
| 			cout << ' ' << option << endl; | 			cout << ' ' << option << endl; | ||||||
| 
 | 
 | ||||||
| 			OptimiserStepContext context{ | 			try | ||||||
| 				m_dialect, |  | ||||||
| 				*m_nameDispenser, |  | ||||||
| 				reservedIdentifiers, |  | ||||||
| 				solidity::frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment |  | ||||||
| 			}; |  | ||||||
| 
 |  | ||||||
| 			auto abbreviationAndName = abbreviationMap.find(option); |  | ||||||
| 			if (abbreviationAndName != abbreviationMap.end()) |  | ||||||
| 			{ | 			{ | ||||||
| 				OptimiserStep const& step = *OptimiserSuite::allSteps().at(abbreviationAndName->second); | 				switch (option) | ||||||
| 				step.run(context, *m_ast); | 				{ | ||||||
|  | 					case 4: | ||||||
|  | 					case '#': | ||||||
|  | 						return; | ||||||
|  | 					case ',': | ||||||
|  | 						VarNameCleaner::run(m_context, *m_ast); | ||||||
|  | 						// VarNameCleaner destroys the unique names guarantee of the disambiguator.
 | ||||||
|  | 						disambiguated = false; | ||||||
|  | 						break; | ||||||
|  | 					case ';': | ||||||
|  | 					{ | ||||||
|  | 						Object obj; | ||||||
|  | 						obj.code = m_ast; | ||||||
|  | 						StackCompressor::run(m_dialect, obj, true, 16); | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 					default: | ||||||
|  | 						OptimiserSuite{m_context}.runSequence( | ||||||
|  | 							std::string_view(&option, 1), | ||||||
|  | 							*m_ast | ||||||
|  | 						); | ||||||
|  | 				} | ||||||
|  | 				_source = AsmPrinter{m_dialect}(*m_ast); | ||||||
| 			} | 			} | ||||||
| 			else switch (option) | 			catch (...) | ||||||
| 			{ | 			{ | ||||||
| 			case '#': | 				cerr << endl << "Exception during optimiser step:" << endl; | ||||||
| 				return; | 				cerr << boost::current_exception_diagnostic_information() << endl; | ||||||
| 			case ',': |  | ||||||
| 				VarNameCleaner::run(context, *m_ast); |  | ||||||
| 				// VarNameCleaner destroys the unique names guarantee of the disambiguator.
 |  | ||||||
| 				disambiguated = false; |  | ||||||
| 				break; |  | ||||||
| 			case ';': |  | ||||||
| 			{ |  | ||||||
| 				Object obj; |  | ||||||
| 				obj.code = m_ast; |  | ||||||
| 				StackCompressor::run(m_dialect, obj, true, 16); |  | ||||||
| 				break; |  | ||||||
| 			} | 			} | ||||||
| 			default: | 			cout << "----------------------" << endl; | ||||||
| 				cerr << "Unknown option." << endl; | 			cout << _source << endl; | ||||||
| 			} |  | ||||||
| 			source = AsmPrinter{m_dialect}(*m_ast); |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	ErrorList m_errors; |  | ||||||
| 	shared_ptr<CharStream> m_charStream; |  | ||||||
| 	shared_ptr<yul::Block> m_ast; | 	shared_ptr<yul::Block> m_ast; | ||||||
| 	Dialect const& m_dialect{EVMDialect::strictAssemblyForEVMObjects(EVMVersion{})}; | 	Dialect const& m_dialect{EVMDialect::strictAssemblyForEVMObjects(EVMVersion{})}; | ||||||
| 	shared_ptr<AsmAnalysisInfo> m_analysisInfo; | 	unique_ptr<AsmAnalysisInfo> m_analysisInfo; | ||||||
| 	shared_ptr<NameDispenser> m_nameDispenser; | 	set<YulString> const m_reservedIdentifiers = {}; | ||||||
|  | 	NameDispenser m_nameDispenser{m_dialect, m_reservedIdentifiers}; | ||||||
|  | 	OptimiserStepContext m_context{ | ||||||
|  | 		m_dialect, | ||||||
|  | 		m_nameDispenser, | ||||||
|  | 		m_reservedIdentifiers, | ||||||
|  | 		solidity::frontend::OptimiserSettings::standard().expectedExecutionsPerDeployment | ||||||
|  | 	}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int main(int argc, char** argv) | int main(int argc, char** argv) | ||||||
| { | { | ||||||
| 	po::options_description options( |  | ||||||
| 		R"(yulopti, yul optimizer exploration tool. |  | ||||||
| Usage: yulopti [Options] <file> |  | ||||||
| Reads <file> as yul code and applies optimizer steps to it, |  | ||||||
| interactively read from stdin. |  | ||||||
| 
 |  | ||||||
| Allowed options)", |  | ||||||
| 		po::options_description::m_default_line_length, |  | ||||||
| 		po::options_description::m_default_line_length - 23); |  | ||||||
| 	options.add_options() |  | ||||||
| 		( |  | ||||||
| 			"input-file", |  | ||||||
| 			po::value<string>(), |  | ||||||
| 			"input file" |  | ||||||
| 		) |  | ||||||
| 		("help", "Show this help screen."); |  | ||||||
| 
 |  | ||||||
| 	// All positional options should be interpreted as input files
 |  | ||||||
| 	po::positional_options_description filesPositions; |  | ||||||
| 	filesPositions.add("input-file", 1); |  | ||||||
| 
 |  | ||||||
| 	po::variables_map arguments; |  | ||||||
| 	try | 	try | ||||||
| 	{ | 	{ | ||||||
|  | 		bool nonInteractive = false; | ||||||
|  | 		po::options_description options( | ||||||
|  | 			R"(yulopti, yul optimizer exploration tool. | ||||||
|  | 	Usage: yulopti [Options] <file> | ||||||
|  | 	Reads <file> as yul code and applies optimizer steps to it, | ||||||
|  | 	interactively read from stdin. | ||||||
|  | 	In non-interactive mode a list of steps has to be provided. | ||||||
|  | 	If <file> is -, yul code is read from stdin and run non-interactively. | ||||||
|  | 
 | ||||||
|  | 	Allowed options)", | ||||||
|  | 			po::options_description::m_default_line_length, | ||||||
|  | 			po::options_description::m_default_line_length - 23); | ||||||
|  | 		options.add_options() | ||||||
|  | 			( | ||||||
|  | 				"input-file", | ||||||
|  | 				po::value<string>(), | ||||||
|  | 				"input file" | ||||||
|  | 			) | ||||||
|  | 			( | ||||||
|  | 				"steps", | ||||||
|  | 				po::value<string>(), | ||||||
|  | 				"steps to execute non-interactively" | ||||||
|  | 			) | ||||||
|  | 			( | ||||||
|  | 				"non-interactive,n", | ||||||
|  | 				po::bool_switch(&nonInteractive)->default_value(false), | ||||||
|  | 				"stop after executing the provided steps" | ||||||
|  | 			) | ||||||
|  | 			("help,h", "Show this help screen."); | ||||||
|  | 
 | ||||||
|  | 		// All positional options should be interpreted as input files
 | ||||||
|  | 		po::positional_options_description filesPositions; | ||||||
|  | 		filesPositions.add("input-file", 1); | ||||||
|  | 
 | ||||||
|  | 		po::variables_map arguments; | ||||||
| 		po::command_line_parser cmdLineParser(argc, argv); | 		po::command_line_parser cmdLineParser(argc, argv); | ||||||
| 		cmdLineParser.options(options).positional(filesPositions); | 		cmdLineParser.options(options).positional(filesPositions); | ||||||
| 		po::store(cmdLineParser.run(), arguments); | 		po::store(cmdLineParser.run(), arguments); | ||||||
|  | 		po::notify(arguments); | ||||||
|  | 
 | ||||||
|  | 		if (arguments.count("help")) | ||||||
|  | 		{ | ||||||
|  | 			cout << options; | ||||||
|  | 			return 0; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		string input; | ||||||
|  | 		if (arguments.count("input-file")) | ||||||
|  | 		{ | ||||||
|  | 			string filename = arguments["input-file"].as<string>(); | ||||||
|  | 			if (filename == "-") | ||||||
|  | 			{ | ||||||
|  | 				nonInteractive = true; | ||||||
|  | 				input = readUntilEnd(cin); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 				input = readFileAsString(arguments["input-file"].as<string>()); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			cout << options; | ||||||
|  | 			return 1; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (nonInteractive && !arguments.count("steps")) | ||||||
|  | 		{ | ||||||
|  | 			cout << options; | ||||||
|  | 			return 1; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		YulOpti yulOpti; | ||||||
|  | 		bool disambiguated = false; | ||||||
|  | 		if (!nonInteractive) | ||||||
|  | 			cout << input << endl; | ||||||
|  | 		if (arguments.count("steps")) | ||||||
|  | 		{ | ||||||
|  | 			string sequence = arguments["steps"].as<string>(); | ||||||
|  | 			if (!nonInteractive) | ||||||
|  | 				cout << "----------------------" << endl; | ||||||
|  | 			yulOpti.runSteps(input, sequence); | ||||||
|  | 			disambiguated = true; | ||||||
|  | 		} | ||||||
|  | 		if (!nonInteractive) | ||||||
|  | 			yulOpti.runInteractive(input, disambiguated); | ||||||
|  | 
 | ||||||
|  | 		return 0; | ||||||
| 	} | 	} | ||||||
| 	catch (po::error const& _exception) | 	catch (po::error const& _exception) | ||||||
| 	{ | 	{ | ||||||
| 		cerr << _exception.what() << endl; | 		cerr << _exception.what() << endl; | ||||||
| 		return 1; | 		return 1; | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	string input; |  | ||||||
| 	try |  | ||||||
| 	{ |  | ||||||
| 		input = readFileAsString(arguments["input-file"].as<string>()); |  | ||||||
| 	} |  | ||||||
| 	catch (FileNotFound const& _exception) | 	catch (FileNotFound const& _exception) | ||||||
| 	{ | 	{ | ||||||
| 		cerr << "File not found:" << _exception.comment() << endl; | 		cerr << "File not found:" << _exception.comment() << endl; | ||||||
| @ -290,11 +362,10 @@ Allowed options)", | |||||||
| 		cerr << "Not a regular file:" << _exception.comment() << endl; | 		cerr << "Not a regular file:" << _exception.comment() << endl; | ||||||
| 		return 1; | 		return 1; | ||||||
| 	} | 	} | ||||||
| 
 | 	catch(...) | ||||||
| 	if (arguments.count("input-file")) | 	{ | ||||||
| 		YulOpti{}.runInteractive(input); | 		cerr << endl << "Exception:" << endl; | ||||||
| 	else | 		cerr << boost::current_exception_diagnostic_information() << endl; | ||||||
| 		cout << options; | 		return 1; | ||||||
| 
 | 	} | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user