// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "explorer/main.h" #include #include #include #include #include #include #include #include #include "common/error.h" #include "explorer/common/arena.h" #include "explorer/common/nonnull.h" #include "explorer/interpreter/exec_program.h" #include "explorer/interpreter/trace_stream.h" #include "explorer/syntax/parse.h" #include "explorer/syntax/prelude.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" namespace Carbon { namespace cl = llvm::cl; namespace path = llvm::sys::path; auto ExplorerMain(int argc, char** argv, void* static_for_main_addr, llvm::StringRef relative_prelude_path) -> int { llvm::setBugReportMsg( "Please report issues to " "https://github.com/carbon-language/carbon-lang/issues and include the " "crash backtrace.\n"); llvm::InitLLVM init_llvm(argc, argv); // Printing to stderr should flush stdout. This is most noticeable when stderr // is piped to stdout. llvm::errs().tie(&llvm::outs()); cl::opt input_file_name(cl::Positional, cl::desc(""), cl::Required); cl::opt parser_debug("parser_debug", cl::desc("Enable debug output from the parser")); cl::opt trace_file_name( "trace_file", cl::desc("Output file for tracing; set to `-` to output to stdout.")); // Use the executable path as a base for the relative prelude path. std::string exe = llvm::sys::fs::getMainExecutable(argv[0], static_for_main_addr); llvm::StringRef install_path = path::parent_path(exe); llvm::SmallString<256> default_prelude_file(install_path); path::append(default_prelude_file, path::begin(relative_prelude_path, path::Style::posix), path::end(relative_prelude_path)); std::string default_prelude_file_str(default_prelude_file); cl::opt prelude_file_name("prelude", cl::desc(""), cl::init(default_prelude_file_str)); cl::ParseCommandLineOptions(argc, argv); // Set up a stream for trace output. std::unique_ptr scoped_trace_stream; TraceStream trace_stream; if (!trace_file_name.empty()) { if (trace_file_name == "-") { trace_stream.set_stream(&llvm::outs()); } else { std::error_code err; scoped_trace_stream = std::make_unique(trace_file_name, err); if (err) { llvm::errs() << err.message() << "\n"; return EXIT_FAILURE; } trace_stream.set_stream(scoped_trace_stream.get()); } } auto time_start = std::chrono::system_clock::now(); Arena arena; AST ast; if (ErrorOr parse_result = Parse(&arena, input_file_name, parser_debug); parse_result.ok()) { ast = *std::move(parse_result); } else { llvm::errs() << "SYNTAX ERROR: " << parse_result.error() << "\n"; return EXIT_FAILURE; } auto time_after_parse = std::chrono::system_clock::now(); AddPrelude(prelude_file_name, &arena, &ast.declarations, &ast.num_prelude_declarations); auto time_after_prelude = std::chrono::system_clock::now(); // Semantically analyze the parsed program. if (ErrorOr analyze_result = AnalyzeProgram(&arena, ast, &trace_stream, &llvm::outs()); analyze_result.ok()) { ast = *std::move(analyze_result); } else { llvm::errs() << "COMPILATION ERROR: " << analyze_result.error() << "\n"; return EXIT_FAILURE; } auto time_after_analyze = std::chrono::system_clock::now(); // Run the program. auto ret = EXIT_SUCCESS; if (ErrorOr exec_result = ExecProgram(&arena, ast, &trace_stream, &llvm::outs()); exec_result.ok()) { // Print the return code to stdout. llvm::outs() << "result: " << *exec_result << "\n"; // When there's a dedicated trace file, print the return code to it too. if (scoped_trace_stream) { trace_stream << "result: " << *exec_result << "\n"; } } else { llvm::errs() << "RUNTIME ERROR: " << exec_result.error() << "\n"; ret = EXIT_FAILURE; } auto time_after_exec = std::chrono::system_clock::now(); if (trace_stream.is_enabled()) { trace_stream << "Timings:\n" << "- Parse: " << std::chrono::duration_cast( time_after_parse - time_start) .count() << "ms\n" << "- AddPrelude: " << std::chrono::duration_cast( time_after_prelude - time_after_parse) .count() << "ms\n" << "- AnalyzeProgram: " << std::chrono::duration_cast( time_after_analyze - time_after_prelude) .count() << "ms\n" << "- ExecProgram: " << std::chrono::duration_cast( time_after_exec - time_after_analyze) .count() << "ms\n"; } return ret; } } // namespace Carbon