polserver/pol-core/bscript/compiler/Compiler.cpp

235 lines
6.9 KiB
C++
Raw Permalink Normal View History

#include "bscript/compiler/Compiler.h"
#include <fstream>
#include "bscript/compiler/Profile.h"
#include "bscript/compiler/Report.h"
#include "bscript/compiler/analyzer/Disambiguator.h"
#include "bscript/compiler/analyzer/SemanticAnalyzer.h"
#include "bscript/compiler/analyzer/ShortCircuitWarning.h"
#include "bscript/compiler/ast/TopLevelStatements.h"
#include "bscript/compiler/astbuilder/CompilerWorkspaceBuilder.h"
#include "bscript/compiler/codegen/CodeGenerator.h"
"Preview/Initial"- Version sourcecode formatting feature (#626) * Squash only prettify changes from escript_formating_try * support of "format-off" / "format-on" comments to mark areas without formatting * fix typo * added FormatterIdentLevel, FormatterMergeEmptyLines cfg entry better line splits for dicts/arrays * added several spacing options. the current setting list is now: //LineWidth FormatterLineWidth 80 // keep original keyword spelling FormatterKeepKeywords 0 // number of spaces for ident FormatterIdentLevel 2 // multiple newlines get merged to a single FormatterMergeEmptyLines 1 // space between emtpy parenthesis eg foo() vs foo( ) FormatterEmptyParenthesisSpacing 0 // space between emtpy brackets eg struct{} vs struct{ } FormatterEmptyBracketSpacing 0 // space after/before parenthesis in conditionals // eg if ( true ) vs if (true) FormatterConditionalParenthesisSpacing 1 // space after/before parenthesis // eg foo( true ) vs foo(true) FormatterParenthesisSpacing 1 // space after/before brackets // eg array{ true } vs array{true} FormatterBracketSpacing 1 // add space after delimiter comma or semi in for loops // eg {1, 2, 3} vs {1,2,3} FormatterDelimiterSpacing 1 // add space around assignment // eg a := 1; vs a:=1; FormatterAssignmentSpacing 1 // add space around comparison // eg a == 1 vs a==1 FormatterComparisonSpacing 1 // add space around operations // eg a + 1 vs a+1 FormatterOperatorSpacing 1 // use \r\n as newline instead of \n FormatterWindowsLineEndings 0 * added tab support // use tabs instead of spaces FormatterUseTabs 0 // tab width FormatterTabWidth 4 * extended example ecompile.cfg with formatter settings * cleanup * program args comma is optional... fixed line comments in group splitting * since tokenids are now correct no more guessing for linecomments needed * comments use as start tokenid the whitespace token if its on the same line * splitted processing from linebuilding * renamed TokenPart to FmtToken better matches the purpose. Comments get directly stored as FmtToken started with a context enum * better(?) formatting for groups * fix eof rawlines added check that all comments/rawlines got parsed * const correctness * datatype adapted to antlr * fixed warnings * added InsertNewlineAtEOF * add newline at the end if the original file had one dont strip comment whitespace if its somejind of "header block" use the defined lineending for /* */ comments * docs * \r\n is default on windows \n otherwise * fixed warning --------- Co-authored-by: Kevin Eady <8634912+KevinEady@users.noreply.github.com>
2024-02-26 21:21:44 +01:00
#include "bscript/compiler/file/PrettifyBuilder.h"
#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"
#include "clib/fileutil.h"
#include "clib/logfacility.h"
#include "clib/timer.h"
#include "bscript/compilercfg.h"
namespace Pol::Bscript::Compiler
{
Compiler::Compiler( SourceFileCache& em_cache, SourceFileCache& inc_cache, Profile& profile )
: em_cache( em_cache ), inc_cache( inc_cache ), profile( profile )
{
}
Compiler::~Compiler() = default;
bool Compiler::write_ecl( const std::string& pathname )
{
if ( output )
{
CompiledScriptSerializer( *output ).write( pathname );
return true;
}
return false;
}
void Compiler::write_listing( const std::string& pathname )
{
if ( output )
{
std::ofstream ofs( pathname );
ListingWriter( *output ).write( ofs );
}
}
void Compiler::write_string_tree( const std::string& pathname )
{
if ( output )
{
std::ofstream ofs( pathname );
ofs << output->tree;
}
}
void Compiler::write_dbg( const std::string& pathname, bool include_debug_text )
{
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>();
DebugStoreSerializer( *output ).write( ofs, text_ofs.get() );
}
}
void Compiler::write_included_filenames( const std::string& pathname )
{
if ( output )
{
std::ofstream ofs( pathname );
for ( auto& r : output->source_file_identifiers )
{
ofs << r->pathname << "\n";
}
}
}
void Compiler::set_include_compile_mode()
{
user_function_inclusion = UserFunctionInclusion::All;
}
bool Compiler::compile_file( const std::string& filename )
{
bool success;
try
{
auto pathname = Clib::FullPath( filename.c_str() );
Report report( compilercfg.DisplayWarnings || compilercfg.ErrorOnWarning,
true /* display errors */, compilercfg.DisplayDebugs );
compile_file_steps( pathname, report );
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 )
{
ERROR_PRINTLN( ex.what() );
success = false;
}
return success;
}
void Compiler::compile_file_steps( const std::string& pathname, Report& report )
{
std::unique_ptr<CompilerWorkspace> workspace = build_workspace( pathname, report );
if ( report.error_count() )
return;
register_constants( *workspace, report );
if ( report.error_count() )
return;
2020-08-10 04:54:59 -07:00
optimize( *workspace, report );
if ( report.error_count() )
return;
disambiguate( *workspace, report );
if ( report.error_count() )
return;
analyze( *workspace, report );
if ( report.error_count() )
return;
check_short_circuit( *workspace, report );
if ( report.error_count() )
return;
output = generate( std::move( workspace ), report );
}
"Preview/Initial"- Version sourcecode formatting feature (#626) * Squash only prettify changes from escript_formating_try * support of "format-off" / "format-on" comments to mark areas without formatting * fix typo * added FormatterIdentLevel, FormatterMergeEmptyLines cfg entry better line splits for dicts/arrays * added several spacing options. the current setting list is now: //LineWidth FormatterLineWidth 80 // keep original keyword spelling FormatterKeepKeywords 0 // number of spaces for ident FormatterIdentLevel 2 // multiple newlines get merged to a single FormatterMergeEmptyLines 1 // space between emtpy parenthesis eg foo() vs foo( ) FormatterEmptyParenthesisSpacing 0 // space between emtpy brackets eg struct{} vs struct{ } FormatterEmptyBracketSpacing 0 // space after/before parenthesis in conditionals // eg if ( true ) vs if (true) FormatterConditionalParenthesisSpacing 1 // space after/before parenthesis // eg foo( true ) vs foo(true) FormatterParenthesisSpacing 1 // space after/before brackets // eg array{ true } vs array{true} FormatterBracketSpacing 1 // add space after delimiter comma or semi in for loops // eg {1, 2, 3} vs {1,2,3} FormatterDelimiterSpacing 1 // add space around assignment // eg a := 1; vs a:=1; FormatterAssignmentSpacing 1 // add space around comparison // eg a == 1 vs a==1 FormatterComparisonSpacing 1 // add space around operations // eg a + 1 vs a+1 FormatterOperatorSpacing 1 // use \r\n as newline instead of \n FormatterWindowsLineEndings 0 * added tab support // use tabs instead of spaces FormatterUseTabs 0 // tab width FormatterTabWidth 4 * extended example ecompile.cfg with formatter settings * cleanup * program args comma is optional... fixed line comments in group splitting * since tokenids are now correct no more guessing for linecomments needed * comments use as start tokenid the whitespace token if its on the same line * splitted processing from linebuilding * renamed TokenPart to FmtToken better matches the purpose. Comments get directly stored as FmtToken started with a context enum * better(?) formatting for groups * fix eof rawlines added check that all comments/rawlines got parsed * const correctness * datatype adapted to antlr * fixed warnings * added InsertNewlineAtEOF * add newline at the end if the original file had one dont strip comment whitespace if its somejind of "header block" use the defined lineending for /* */ comments * docs * \r\n is default on windows \n otherwise * fixed warning --------- Co-authored-by: Kevin Eady <8634912+KevinEady@users.noreply.github.com>
2024-02-26 21:21:44 +01:00
bool Compiler::format_file( const std::string& filename, bool is_module, bool inplace )
{
if ( !Clib::filesize( filename.c_str() ) )
return true;
"Preview/Initial"- Version sourcecode formatting feature (#626) * Squash only prettify changes from escript_formating_try * support of "format-off" / "format-on" comments to mark areas without formatting * fix typo * added FormatterIdentLevel, FormatterMergeEmptyLines cfg entry better line splits for dicts/arrays * added several spacing options. the current setting list is now: //LineWidth FormatterLineWidth 80 // keep original keyword spelling FormatterKeepKeywords 0 // number of spaces for ident FormatterIdentLevel 2 // multiple newlines get merged to a single FormatterMergeEmptyLines 1 // space between emtpy parenthesis eg foo() vs foo( ) FormatterEmptyParenthesisSpacing 0 // space between emtpy brackets eg struct{} vs struct{ } FormatterEmptyBracketSpacing 0 // space after/before parenthesis in conditionals // eg if ( true ) vs if (true) FormatterConditionalParenthesisSpacing 1 // space after/before parenthesis // eg foo( true ) vs foo(true) FormatterParenthesisSpacing 1 // space after/before brackets // eg array{ true } vs array{true} FormatterBracketSpacing 1 // add space after delimiter comma or semi in for loops // eg {1, 2, 3} vs {1,2,3} FormatterDelimiterSpacing 1 // add space around assignment // eg a := 1; vs a:=1; FormatterAssignmentSpacing 1 // add space around comparison // eg a == 1 vs a==1 FormatterComparisonSpacing 1 // add space around operations // eg a + 1 vs a+1 FormatterOperatorSpacing 1 // use \r\n as newline instead of \n FormatterWindowsLineEndings 0 * added tab support // use tabs instead of spaces FormatterUseTabs 0 // tab width FormatterTabWidth 4 * extended example ecompile.cfg with formatter settings * cleanup * program args comma is optional... fixed line comments in group splitting * since tokenids are now correct no more guessing for linecomments needed * comments use as start tokenid the whitespace token if its on the same line * splitted processing from linebuilding * renamed TokenPart to FmtToken better matches the purpose. Comments get directly stored as FmtToken started with a context enum * better(?) formatting for groups * fix eof rawlines added check that all comments/rawlines got parsed * const correctness * datatype adapted to antlr * fixed warnings * added InsertNewlineAtEOF * add newline at the end if the original file had one dont strip comment whitespace if its somejind of "header block" use the defined lineending for /* */ comments * docs * \r\n is default on windows \n otherwise * fixed warning --------- Co-authored-by: Kevin Eady <8634912+KevinEady@users.noreply.github.com>
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;
more formatting improvements (#696) * more formatting improvements: replace inside of comments tabs with spaces if UseTabs is false do not strip whitespaces at the beginning of linecomments better handling of long lines eg string additions "binpack": if an array fits equally into up to 3 lines use this instead of having each element in a newline struct/dicts get only packed if they fit into a single line, or half of the room for two lines align comments in statements * fixed linecomment forcing newline in simple splits formatting of functionexpressions ``` @(blubb) { blah; }; ``` * fixed windows lineendings fixed extra newline before long comment in certain situations added option FormatterFormatInsideComments to deactivate trimming and replacing of tabs * fixed typo.. ecompile cfg is now FormatterIndentLevel * FormatterBracketAttachToType: array{} vs array {} FormatterAllowSingleLines: allow single line case/functionrefs * align case label expressions comments at the end still make the expression packable other bugs * better detection of case labels, by buffering the text. fixed more problems with comments while packing lines * do not allow more then 3 lines to be packed to a single one * fixed hopefully last bug with comments and packing removed FormatterAllowSingleLines added FormatterAlignTrailingComments FormatterAlignConsecutiveShortCaseStatements FormatterAllowShortCaseLabelsOnASingleLine FormatterAllowShortFuncRefsOnASingleLine * better linesplits when prefferedBreak is used (functions with params) * fixed unalign lines with comments in arrays * simplified ecompile code, use callback for compilation during iteration through the directories. use for pkgs recursive_directory_iterator * core-changes * onlinedocs * onlinedocs-typo * corrected cfg * do not touch comments at all when disabled detect aligned */ * fixed group formatting in var statements in more complicated situations * when packing finishes right before the last element check if this element also fit into the last line * remaining ); or similar parts dont start a new line during group formatting * fixed edge cases of preferredBreak tactic with paranthesis alignment * changed defaults, updated docs
2024-09-13 06:49:00 +02:00
filestream.open( filename, std::ios_base::out | std::ios_base::trunc | std::ios::binary );
"Preview/Initial"- Version sourcecode formatting feature (#626) * Squash only prettify changes from escript_formating_try * support of "format-off" / "format-on" comments to mark areas without formatting * fix typo * added FormatterIdentLevel, FormatterMergeEmptyLines cfg entry better line splits for dicts/arrays * added several spacing options. the current setting list is now: //LineWidth FormatterLineWidth 80 // keep original keyword spelling FormatterKeepKeywords 0 // number of spaces for ident FormatterIdentLevel 2 // multiple newlines get merged to a single FormatterMergeEmptyLines 1 // space between emtpy parenthesis eg foo() vs foo( ) FormatterEmptyParenthesisSpacing 0 // space between emtpy brackets eg struct{} vs struct{ } FormatterEmptyBracketSpacing 0 // space after/before parenthesis in conditionals // eg if ( true ) vs if (true) FormatterConditionalParenthesisSpacing 1 // space after/before parenthesis // eg foo( true ) vs foo(true) FormatterParenthesisSpacing 1 // space after/before brackets // eg array{ true } vs array{true} FormatterBracketSpacing 1 // add space after delimiter comma or semi in for loops // eg {1, 2, 3} vs {1,2,3} FormatterDelimiterSpacing 1 // add space around assignment // eg a := 1; vs a:=1; FormatterAssignmentSpacing 1 // add space around comparison // eg a == 1 vs a==1 FormatterComparisonSpacing 1 // add space around operations // eg a + 1 vs a+1 FormatterOperatorSpacing 1 // use \r\n as newline instead of \n FormatterWindowsLineEndings 0 * added tab support // use tabs instead of spaces FormatterUseTabs 0 // tab width FormatterTabWidth 4 * extended example ecompile.cfg with formatter settings * cleanup * program args comma is optional... fixed line comments in group splitting * since tokenids are now correct no more guessing for linecomments needed * comments use as start tokenid the whitespace token if its on the same line * splitted processing from linebuilding * renamed TokenPart to FmtToken better matches the purpose. Comments get directly stored as FmtToken started with a context enum * better(?) formatting for groups * fix eof rawlines added check that all comments/rawlines got parsed * const correctness * datatype adapted to antlr * fixed warnings * added InsertNewlineAtEOF * add newline at the end if the original file had one dont strip comment whitespace if its somejind of "header block" use the defined lineending for /* */ comments * docs * \r\n is default on windows \n otherwise * fixed warning --------- Co-authored-by: Kevin Eady <8634912+KevinEady@users.noreply.github.com>
2024-02-26 21:21:44 +01:00
filestream << formatted;
filestream.flush();
}
else
INFO_PRINTLN( formatted );
return true;
}
std::unique_ptr<CompilerWorkspace> Compiler::build_workspace( const std::string& pathname,
Report& report )
{
Pol::Tools::HighPerfTimer timer;
CompilerWorkspaceBuilder workspace_builder( em_cache, inc_cache, profile, report );
auto workspace = workspace_builder.build( pathname, user_function_inclusion );
profile.build_workspace_micros += timer.ellapsed().count();
return workspace;
}
void Compiler::register_constants( CompilerWorkspace& workspace, Report& report )
{
Pol::Tools::HighPerfTimer timer;
SemanticAnalyzer::register_const_declarations( workspace, report );
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;
Optimizer optimizer( workspace.constants, report );
optimizer.optimize( workspace, user_function_inclusion );
2020-08-10 04:54:59 -07:00
profile.optimize_micros += timer.ellapsed().count();
}
void Compiler::disambiguate( CompilerWorkspace& workspace, Report& report )
{
Pol::Tools::HighPerfTimer timer;
Disambiguator disambiguator( workspace.constants, report );
disambiguator.disambiguate( workspace );
profile.disambiguate_micros += timer.ellapsed().count();
}
void Compiler::analyze( CompilerWorkspace& workspace, Report& report )
{
Pol::Tools::HighPerfTimer timer;
SemanticAnalyzer analyzer( workspace, report );
analyzer.analyze();
profile.analyze_micros += timer.ellapsed().count();
}
void Compiler::check_short_circuit( CompilerWorkspace& workspace, Report& report )
{
ShortCircuitWarning warn{ report };
warn.warn( workspace );
}
std::unique_ptr<CompiledScript> Compiler::generate( std::unique_ptr<CompilerWorkspace> workspace,
Report& report )
{
Pol::Tools::HighPerfTimer codegen_timer;
auto compiled_script = CodeGenerator::generate( std::move( workspace ), report,
compilercfg.GenerateAbstractSyntaxTree );
profile.codegen_micros += codegen_timer.ellapsed().count();
return compiled_script;
}
void Compiler::display_outcome( const std::string& filename, Report& report )
{
auto msg = fmt::format( "{}: {} errors", filename, report.error_count() );
if ( compilercfg.DisplayWarnings || compilercfg.ErrorOnWarning )
msg += fmt::format( ", {} warnings", report.warning_count() );
INFO_PRINTLN( msg + '.' );
}
} // namespace Pol::Bscript::Compiler