diff --git a/cmake/escripttest.cmake b/cmake/escripttest.cmake index 02f00357f..34f23ddb2 100644 --- a/cmake/escripttest.cmake +++ b/cmake/escripttest.cmake @@ -17,7 +17,7 @@ endif() # set(keepfailedformats TRUE) function (cleanup scriptname) - foreach (ext .ecl .tst .lst .unformatted.src .formatted.src .dbg) + foreach (ext .ecl .tst .lst .ast .unformatted.src .formatted.src .dbg) if(EXISTS "${scriptname}${ext}") if ("${ext}" STREQUAL ".formatted.src" AND DEFINED keepfailedformats) continue() @@ -95,6 +95,18 @@ endfunction() # start of test function (testwithcompiler formatoption) + # Only add -Z for ast tests + if(${subtest} MATCHES "ast") + # Currently don't have formatting for typing nodes, so ignore that subtest + # when testing formatting. + if (NOT ${formatoption} STREQUAL "") + return() + endif() + set(astoption "-Z") + else() + set(astoption "") + endif() + file(GLOB scripts RELATIVE ${testdir} ${testdir}/${subtest}/*) foreach(script ${scripts}) string(FIND "${script}" ".src" out) @@ -107,7 +119,7 @@ function (testwithcompiler formatoption) message("${script} [formatted]") string(REPLACE ".src" ".unformatted.src" unformattedscript "${script}") configure_file(${testdir}/${script} ${testdir}/${unformattedscript} COPYONLY) - execute_process( COMMAND ${ecompile} ${formatoption} -q -C ecompile.cfg ${script} + execute_process( COMMAND ${ecompile} ${formatoption} ${astoption} -q -C ecompile.cfg ${script} RESULT_VARIABLE ecompile_format_res OUTPUT_VARIABLE ecompile_format_out ERROR_VARIABLE ecompile_format_out) @@ -116,7 +128,7 @@ function (testwithcompiler formatoption) endif() if (EXISTS "${testdir}/${scriptname}.out" OR EXISTS "${testdir}/${scriptname}.err") - execute_process( COMMAND ${ecompile} -l -q -C ecompile.cfg ${script} + execute_process( COMMAND ${ecompile} ${astoption} -l -q -C ecompile.cfg ${script} RESULT_VARIABLE ecompile_res OUTPUT_VARIABLE ecompile_out ERROR_VARIABLE ecompile_out) diff --git a/docs/docs.polserver.com/pol100/configfiles.xml b/docs/docs.polserver.com/pol100/configfiles.xml index 72e514db7..c6ba75086 100644 --- a/docs/docs.polserver.com/pol100/configfiles.xml +++ b/docs/docs.polserver.com/pol100/configfiles.xml @@ -1046,6 +1046,7 @@ PackageRoot (path to package root) [GenerateListing (0/1 {default 0})] [GenerateDebugInfo (0/1 {default 0})] [GenerateDebugTextInfo (0/1 {default 0})] +[GenerateAbstractSyntaxTree (0/1 {default 0})] [DisplayWarnings (0/1 {default 0})] //same as -w flag [CompileAspPages (0/1 {default 0})] //same as -a flag [OnlyCompileUpdatedScripts (0/1 {default 0})] //same as -u flag diff --git a/docs/docs.polserver.com/pol100/corechanges.xml b/docs/docs.polserver.com/pol100/corechanges.xml index 966878bef..12cba4f03 100644 --- a/docs/docs.polserver.com/pol100/corechanges.xml +++ b/docs/docs.polserver.com/pol100/corechanges.xml @@ -2,9 +2,14 @@
Latest Core Changes - 07-10-2025 + 07-22-2025
+ + 07-22-2025 + Kevin: + ecompile switch -Z, ecompile.cfg setting GenerateAbstractSyntaxTree to write abstract syntax tree (AST) to file + 07-10-2025 Turley: diff --git a/pol-core/bscript/CMakeSources.cmake b/pol-core/bscript/CMakeSources.cmake index 37aac5cd2..5d85766ab 100644 --- a/pol-core/bscript/CMakeSources.cmake +++ b/pol-core/bscript/CMakeSources.cmake @@ -226,6 +226,8 @@ set (bscript_sources # sorted ! compiler/astbuilder/UserFunctionVisitor.h compiler/astbuilder/ValueBuilder.cpp compiler/astbuilder/ValueBuilder.h + compiler/codegen/AbstractSyntaxTreeStringGenerator.cpp + compiler/codegen/AbstractSyntaxTreeStringGenerator.h compiler/codegen/CaseDispatchGroupVisitor.cpp compiler/codegen/CaseDispatchGroupVisitor.h compiler/codegen/ClassDeclarationRegistrar.cpp diff --git a/pol-core/bscript/compiler/Compiler.cpp b/pol-core/bscript/compiler/Compiler.cpp index aab5a7b36..4358f0465 100644 --- a/pol-core/bscript/compiler/Compiler.cpp +++ b/pol-core/bscript/compiler/Compiler.cpp @@ -51,6 +51,15 @@ void Compiler::write_listing( const std::string& pathname ) } } +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 ) @@ -196,7 +205,8 @@ std::unique_ptr Compiler::generate( std::unique_ptrindex == 0 ) + _tree += parent.to_string_tree(); +} +} // namespace Pol::Bscript::Compiler \ No newline at end of file diff --git a/pol-core/bscript/compiler/codegen/AbstractSyntaxTreeStringGenerator.h b/pol-core/bscript/compiler/codegen/AbstractSyntaxTreeStringGenerator.h new file mode 100644 index 000000000..444170ace --- /dev/null +++ b/pol-core/bscript/compiler/codegen/AbstractSyntaxTreeStringGenerator.h @@ -0,0 +1,22 @@ +#pragma once + +#include "bscript/compiler/ast/NodeVisitor.h" + +#include + +namespace Pol::Bscript::Compiler +{ +class AbstractSyntaxTreeStringGenerator : public NodeVisitor +{ +public: + AbstractSyntaxTreeStringGenerator(); + + void visit_children( Node& parent ) override; + + const std::string& tree() const { return _tree; } + +private: + std::string _tree; +}; + +} // namespace Pol::Bscript::Compiler diff --git a/pol-core/bscript/compiler/codegen/CodeGenerator.cpp b/pol-core/bscript/compiler/codegen/CodeGenerator.cpp index 8dd2cf4d2..e3f64c08e 100644 --- a/pol-core/bscript/compiler/codegen/CodeGenerator.cpp +++ b/pol-core/bscript/compiler/codegen/CodeGenerator.cpp @@ -9,6 +9,7 @@ #include "bscript/compiler/ast/ProgramParameterList.h" #include "bscript/compiler/ast/TopLevelStatements.h" #include "bscript/compiler/ast/UserFunction.h" +#include "bscript/compiler/codegen/AbstractSyntaxTreeStringGenerator.h" #include "bscript/compiler/codegen/ClassDeclarationRegistrar.h" #include "bscript/compiler/codegen/FunctionReferenceRegistrar.h" #include "bscript/compiler/codegen/InstructionEmitter.h" @@ -27,7 +28,7 @@ namespace Pol::Bscript::Compiler { std::unique_ptr CodeGenerator::generate( - std::unique_ptr workspace, Report& report ) + std::unique_ptr workspace, Report& report, bool generate_ast_string ) { auto program_info = workspace->program @@ -73,11 +74,20 @@ std::unique_ptr CodeGenerator::generate( std::vector class_descriptors = class_declaration_registrar.take_descriptors(); + std::string tree; + + if ( generate_ast_string ) + { + AbstractSyntaxTreeStringGenerator ast_generator; + workspace->accept( ast_generator ); + tree = ast_generator.tree(); + } + return std::make_unique( std::move( code ), std::move( data ), std::move( debug ), std::move( exported_functions ), std::move( workspace->global_variable_names ), std::move( module_descriptors ), std::move( function_references ), std::move( class_descriptors ), std::move( program_info ), - std::move( workspace->referenced_source_file_identifiers ) ); + std::move( workspace->referenced_source_file_identifiers ), std::move( tree ) ); } CodeGenerator::CodeGenerator( InstructionEmitter& emitter, diff --git a/pol-core/bscript/compiler/codegen/CodeGenerator.h b/pol-core/bscript/compiler/codegen/CodeGenerator.h index da70d2d00..548a881e6 100644 --- a/pol-core/bscript/compiler/codegen/CodeGenerator.h +++ b/pol-core/bscript/compiler/codegen/CodeGenerator.h @@ -16,7 +16,7 @@ class CodeGenerator { public: static std::unique_ptr generate( std::unique_ptr, - Report& report ); + Report& report, bool generate_ast_string ); private: CodeGenerator( InstructionEmitter&, ModuleDeclarationRegistrar& ); diff --git a/pol-core/bscript/compiler/representation/CompiledScript.cpp b/pol-core/bscript/compiler/representation/CompiledScript.cpp index 7bfe871e3..5380e015c 100644 --- a/pol-core/bscript/compiler/representation/CompiledScript.cpp +++ b/pol-core/bscript/compiler/representation/CompiledScript.cpp @@ -12,11 +12,14 @@ namespace Pol::Bscript::Compiler { -CompiledScript::CompiledScript( - CodeSection code, DataSection data, DebugStore debug, ExportedFunctions exported_functions, - std::vector global_variable_names, ModuleDescriptors module_descriptors, - FunctionReferences function_references, ClassDescriptors class_descriptors, - std::unique_ptr program_info, SourceFileIdentifiers source_file_identifiers ) +CompiledScript::CompiledScript( CodeSection code, DataSection data, DebugStore debug, + ExportedFunctions exported_functions, + std::vector global_variable_names, + ModuleDescriptors module_descriptors, + FunctionReferences function_references, + ClassDescriptors class_descriptors, + std::unique_ptr program_info, + SourceFileIdentifiers source_file_identifiers, std::string tree ) : code( std::move( code ) ), data( std::move( data ) ), debug( std::move( debug ) ), @@ -26,7 +29,8 @@ CompiledScript::CompiledScript( function_references( std::move( function_references ) ), class_descriptors( std::move( class_descriptors ) ), program_info( std::move( program_info ) ), - source_file_identifiers( std::move( source_file_identifiers ) ) + source_file_identifiers( std::move( source_file_identifiers ) ), + tree( std::move( tree ) ) { } diff --git a/pol-core/bscript/compiler/representation/CompiledScript.h b/pol-core/bscript/compiler/representation/CompiledScript.h index c439e1f7d..235230c24 100644 --- a/pol-core/bscript/compiler/representation/CompiledScript.h +++ b/pol-core/bscript/compiler/representation/CompiledScript.h @@ -41,7 +41,7 @@ public: ExportedFunctions exported_functions, std::vector global_variable_names, ModuleDescriptors modules, FunctionReferences function_references, ClassDescriptors class_descriptors, - std::unique_ptr, SourceFileIdentifiers ); + std::unique_ptr, SourceFileIdentifiers, std::string tree ); ~CompiledScript(); CompiledScript( const CompiledScript& ) = delete; CompiledScript& operator=( const CompiledScript& ) = delete; @@ -56,6 +56,7 @@ public: const ClassDescriptors class_descriptors; const std::unique_ptr program_info; const SourceFileIdentifiers source_file_identifiers; + const std::string tree; }; } // namespace Pol::Bscript::Compiler diff --git a/pol-core/bscript/compilercfg.cpp b/pol-core/bscript/compilercfg.cpp index a429802a8..d70dc9678 100644 --- a/pol-core/bscript/compilercfg.cpp +++ b/pol-core/bscript/compilercfg.cpp @@ -46,6 +46,7 @@ void CompilerConfig::Read( const std::string& path ) GenerateListing = elem.remove_bool( "GenerateListing", false ); GenerateDebugInfo = elem.remove_bool( "GenerateDebugInfo", false ); GenerateDebugTextInfo = elem.remove_bool( "GenerateDebugTextInfo", false ); + GenerateAbstractSyntaxTree = elem.remove_bool( "GenerateAbstractSyntaxTree", false ); VerbosityLevel = elem.remove_int( "VerbosityLevel", 0 ); DisplayWarnings = elem.remove_bool( "DisplayWarnings", false ); diff --git a/pol-core/bscript/compilercfg.h b/pol-core/bscript/compilercfg.h index ba8fafc8c..e2052a054 100644 --- a/pol-core/bscript/compilercfg.h +++ b/pol-core/bscript/compilercfg.h @@ -23,6 +23,7 @@ struct CompilerConfig bool GenerateListing; bool GenerateDebugInfo; bool GenerateDebugTextInfo; + bool GenerateAbstractSyntaxTree; int VerbosityLevel; bool DisplayWarnings; bool DisplayDebugs; diff --git a/pol-core/doc/core-changes.txt b/pol-core/doc/core-changes.txt index 103a54634..e2c272142 100644 --- a/pol-core/doc/core-changes.txt +++ b/pol-core/doc/core-changes.txt @@ -1,4 +1,6 @@ -- POL100.2.0 -- +07-22-2025 Kevin: + Added: ecompile switch -Z, ecompile.cfg setting GenerateAbstractSyntaxTree to write abstract syntax tree (AST) to file 07-10-2025 Turley: Added: Compiler is now able to optimize: - more (all?) constant operations. Eg 2*2.1 is now calculated at compiletime instead of runtime. diff --git a/pol-core/ecompile/ECompileMain.cpp b/pol-core/ecompile/ECompileMain.cpp index 829c53274..62dc0dd58 100644 --- a/pol-core/ecompile/ECompileMain.cpp +++ b/pol-core/ecompile/ECompileMain.cpp @@ -66,6 +66,7 @@ void ECompileMain::showHelp() " Options: \n" " -F format filespec (print result)\n" " -Fi format filespec (inplace)\n" + " -Z generate abstract syntax tree (AST)\n" " -a compile *.asp pages also\n" " -A automatically compile scripts in main and enabled packages\n" " -Au (as '-A' but only compile updated files)\n" @@ -361,6 +362,7 @@ bool compile_file( const std::string& path ) std::string fname = path; std::string filename_ecl = fname.replace( pos, 4, ".ecl" ); std::string filename_lst = fname.replace( pos, 4, ".lst" ); + std::string filename_ast = fname.replace( pos, 4, ".ast" ); std::string filename_dep = fname.replace( pos, 4, ".dep" ); std::string filename_dbg = fname.replace( pos, 4, ".dbg" ); @@ -459,6 +461,19 @@ bool compile_file( const std::string& path ) Clib::RemoveFile( filename_lst ); } + if ( compilercfg.GenerateAbstractSyntaxTree ) + { + if ( !quiet ) + INFO_PRINTLN( "Writing: {}", filename_ast ); + compiler->write_string_tree( filename_ast ); + } + else if ( Clib::FileExists( filename_ast.c_str() ) ) + { + if ( !quiet ) + INFO_PRINTLN( "Deleting: {}", filename_ast ); + Clib::RemoveFile( filename_ast ); + } + if ( compilercfg.GenerateDebugInfo ) { if ( !quiet ) @@ -703,6 +718,10 @@ int readargs( int argc, char** argv ) compilercfg.GenerateDebugTextInfo = ( argv[i][2] == 't' ); break; + case 'Z': + compilercfg.GenerateAbstractSyntaxTree = setting_value( arg ); + break; + #ifdef WIN32 case 'P': { diff --git a/testsuite/escript/.gitignore b/testsuite/escript/.gitignore index c29392a81..7844e81f8 100644 --- a/testsuite/escript/.gitignore +++ b/testsuite/escript/.gitignore @@ -5,3 +5,4 @@ *.txt *.dep *.tst +*.ast diff --git a/testsuite/escript/ast/ast001.out b/testsuite/escript/ast/ast001.out new file mode 100644 index 000000000..d78dacdf4 --- /dev/null +++ b/testsuite/escript/ast/ast001.out @@ -0,0 +1,11 @@ +- top-level-statements + - value-consumer + - function-call(foo) +- user-function(foo) + - function-parameter-list + - user-function-body + - value-consumer + - function-call(print_astfile) + - string-value("ast001") + - return-statement + - integer-value(0) diff --git a/testsuite/escript/ast/ast001.src b/testsuite/escript/ast/ast001.src new file mode 100644 index 000000000..d37be51b7 --- /dev/null +++ b/testsuite/escript/ast/ast001.src @@ -0,0 +1,8 @@ +include "astfile"; + +function foo() + print_astfile( "ast001" ); + return 0; +endfunction + +foo(); diff --git a/testsuite/escript/ast/astfile.inc b/testsuite/escript/ast/astfile.inc new file mode 100644 index 000000000..0af5c8e74 --- /dev/null +++ b/testsuite/escript/ast/astfile.inc @@ -0,0 +1,9 @@ +use file; + +function print_astfile( test ) + var lines := ReadFile( $"./ast/{test}.ast" ); + if ( !lines ) + return print( lines ); + endif + print( "\n".join( lines ) ); +endfunction