2026-07-25 23:01:18 +02:00
|
|
|
#include "bscript/compiler/Compiler.h"
|
2020-08-04 22:42:46 -07:00
|
|
|
|
2026-07-08 19:58:41 +02:00
|
|
|
#include <fstream>
|
|
|
|
|
|
2021-02-25 16:53:22 +01:00
|
|
|
#include "bscript/compiler/Profile.h"
|
|
|
|
|
#include "bscript/compiler/Report.h"
|
|
|
|
|
#include "bscript/compiler/analyzer/Disambiguator.h"
|
|
|
|
|
#include "bscript/compiler/analyzer/SemanticAnalyzer.h"
|
2025-07-28 21:48:34 +02:00
|
|
|
#include "bscript/compiler/analyzer/ShortCircuitWarning.h"
|
|
|
|
|
#include "bscript/compiler/ast/TopLevelStatements.h"
|
2021-02-25 16:53:22 +01:00
|
|
|
#include "bscript/compiler/astbuilder/CompilerWorkspaceBuilder.h"
|
|
|
|
|
#include "bscript/compiler/codegen/CodeGenerator.h"
|
2024-02-26 21:21:44 +01:00
|
|
|
#include "bscript/compiler/file/PrettifyBuilder.h"
|
2021-02-25 16:53:22 +01:00
|
|
|
#include "bscript/compiler/file/SourceFileCache.h"
|
|
|
|
|
#include "bscript/compiler/file/SourceFileIdentifier.h"
|
|
|
|
|
#include "bscript/compiler/format/CompiledScriptSerializer.h"
|
|
|
|
|
#include "bscript/compiler/format/DebugStoreSerializer.h"
|
|
|
|
|
#include "bscript/compiler/format/ListingWriter.h"
|
|
|
|
|
#include "bscript/compiler/model/CompilerWorkspace.h"
|
|
|
|
|
#include "bscript/compiler/optimizer/Optimizer.h"
|
|
|
|
|
#include "bscript/compiler/representation/CompiledScript.h"
|
2024-01-10 18:29:10 +01:00
|
|
|
#include "clib/fileutil.h"
|
|
|
|
|
#include "clib/logfacility.h"
|
|
|
|
|
#include "clib/timer.h"
|
2026-07-25 23:01:18 +02:00
|
|
|
#include "bscript/compilercfg.h"
|
2020-08-08 07:31:55 -07:00
|
|
|
|
2020-08-10 03:20:29 -07:00
|
|
|
namespace Pol::Bscript::Compiler
|
2020-08-04 22:42:46 -07:00
|
|
|
{
|
2020-08-16 17:22:16 -07:00
|
|
|
Compiler::Compiler( SourceFileCache& em_cache, SourceFileCache& inc_cache, Profile& profile )
|
2024-01-10 18:29:10 +01:00
|
|
|
: em_cache( em_cache ), inc_cache( inc_cache ), profile( profile )
|
2020-08-08 07:31:55 -07:00
|
|
|
{
|
|
|
|
|
}
|
2020-08-04 22:42:46 -07:00
|
|
|
|
|
|
|
|
Compiler::~Compiler() = default;
|
|
|
|
|
|
2020-08-10 00:00:47 -07:00
|
|
|
bool Compiler::write_ecl( const std::string& pathname )
|
2020-08-04 22:42:46 -07:00
|
|
|
{
|
2020-08-10 00:00:47 -07:00
|
|
|
if ( output )
|
|
|
|
|
{
|
|
|
|
|
CompiledScriptSerializer( *output ).write( pathname );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2026-01-18 09:35:52 +01:00
|
|
|
|
|
|
|
|
return false;
|
2020-08-04 22:42:46 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-11 03:49:18 -07:00
|
|
|
void Compiler::write_listing( const std::string& pathname )
|
2020-08-04 22:42:46 -07:00
|
|
|
{
|
2020-08-11 03:49:18 -07:00
|
|
|
if ( output )
|
|
|
|
|
{
|
|
|
|
|
std::ofstream ofs( pathname );
|
|
|
|
|
ListingWriter( *output ).write( ofs );
|
|
|
|
|
}
|
2020-08-04 22:42:46 -07:00
|
|
|
}
|
|
|
|
|
|
2025-07-23 23:00:34 +02:00
|
|
|
void Compiler::write_string_tree( const std::string& pathname )
|
|
|
|
|
{
|
|
|
|
|
if ( output )
|
|
|
|
|
{
|
|
|
|
|
std::ofstream ofs( pathname );
|
|
|
|
|
ofs << output->tree;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-12 14:26:58 -07:00
|
|
|
void Compiler::write_dbg( const std::string& pathname, bool include_debug_text )
|
2020-08-04 22:42:46 -07:00
|
|
|
{
|
2020-09-12 14:26:58 -07:00
|
|
|
if ( output )
|
|
|
|
|
{
|
|
|
|
|
std::ofstream ofs( pathname, std::ofstream::binary );
|
|
|
|
|
auto text_ofs = include_debug_text ? std::make_unique<std::ofstream>( pathname + ".txt" )
|
|
|
|
|
: std::unique_ptr<std::ofstream>();
|
|
|
|
|
|
2024-01-10 18:29:10 +01:00
|
|
|
DebugStoreSerializer( *output ).write( ofs, text_ofs.get() );
|
2020-09-12 14:26:58 -07:00
|
|
|
}
|
2020-08-04 22:42:46 -07:00
|
|
|
}
|
|
|
|
|
|
2020-09-13 01:13:23 -07:00
|
|
|
void Compiler::write_included_filenames( const std::string& pathname )
|
2020-08-04 22:42:46 -07:00
|
|
|
{
|
2020-09-13 01:13:23 -07:00
|
|
|
if ( output )
|
|
|
|
|
{
|
|
|
|
|
std::ofstream ofs( pathname );
|
2024-01-10 18:29:10 +01:00
|
|
|
for ( auto& r : output->source_file_identifiers )
|
2020-09-13 01:13:23 -07:00
|
|
|
{
|
|
|
|
|
ofs << r->pathname << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-04 22:42:46 -07:00
|
|
|
}
|
|
|
|
|
|
2020-09-13 00:41:45 -07:00
|
|
|
void Compiler::set_include_compile_mode()
|
|
|
|
|
{
|
|
|
|
|
user_function_inclusion = UserFunctionInclusion::All;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-06 01:39:26 +01:00
|
|
|
bool Compiler::compile_file( const std::string& filename )
|
2020-08-05 00:01:07 -07:00
|
|
|
{
|
2020-08-08 07:31:55 -07:00
|
|
|
bool success;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
auto pathname = Clib::FullPath( filename.c_str() );
|
|
|
|
|
|
2024-08-11 23:01:38 +02:00
|
|
|
Report report( compilercfg.DisplayWarnings || compilercfg.ErrorOnWarning,
|
|
|
|
|
true /* display errors */, compilercfg.DisplayDebugs );
|
2020-08-08 07:31:55 -07:00
|
|
|
|
2021-03-06 01:39:26 +01:00
|
|
|
compile_file_steps( pathname, report );
|
2020-08-08 07:31:55 -07:00
|
|
|
display_outcome( pathname, report );
|
|
|
|
|
|
|
|
|
|
bool have_warning_as_error = report.warning_count() && compilercfg.ErrorOnWarning;
|
|
|
|
|
success = !report.error_count() && !have_warning_as_error;
|
|
|
|
|
}
|
|
|
|
|
catch ( std::exception& ex )
|
|
|
|
|
{
|
2024-01-12 06:51:44 +01:00
|
|
|
ERROR_PRINTLN( ex.what() );
|
2020-08-08 07:31:55 -07:00
|
|
|
success = false;
|
|
|
|
|
}
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-06 01:39:26 +01:00
|
|
|
void Compiler::compile_file_steps( const std::string& pathname, Report& report )
|
2020-08-10 00:42:37 -07:00
|
|
|
{
|
2021-03-06 01:39:26 +01:00
|
|
|
std::unique_ptr<CompilerWorkspace> workspace = build_workspace( pathname, report );
|
2020-08-10 00:42:37 -07:00
|
|
|
if ( report.error_count() )
|
|
|
|
|
return;
|
|
|
|
|
|
2020-09-11 00:16:20 -07:00
|
|
|
register_constants( *workspace, report );
|
2020-08-10 01:37:07 -07:00
|
|
|
if ( report.error_count() )
|
|
|
|
|
return;
|
|
|
|
|
|
2020-08-10 04:54:59 -07:00
|
|
|
optimize( *workspace, report );
|
|
|
|
|
if ( report.error_count() )
|
|
|
|
|
return;
|
|
|
|
|
|
2020-08-10 23:21:34 -07:00
|
|
|
disambiguate( *workspace, report );
|
|
|
|
|
if ( report.error_count() )
|
|
|
|
|
return;
|
|
|
|
|
|
2021-03-06 01:39:26 +01:00
|
|
|
analyze( *workspace, report );
|
2020-08-10 01:37:07 -07:00
|
|
|
if ( report.error_count() )
|
|
|
|
|
return;
|
2020-08-11 00:08:48 -07:00
|
|
|
|
2025-07-28 21:48:34 +02:00
|
|
|
check_short_circuit( *workspace, report );
|
|
|
|
|
if ( report.error_count() )
|
|
|
|
|
return;
|
|
|
|
|
|
2024-08-19 19:57:31 +02:00
|
|
|
output = generate( std::move( workspace ), report );
|
2020-08-10 00:42:37 -07:00
|
|
|
}
|
|
|
|
|
|
2024-02-26 21:21:44 +01:00
|
|
|
bool Compiler::format_file( const std::string& filename, bool is_module, bool inplace )
|
|
|
|
|
{
|
2024-10-03 15:10:21 +02:00
|
|
|
if ( !Clib::filesize( filename.c_str() ) )
|
|
|
|
|
return true;
|
|
|
|
|
|
2024-02-26 21:21:44 +01:00
|
|
|
Report report( false, true );
|
|
|
|
|
PrettifyBuilder prettify_builder( profile, report );
|
|
|
|
|
auto formatted = prettify_builder.build( filename, is_module );
|
|
|
|
|
if ( report.error_count() )
|
|
|
|
|
return false;
|
|
|
|
|
if ( inplace )
|
|
|
|
|
{
|
|
|
|
|
std::ofstream filestream;
|
2024-09-13 06:49:00 +02:00
|
|
|
filestream.open( filename, std::ios_base::out | std::ios_base::trunc | std::ios::binary );
|
2024-02-26 21:21:44 +01:00
|
|
|
filestream << formatted;
|
|
|
|
|
filestream.flush();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
INFO_PRINTLN( formatted );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-06 01:39:26 +01:00
|
|
|
std::unique_ptr<CompilerWorkspace> Compiler::build_workspace( const std::string& pathname,
|
|
|
|
|
Report& report )
|
2020-08-08 07:31:55 -07:00
|
|
|
{
|
2020-08-10 00:42:37 -07:00
|
|
|
Pol::Tools::HighPerfTimer timer;
|
2020-08-16 17:22:16 -07:00
|
|
|
CompilerWorkspaceBuilder workspace_builder( em_cache, inc_cache, profile, report );
|
2021-03-06 01:39:26 +01:00
|
|
|
auto workspace = workspace_builder.build( pathname, user_function_inclusion );
|
2020-08-10 00:42:37 -07:00
|
|
|
profile.build_workspace_micros += timer.ellapsed().count();
|
|
|
|
|
return workspace;
|
2020-08-08 07:31:55 -07:00
|
|
|
}
|
|
|
|
|
|
2020-09-11 00:16:20 -07:00
|
|
|
void Compiler::register_constants( CompilerWorkspace& workspace, Report& report )
|
2020-08-10 01:37:07 -07:00
|
|
|
{
|
|
|
|
|
Pol::Tools::HighPerfTimer timer;
|
2020-09-11 00:16:20 -07:00
|
|
|
SemanticAnalyzer::register_const_declarations( workspace, report );
|
2020-08-10 01:37:07 -07:00
|
|
|
profile.register_const_declarations_micros += timer.ellapsed().count();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-10 04:54:59 -07:00
|
|
|
void Compiler::optimize( CompilerWorkspace& workspace, Report& report )
|
|
|
|
|
{
|
|
|
|
|
Pol::Tools::HighPerfTimer timer;
|
2020-09-01 00:54:24 -07:00
|
|
|
Optimizer optimizer( workspace.constants, report );
|
2020-09-13 00:41:45 -07:00
|
|
|
optimizer.optimize( workspace, user_function_inclusion );
|
2020-08-10 04:54:59 -07:00
|
|
|
profile.optimize_micros += timer.ellapsed().count();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-10 23:21:34 -07:00
|
|
|
void Compiler::disambiguate( CompilerWorkspace& workspace, Report& report )
|
|
|
|
|
{
|
|
|
|
|
Pol::Tools::HighPerfTimer timer;
|
2020-09-05 21:52:56 -07:00
|
|
|
Disambiguator disambiguator( workspace.constants, report );
|
2020-08-10 23:21:34 -07:00
|
|
|
disambiguator.disambiguate( workspace );
|
|
|
|
|
profile.disambiguate_micros += timer.ellapsed().count();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-10 01:37:07 -07:00
|
|
|
void Compiler::analyze( CompilerWorkspace& workspace, Report& report )
|
|
|
|
|
{
|
|
|
|
|
Pol::Tools::HighPerfTimer timer;
|
2020-09-11 00:16:20 -07:00
|
|
|
SemanticAnalyzer analyzer( workspace, report );
|
|
|
|
|
analyzer.analyze();
|
2020-08-10 01:37:07 -07:00
|
|
|
profile.analyze_micros += timer.ellapsed().count();
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-28 21:48:34 +02:00
|
|
|
void Compiler::check_short_circuit( CompilerWorkspace& workspace, Report& report )
|
|
|
|
|
{
|
|
|
|
|
ShortCircuitWarning warn{ report };
|
|
|
|
|
warn.warn( workspace );
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-19 19:57:31 +02:00
|
|
|
std::unique_ptr<CompiledScript> Compiler::generate( std::unique_ptr<CompilerWorkspace> workspace,
|
|
|
|
|
Report& report )
|
2020-08-11 00:08:48 -07:00
|
|
|
{
|
|
|
|
|
Pol::Tools::HighPerfTimer codegen_timer;
|
2025-07-23 23:00:34 +02:00
|
|
|
auto compiled_script = CodeGenerator::generate( std::move( workspace ), report,
|
|
|
|
|
compilercfg.GenerateAbstractSyntaxTree );
|
2020-08-11 00:08:48 -07:00
|
|
|
profile.codegen_micros += codegen_timer.ellapsed().count();
|
|
|
|
|
return compiled_script;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-08 07:31:55 -07:00
|
|
|
void Compiler::display_outcome( const std::string& filename, Report& report )
|
|
|
|
|
{
|
2024-01-10 18:29:10 +01:00
|
|
|
auto msg = fmt::format( "{}: {} errors", filename, report.error_count() );
|
2020-08-08 07:31:55 -07:00
|
|
|
if ( compilercfg.DisplayWarnings || compilercfg.ErrorOnWarning )
|
2024-01-10 18:29:10 +01:00
|
|
|
msg += fmt::format( ", {} warnings", report.warning_count() );
|
|
|
|
|
INFO_PRINTLN( msg + '.' );
|
2020-08-05 00:01:07 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-10 03:20:29 -07:00
|
|
|
} // namespace Pol::Bscript::Compiler
|