A rudimentary(basic) plug-in system based on build stages doesn't require high maintenance or complex API because it's simple. For example, the compiler calls a library "
processdata(filename{string},stage{enum})" routine for each processed file like:
- processdata('/development/foo.pas',stage1); At stage 1 the addon routine reads the file and if the file content has syntaxes known that can't be understood by the FPC, those are modified(translated). It's like an external compiler mode directive but it might even translate an entire file from a different than Pascal computer language to Pascal.
- processdata('/development/foo.pas',stage2); At stage 2 the compiler already checked the syntax of the source files and arranged it according to it's own standardized code format. For example, all lines are trimmed, all those useless empty lines are removed, macros have been applied, all function calls have a single text line with parameters, a single block for each constant, type and variable declarations(for example: "procedure Foo;var x:integer;var y:integer;begin...end;" would remove the duplicate "var" keyword) and so on. Because the content of the file has been cleaned, arranged and verified for valid syntaxes, it would be easy for the plug-in to work with it. A "repeat" line will always be followed by a line that starts with "until " and ends with ";". A "for" loop line will always start with "for ". An assignment line will always contain ":=" in a greater than 1 position and will end with ";". So, it would be easier to process most of the source code.
- ...
- processdata('/development/foo.s',stageN); At stage N the compiler built the assembly files, files that have the assembly code arranged the same way as the pascal code was arranged in stage 2. Again, the plug-in will analyse the file and make changes to it. For the code presented in the first post, the compiler generates consecutive and identical "neg*" lines, which means that a plug-in can easily remove some of them, it's not rocket science.
So, the plug-in system doesn't necessary have to be something very complex. In the above example, there is a single addon(plug-in) routine that's called. Obviously, file reads and writes should be avoided, a TargetCPU parameter might be usefull, a compiler optimization level parameter might be usefull, and so on. Plug-in capabilities might be presented at compiler's request, capabilities that should appear when calling the compiler with the "
-i" series of parameters, but those are details.
To me it looks like it's not a significant effort to implement such a simple(basic, rudimentary) addon(plug-in) system mostly because it's based on compiler's build stages, not on internal routines(functions and procedures) and structures(like records) that are subject to frequent changes. And because it's based on compiler's build stages, similar results should be achievable by using compiler calling parameters. For example, FPC has the "
-s" series of parameters to stop the building process before using an assembler, but doesn't have a parameter to stop the process in an earlier stage, when the code is still in Pascal syntax. In addition, FPC doesn't have a "
restartstage" or a "
resumebuild" like parameter, forcing you to use external tools directly.
So, once FPC has a parameter to stop it's build process in a stage where the code is still in Pascal language and a parameter to resume it's building process, or restart it at a specified stage, most likely 80% of this rudimentary addon infrastructure is done.Obviously, FPC's current architecture might be so inappropriate to stopping, restarting a stage and resuming it's own building process, that would make implementing even such a stage-based rudimentary addon system a nightmare.