polserver/pol-core/bscript/compiler/file/SourceFile.cpp

318 lines
8.7 KiB
C++
Raw Permalink Normal View History

2020-08-14 13:54:20 -07:00
#include "SourceFile.h"
#include <cstring>
#include "clib/filecont.h"
2020-08-14 13:54:20 -07:00
#include "clib/fileutil.h"
#include "clib/strutil.h"
#include "bscript/compiler/Report.h"
#include "bscript/compiler/file/SourceFileIdentifier.h"
2020-08-14 13:54:20 -07:00
#include "compilercfg.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 <EscriptGrammar/EscriptParserVisitor.h>
2020-08-14 13:54:20 -07:00
using EscriptGrammar::EscriptLexer;
using EscriptGrammar::EscriptParser;
"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
using EscriptGrammar::EscriptParserVisitor;
2020-08-14 13:54:20 -07:00
namespace Pol::Bscript::Compiler
2020-08-14 13:54:20 -07:00
{
bool is_web_script( const char* filename );
std::string preprocess_web_script( const std::string& input );
SourceFile::SourceFile( const std::string& pathname, const std::string& contents, Profile& profile )
: pathname( pathname ),
input( contents ),
conformer( &input ),
lexer( &conformer ),
"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
token_stream( &lexer ),
parser( &token_stream ),
2020-08-14 13:54:20 -07:00
error_listener( pathname, profile ),
compilation_unit( nullptr ),
module_unit( nullptr ),
Introduce DAP Debugger (#608) * Add cppdap debugger library and simple server (#508) * Add cppdap library * Add cppdap server * fixup cmake scripts for windows * Enable caching of cppdap on GitHub actions * Fix CMake for cppdap target * Wait 1s for session close before thread ends * Address review comments - Remove unnecessary use of wait_for - Fix wait_for method * Do not use SocketClientThread for cppdap clients * Address review comments - Cleanup object ownership * Add authorization and event handling (#510) * Add authorization and event handling [WIP] * Use std::weak_ptr; Only allow one debugger conn * Only attach debugger if dbg file exists * Cleanup weak_ptr; Fix listeners; Add handler stubs * Address review comments - PolLock on uoexec and weakptr access - Use make_shared when creating client thread * Add ExecutorDebugListener on_destroy callback * Use cppdap sockets instead of clib sockets * Update cppdap repository to 2703cf4 * Implement server address binding * Update cppdap repository to eeca5ce * Fix warnings * Use weak_from_this * Fix stalled executors on disconnect * Fix stalled executors on re-attach * Clear uoexec weakptr on all debugger detaches * Move server to gamestate * move DapDebugServer into Network namespace * move DapDebugServer into GameState for storage * Move DapDebugServer into NetworkManager * Fix missing memory include * Add more events (#513) * Add more events * Implement dbg_step_out * Fix breakpoint clearing * Add even more events (#515) * add launch request * Add custom `processes` command * fixup loop * Refactoring to move handlers to member functions * Add VariablesRequest and ScopesRequest * use std::varaint for Handles * add pollocks * refactor Handles to new file * move custom messages to proto.h * move clientthread * some formatting / cleanup * Add missing PolLock * move dap variables creation to Handles * appobj members * rename ClientThread to DebugClientThread * rename LaunchRequest args to arg * Fix compiler error on size_t * Add support for EvaluateRequest and SetVariableRequest (#519) * Update grammar for evaluateUnit * Cleanup various compiler code * Add support for EvaluateRequest Only supports values, variables, element access, member access * Add report clearing to reinitialize state * Add support for SetVariableRequest * Fix CI build errors * Move ExpressionEvaluator to Bscript * Fix formatting * Fix include * Refactor global and frame variable references * Encapsulate Executor debugging environment; Fix step over (#524) * Fix step over * Some cleanup of executor - Remove unused debug states - Rename members for consistency * move debugging environment to new class * Move instruction inspection to class * Cleanup slashes on Windows; Add Executor state to processes response (#527) * Fix backspaces in script names on Windows * Fix compilation warnings with data loss * Use boost::icontains for string comparison * Add Executor state to processes response * Updates for libfmt * Fix tests; Fix cppdap build for Mac universal binary (#607) * fix tests * fix cppdap build for mac universal binary * Update cppdap to 2a4c7cf * Add tests; Modify launch behavior to not stop at entry (redo) (#609) * Remove unused setExceptionBreakpoints handler * Add debugger tests * Launching a script should not set attaching state * Add launch tests * Do not check for connection in debugger tests * Rename `program` to `script` in protocol structs * Fix launch stopAtEntry; quote string var values * Fix compilation error on Windows * Add configfiles doc entry * Various fixes for finishing touches; Add core-changes (#610) * switch cmake projects * simple docs * cmake move make_directory * Fix launch request with relative, absolute, package paths * make relative paths as absolute in source request * Add true, false, uninit to ExpressionEvaluator * Re-add setExceptionBreakpoints to avoid unhandled message errors * Better debug thread logging with instance numbers * launched scripts should terminate on disconnect (according to DAP spec) * Properly handle exited event in client thread * Add core-changes * Address Discord comments - Mention vscode-escript in core-changes - Re-add "cppdap already built" in cmake * change cmake escriptgrammarlib visibility to public
2024-01-28 15:49:55 +07:00
evaluate_unit( nullptr ),
2020-08-14 13:54:20 -07:00
access_count( 0 )
{
input.name = pathname;
lexer.removeErrorListeners();
lexer.addErrorListener( &error_listener );
parser.removeErrorListeners();
parser.addErrorListener( &error_listener );
parser.getInterpreter<antlr4::atn::ParserATNSimulator>()->setPredictionMode(
antlr4::atn::PredictionMode::SLL );
parser.setErrorHandler( std::make_shared<antlr4::BailErrorStrategy>() );
2020-08-14 13:54:20 -07:00
}
SourceFile::~SourceFile() = default;
void SourceFile::propagate_errors_to( Report& report, const SourceFileIdentifier& ident )
{
error_listener.propagate_errors_to( report, ident );
}
#if defined( _WIN32 ) || defined( __APPLE__ )
2020-08-14 13:54:20 -07:00
bool SourceFile::enforced_case_sensitivity_mismatch( const SourceLocation& referencing_location,
const std::string& pathname, Report& report )
{
std::string truename = Clib::GetTrueName( pathname.c_str() );
std::string filepart = Clib::GetFilePart( pathname.c_str() );
if ( truename != filepart && Clib::FileExists( pathname ) )
{
if ( compilercfg.ErrorOnFileCaseMissmatch )
{
report.error( referencing_location,
"Case mismatch: \n"
" Specified: {}\n"
" Filesystem: {}",
filepart, truename );
2020-08-14 13:54:20 -07:00
return true;
}
report.warning( referencing_location,
"Case mismatch: \n"
" Specified: {}\n"
" Filesystem: {}",
filepart, truename );
2020-08-14 13:54:20 -07:00
}
return false;
}
#else
bool SourceFile::enforced_case_sensitivity_mismatch( const SourceLocation&, const std::string&,
Report& )
{
return false;
}
#endif
std::shared_ptr<SourceFile> SourceFile::load( const SourceFileIdentifier& ident, Profile& profile,
Report& report )
{
const std::string& pathname = ident.pathname;
try
2020-08-14 13:54:20 -07:00
{
Clib::FileContents fc( pathname.c_str(), true );
std::string contents( fc.contents() );
Clib::sanitizeUnicodeWithIso( &contents );
2020-08-14 13:54:20 -07:00
if ( is_web_script( pathname.c_str() ) )
{
contents = preprocess_web_script( contents );
}
2020-08-14 13:54:20 -07:00
return std::make_shared<SourceFile>( pathname, contents, profile );
}
catch ( ... )
2020-08-14 13:54:20 -07:00
{
report.error( ident, "Unable to read file '{}'.", pathname );
2020-08-14 13:54:20 -07:00
return {};
}
}
EscriptGrammar::EscriptParser::CompilationUnitContext* SourceFile::get_compilation_unit(
Report& report, const SourceFileIdentifier& ident )
{
if ( !compilation_unit )
{
std::lock_guard<std::mutex> guard( mutex );
if ( !compilation_unit )
compilation_unit = two_stage_parse<EscriptGrammar::EscriptParser::CompilationUnitContext>(
[&] { return parser.compilationUnit(); } );
2020-08-14 13:54:20 -07:00
}
++access_count;
propagate_errors_to( report, ident );
return compilation_unit;
}
EscriptGrammar::EscriptParser::ModuleUnitContext* SourceFile::get_module_unit(
Report& report, const SourceFileIdentifier& ident )
{
if ( !module_unit )
{
std::lock_guard<std::mutex> guard( mutex );
if ( !module_unit )
module_unit = two_stage_parse<EscriptGrammar::EscriptParser::ModuleUnitContext>(
[&] { return parser.moduleUnit(); } );
2020-08-14 13:54:20 -07:00
}
++access_count;
propagate_errors_to( report, ident );
return module_unit;
}
EscriptGrammar::EscriptParser::EvaluateUnitContext* SourceFile::get_evaluate_unit( Report& report )
Introduce DAP Debugger (#608) * Add cppdap debugger library and simple server (#508) * Add cppdap library * Add cppdap server * fixup cmake scripts for windows * Enable caching of cppdap on GitHub actions * Fix CMake for cppdap target * Wait 1s for session close before thread ends * Address review comments - Remove unnecessary use of wait_for - Fix wait_for method * Do not use SocketClientThread for cppdap clients * Address review comments - Cleanup object ownership * Add authorization and event handling (#510) * Add authorization and event handling [WIP] * Use std::weak_ptr; Only allow one debugger conn * Only attach debugger if dbg file exists * Cleanup weak_ptr; Fix listeners; Add handler stubs * Address review comments - PolLock on uoexec and weakptr access - Use make_shared when creating client thread * Add ExecutorDebugListener on_destroy callback * Use cppdap sockets instead of clib sockets * Update cppdap repository to 2703cf4 * Implement server address binding * Update cppdap repository to eeca5ce * Fix warnings * Use weak_from_this * Fix stalled executors on disconnect * Fix stalled executors on re-attach * Clear uoexec weakptr on all debugger detaches * Move server to gamestate * move DapDebugServer into Network namespace * move DapDebugServer into GameState for storage * Move DapDebugServer into NetworkManager * Fix missing memory include * Add more events (#513) * Add more events * Implement dbg_step_out * Fix breakpoint clearing * Add even more events (#515) * add launch request * Add custom `processes` command * fixup loop * Refactoring to move handlers to member functions * Add VariablesRequest and ScopesRequest * use std::varaint for Handles * add pollocks * refactor Handles to new file * move custom messages to proto.h * move clientthread * some formatting / cleanup * Add missing PolLock * move dap variables creation to Handles * appobj members * rename ClientThread to DebugClientThread * rename LaunchRequest args to arg * Fix compiler error on size_t * Add support for EvaluateRequest and SetVariableRequest (#519) * Update grammar for evaluateUnit * Cleanup various compiler code * Add support for EvaluateRequest Only supports values, variables, element access, member access * Add report clearing to reinitialize state * Add support for SetVariableRequest * Fix CI build errors * Move ExpressionEvaluator to Bscript * Fix formatting * Fix include * Refactor global and frame variable references * Encapsulate Executor debugging environment; Fix step over (#524) * Fix step over * Some cleanup of executor - Remove unused debug states - Rename members for consistency * move debugging environment to new class * Move instruction inspection to class * Cleanup slashes on Windows; Add Executor state to processes response (#527) * Fix backspaces in script names on Windows * Fix compilation warnings with data loss * Use boost::icontains for string comparison * Add Executor state to processes response * Updates for libfmt * Fix tests; Fix cppdap build for Mac universal binary (#607) * fix tests * fix cppdap build for mac universal binary * Update cppdap to 2a4c7cf * Add tests; Modify launch behavior to not stop at entry (redo) (#609) * Remove unused setExceptionBreakpoints handler * Add debugger tests * Launching a script should not set attaching state * Add launch tests * Do not check for connection in debugger tests * Rename `program` to `script` in protocol structs * Fix launch stopAtEntry; quote string var values * Fix compilation error on Windows * Add configfiles doc entry * Various fixes for finishing touches; Add core-changes (#610) * switch cmake projects * simple docs * cmake move make_directory * Fix launch request with relative, absolute, package paths * make relative paths as absolute in source request * Add true, false, uninit to ExpressionEvaluator * Re-add setExceptionBreakpoints to avoid unhandled message errors * Better debug thread logging with instance numbers * launched scripts should terminate on disconnect (according to DAP spec) * Properly handle exited event in client thread * Add core-changes * Address Discord comments - Mention vscode-escript in core-changes - Re-add "cppdap already built" in cmake * change cmake escriptgrammarlib visibility to public
2024-01-28 15:49:55 +07:00
{
if ( !evaluate_unit )
{
std::lock_guard<std::mutex> guard( mutex );
if ( !evaluate_unit )
evaluate_unit = two_stage_parse<EscriptGrammar::EscriptParser::EvaluateUnitContext>(
[&] { return parser.evaluateUnit(); } );
Introduce DAP Debugger (#608) * Add cppdap debugger library and simple server (#508) * Add cppdap library * Add cppdap server * fixup cmake scripts for windows * Enable caching of cppdap on GitHub actions * Fix CMake for cppdap target * Wait 1s for session close before thread ends * Address review comments - Remove unnecessary use of wait_for - Fix wait_for method * Do not use SocketClientThread for cppdap clients * Address review comments - Cleanup object ownership * Add authorization and event handling (#510) * Add authorization and event handling [WIP] * Use std::weak_ptr; Only allow one debugger conn * Only attach debugger if dbg file exists * Cleanup weak_ptr; Fix listeners; Add handler stubs * Address review comments - PolLock on uoexec and weakptr access - Use make_shared when creating client thread * Add ExecutorDebugListener on_destroy callback * Use cppdap sockets instead of clib sockets * Update cppdap repository to 2703cf4 * Implement server address binding * Update cppdap repository to eeca5ce * Fix warnings * Use weak_from_this * Fix stalled executors on disconnect * Fix stalled executors on re-attach * Clear uoexec weakptr on all debugger detaches * Move server to gamestate * move DapDebugServer into Network namespace * move DapDebugServer into GameState for storage * Move DapDebugServer into NetworkManager * Fix missing memory include * Add more events (#513) * Add more events * Implement dbg_step_out * Fix breakpoint clearing * Add even more events (#515) * add launch request * Add custom `processes` command * fixup loop * Refactoring to move handlers to member functions * Add VariablesRequest and ScopesRequest * use std::varaint for Handles * add pollocks * refactor Handles to new file * move custom messages to proto.h * move clientthread * some formatting / cleanup * Add missing PolLock * move dap variables creation to Handles * appobj members * rename ClientThread to DebugClientThread * rename LaunchRequest args to arg * Fix compiler error on size_t * Add support for EvaluateRequest and SetVariableRequest (#519) * Update grammar for evaluateUnit * Cleanup various compiler code * Add support for EvaluateRequest Only supports values, variables, element access, member access * Add report clearing to reinitialize state * Add support for SetVariableRequest * Fix CI build errors * Move ExpressionEvaluator to Bscript * Fix formatting * Fix include * Refactor global and frame variable references * Encapsulate Executor debugging environment; Fix step over (#524) * Fix step over * Some cleanup of executor - Remove unused debug states - Rename members for consistency * move debugging environment to new class * Move instruction inspection to class * Cleanup slashes on Windows; Add Executor state to processes response (#527) * Fix backspaces in script names on Windows * Fix compilation warnings with data loss * Use boost::icontains for string comparison * Add Executor state to processes response * Updates for libfmt * Fix tests; Fix cppdap build for Mac universal binary (#607) * fix tests * fix cppdap build for mac universal binary * Update cppdap to 2a4c7cf * Add tests; Modify launch behavior to not stop at entry (redo) (#609) * Remove unused setExceptionBreakpoints handler * Add debugger tests * Launching a script should not set attaching state * Add launch tests * Do not check for connection in debugger tests * Rename `program` to `script` in protocol structs * Fix launch stopAtEntry; quote string var values * Fix compilation error on Windows * Add configfiles doc entry * Various fixes for finishing touches; Add core-changes (#610) * switch cmake projects * simple docs * cmake move make_directory * Fix launch request with relative, absolute, package paths * make relative paths as absolute in source request * Add true, false, uninit to ExpressionEvaluator * Re-add setExceptionBreakpoints to avoid unhandled message errors * Better debug thread logging with instance numbers * launched scripts should terminate on disconnect (according to DAP spec) * Properly handle exited event in client thread * Add core-changes * Address Discord comments - Mention vscode-escript in core-changes - Re-add "cppdap already built" in cmake * change cmake escriptgrammarlib visibility to public
2024-01-28 15:49:55 +07:00
}
++access_count;
propagate_errors_to( report, SourceFileIdentifier( 0, "<eval>" ) );
return evaluate_unit;
}
"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
std::vector<antlr4::Token*> SourceFile::get_hidden_tokens_before( const Position& position )
{
auto tokens = get_all_tokens();
size_t token_index = 0;
for ( const auto& token : tokens )
{
if ( token->getLine() == position.line_number &&
token->getCharPositionInLine() + 1 <= position.character_column &&
token->getCharPositionInLine() + 1 + token->getText().length() >=
position.character_column )
{
break;
}
token_index++;
}
if ( token_index < tokens.size() )
{
return get_hidden_tokens_before( token_index );
}
return std::vector<antlr4::Token*>();
}
std::vector<antlr4::Token*> SourceFile::get_hidden_tokens_before( size_t tokenIndex )
{
return token_stream.getHiddenTokensToLeft( tokenIndex );
}
antlr4::Token* SourceFile::get_token_at( const Position& position )
{
auto tokens = get_all_tokens();
auto result =
std::find_if( tokens.begin(), tokens.end(),
[&]( const auto& token )
{
return token->getLine() == position.line_number &&
token->getCharPositionInLine() + 1 <= position.character_column &&
token->getCharPositionInLine() + 1 + token->getText().length() >=
position.character_column;
} );
if ( result != tokens.end() )
{
return *result;
}
return nullptr;
}
std::vector<antlr4::Token*> SourceFile::get_all_tokens()
{
return token_stream.getTokens();
}
/**
* Given a file name, tells if this is a web script
*/
bool is_web_script( const char* file )
{
const char* ext = strstr( file, ".hsr" );
if ( ext && memcmp( ext, ".hsr", 5 ) == 0 )
return true;
ext = strstr( file, ".asp" );
if ( ext && memcmp( ext, ".asp", 5 ) == 0 )
return true;
return false;
}
/**
* Transforms the raw html page into a script with a single WriteHtml() instruction
*/
std::string preprocess_web_script( const std::string& input )
{
std::string output;
output = "use http;";
output += '\n';
bool reading_html = true;
bool source_is_emit = false;
const char* s = input.c_str();
std::string acc;
while ( *s )
{
if ( reading_html )
{
if ( s[0] == '<' && s[1] == '%' )
{
reading_html = false;
if ( !acc.empty() )
{
output += "WriteHtmlRaw( \"" + acc + "\");\n";
acc = "";
}
s += 2;
source_is_emit = ( s[0] == '=' );
if ( source_is_emit )
{
output += "WriteHtmlRaw( ";
++s;
}
}
else
{
if ( *s == '\"' )
acc += "\\\"";
else if ( *s == '\r' )
;
else if ( *s == '\n' )
acc += "\\n";
else
acc += *s;
++s;
}
}
else
{
if ( s[0] == '%' && s[1] == '>' )
{
reading_html = true;
s += 2;
if ( source_is_emit )
output += " );\n";
}
else
{
output += *s++;
}
}
}
if ( !acc.empty() )
output += "WriteHtmlRaw( \"" + acc + "\");\n";
return output;
}
// We do not need to switch between the BailErrorStrategy and
// DefaultErrorStrategy multiple times, as a SourceFile will only ever access
// _one_ specific unit function (`get_module_unit`, etc), which get cached once
// parsed. We try to parse with the SLL prediction mode first (set in the
// SourceFile constructor). If that fails, try the default LL parser. See
// https://github.com/antlr/antlr4/issues/374#issuecomment-30952357
template <typename T, typename Fn>
inline T* SourceFile::two_stage_parse( Fn callback )
{
try
{
// SLL set in constructor
return callback();
}
catch ( antlr4::RuntimeException& )
{
// Switch to (default) LL.
token_stream.reset();
parser.reset();
parser.getInterpreter<antlr4::atn::ParserATNSimulator>()->setPredictionMode(
antlr4::atn::PredictionMode::LL );
parser.setErrorHandler( std::make_shared<antlr4::DefaultErrorStrategy>() );
return callback();
}
}
2020-08-14 13:54:20 -07:00
} // namespace Pol::Bscript::Compiler