mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:32:46 +00:00 
			
		
		
		
	JSSpecCompiler: Provide an adequate command line interface
This commit is contained in:
		
							parent
							
								
									867ce0df52
								
							
						
					
					
						commit
						6ed069ea8d
					
				
					 10 changed files with 226 additions and 33 deletions
				
			
		|  | @ -5,21 +5,96 @@ | |||
|  */ | ||||
| 
 | ||||
| #include <AK/Format.h> | ||||
| #include <LibCore/File.h> | ||||
| #include <LibCore/ArgsParser.h> | ||||
| #include <LibMain/Main.h> | ||||
| #include <LibXML/Parser/Parser.h> | ||||
| 
 | ||||
| #include "Compiler/Passes/FunctionCallCanonicalizationPass.h" | ||||
| #include "Compiler/Passes/IfBranchMergingPass.h" | ||||
| #include "Compiler/Passes/ReferenceResolvingPass.h" | ||||
| #include "Function.h" | ||||
| #include "Parser/CppASTConverter.h" | ||||
| #include "Parser/SpecParser.h" | ||||
| 
 | ||||
| ErrorOr<int> serenity_main(Main::Arguments) | ||||
| using namespace JSSpecCompiler; | ||||
| 
 | ||||
| class CompilationPipeline { | ||||
| public: | ||||
|     template<typename T> | ||||
|     void add_compilation_pass() | ||||
|     { | ||||
|         auto func = +[](TranslationUnitRef translation_unit) { | ||||
|             T { translation_unit }.run(); | ||||
|         }; | ||||
|         add_step(adopt_own_if_nonnull(new NonOwningCompilationStep(T::name, func))); | ||||
|     } | ||||
| 
 | ||||
|     template<typename T> | ||||
|     void for_each_step_in(StringView pass_list, T&& func) | ||||
|     { | ||||
|         HashTable<StringView> selected_steps; | ||||
|         for (auto pass : pass_list.split_view(',')) { | ||||
|             if (pass == "all") { | ||||
|                 for (auto const& step : m_pipeline) | ||||
|                     selected_steps.set(step->name()); | ||||
|             } else if (pass == "last") { | ||||
|                 selected_steps.set(m_pipeline.last()->name()); | ||||
|             } else if (pass.starts_with('-')) { | ||||
|                 VERIFY(selected_steps.remove(pass.substring_view(1))); | ||||
|             } else { | ||||
|                 selected_steps.set(pass); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for (auto& step : m_pipeline) | ||||
|             if (selected_steps.contains(step->name())) | ||||
|                 func(step); | ||||
|     } | ||||
| 
 | ||||
|     void add_step(OwnPtr<CompilationStep>&& step) | ||||
|     { | ||||
|         m_pipeline.append(move(step)); | ||||
|     } | ||||
| 
 | ||||
|     auto const& pipeline() const { return m_pipeline; } | ||||
| 
 | ||||
| private: | ||||
|     Vector<OwnPtr<CompilationStep>> m_pipeline; | ||||
| }; | ||||
| 
 | ||||
| ErrorOr<int> serenity_main(Main::Arguments arguments) | ||||
| { | ||||
|     using namespace JSSpecCompiler; | ||||
|     Core::ArgsParser args_parser; | ||||
| 
 | ||||
|     StringView filename; | ||||
|     args_parser.add_positional_argument(filename, "File to compile", "file"); | ||||
| 
 | ||||
|     constexpr StringView language_spec = "spec"sv; | ||||
|     constexpr StringView language_cpp = "c++"sv; | ||||
|     StringView language = language_spec; | ||||
|     args_parser.add_option(Core::ArgsParser::Option { | ||||
|         .argument_mode = Core::ArgsParser::OptionArgumentMode::Optional, | ||||
|         .help_string = "Specify the language of the input file.", | ||||
|         .short_name = 'x', | ||||
|         .value_name = "{c++|spec}", | ||||
|         .accept_value = [&](StringView value) { | ||||
|             language = value; | ||||
|             return language.is_one_of(language_spec, language_cpp); | ||||
|         }, | ||||
|     }); | ||||
| 
 | ||||
|     args_parser.parse(arguments); | ||||
| 
 | ||||
|     CompilationPipeline pipeline; | ||||
|     if (language == language_cpp) | ||||
|         pipeline.add_step(adopt_own_if_nonnull(new CppParsingStep())); | ||||
|     else | ||||
|         pipeline.add_step(adopt_own_if_nonnull(new SpecParsingStep())); | ||||
|     pipeline.add_compilation_pass<FunctionCallCanonicalizationPass>(); | ||||
|     pipeline.add_compilation_pass<IfBranchMergingPass>(); | ||||
|     pipeline.add_compilation_pass<ReferenceResolvingPass>(); | ||||
| 
 | ||||
|     TranslationUnit translation_unit; | ||||
|     translation_unit.filename = filename; | ||||
| 
 | ||||
|     // Functions referenced in DifferenceISODate
 | ||||
|     // TODO: This is here just for testing. In a long run, we need some place, which is not
 | ||||
|  | @ -33,33 +108,8 @@ ErrorOr<int> serenity_main(Main::Arguments) | |||
|     functions.set("truncate"sv, make_ref_counted<FunctionPointer>("truncate"sv)); | ||||
|     functions.set("remainder"sv, make_ref_counted<FunctionPointer>("remainder"sv)); | ||||
| 
 | ||||
|     auto input = TRY(TRY(Core::File::standard_input())->read_until_eof()); | ||||
|     XML::Parser parser { StringView(input.bytes()) }; | ||||
|     for (auto const& step : pipeline.pipeline()) | ||||
|         step->run(&translation_unit); | ||||
| 
 | ||||
|     auto maybe_document = parser.parse(); | ||||
|     if (maybe_document.is_error()) { | ||||
|         outln("{}", maybe_document.error()); | ||||
|         return 1; | ||||
|     } | ||||
|     auto document = maybe_document.release_value(); | ||||
| 
 | ||||
|     auto maybe_function = JSSpecCompiler::SpecFunction::create(&document.root()); | ||||
|     if (maybe_function.is_error()) { | ||||
|         outln("{}", maybe_function.error()->to_string()); | ||||
|         return 1; | ||||
|     } | ||||
|     auto spec_function = maybe_function.value(); | ||||
| 
 | ||||
|     auto* function = translation_unit.adopt_function( | ||||
|         make_ref_counted<FunctionDefinition>(spec_function.m_name, spec_function.m_algorithm.m_tree)); | ||||
| 
 | ||||
|     for (auto const& argument : spec_function.m_arguments) | ||||
|         function->m_local_variables.set(argument.name, make_ref_counted<VariableDeclaration>(argument.name)); | ||||
| 
 | ||||
|     FunctionCallCanonicalizationPass(&translation_unit).run(); | ||||
|     IfBranchMergingPass(&translation_unit).run(); | ||||
|     ReferenceResolvingPass(&translation_unit).run(); | ||||
| 
 | ||||
|     out("{}", function->m_ast); | ||||
|     return 0; | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Klishch
						Dan Klishch