Compiler
All of the functionality mentioned in the past chapters describing each
stage of the compilation process and their respective components are all
combined in a Compiler
object which adds additional functionality via
the compiler configuration sub-system. This sub-system is passed into
each stage (TODO: Not yet, only the code emitter, we must fix this) such
that if a requirement for a decision to be taken based on compiler flags
is specified then such configuration paremeters can be obtained via each
module of the compilation stage.
Compiler system
The Compiler
class provides is constructed by being given source code
as a string along with a File
struct which represents the file of
which to write the final emitted code to. This type provides the
following methods:
this(string sourceCode, File emitOutFile)
- Constructs a new compiler object with the given source code and the file to write the emitted code out to
- An newly initialized
File
struct that doesn’t contain a valid file handle can be passed in in the case whereby the emitter won’t be used but an instance of the compiler is required
doLex()
- Performs the tokenization of the input source code,
sourceCode
. - A
LexerException
may be thrown if an error occurs during the toeknization process.
- Performs the tokenization of the input source code,
getTokens()
- Returns the tokens produced by a call to
doLex()
- A
CompilerException
will be thrown if called withoutdoLex()
having been called.
- Returns the tokens produced by a call to
doParse()
- Peforms parsing on the tokens and returns the generated
super-container parse node,
Module
. - A
CompilerException
will be thrown if called withoutdoLex()
having been called. - A
CompilerException
will be thrown if called without and no tokens were produced by the call todoLex()
.
- Peforms parsing on the tokens and returns the generated
super-container parse node,
doTypeCheck()
- Performs typechecking and code generation.
- A
CompilerException
will be thrown is the previous stages, includingdoParse()
and its requirements, have not been called.
doEmit()
- Performs emitting of C code
- A
CompilerException
will be thrown is the previous stages, includingdoTypeCheck()
and its requirements, have not been called.
compile()
- Performs all of the above stages.
- A
CompilerException
can be thrown for any of the aforementioned reasons.
TODO: Document CompilerException
exception and CompilerError
enum.
Configuration sub-system
At user-request or due to constraints of the host machine it may be
required that certain aspects of the various components of the compiler
be modified in terms of their behaviour. This is where the compiler
configuration sub-system comes in in order to support a key-value store
that can be used via the compiler.config
field at any time.
The CompilerConfiguration
API
The CompilerConfiguration
exposes the following API:
bool hasConfig(string key)
- Checks if the given
key
exists in the key-value store, returnsfalse
if not,true
otherwise
- Checks if the given
addConfig(ConfigEntry entry)
- Stores the given entry in the cnfiguration store
- Throws a
CompilerException
if you are trying to update an entry to a different tye than the existing one
ConfigEntry getConfig(string key)
- Returns the
ConfigEntry
at the provided name - Throws a
CompilerException
if no such entry exists
- Returns the
CompilerConfiguration defaultConfig()
- Returns the default compiler configuration (TODO: link to it)
The ConfigEntry
API
The ConfigEntry
represents a configuration entry, this is composed of:
- An entry name
- Fetched via
string getName()
- Fetched via
- An entry type
- This is fetched via
ConfigType getType()
- This is fetched via
- An entry value
- This is fetched via
getX()
- There are several getter functions which will interpret the
union space dependent on which one you call, however, in reality
a misinterpretation will cause a runtime error as we catch it
before you attempt to do a reinterpattion of it, therefore
throwing a
CompilerException
- This is fetched via
The types that can be stored and their respectives methods are:
- Boolean
- Values:
true
orfalse
- Use
getBoolean()
- Values:
- Number
- Values: A valid D
ulong
- Use
getNumber()
- Values: A valid D
- Text
- Values: A D
string
- Use
getText()
- Values: A D
- Tex array
- Values: A D
string[]
- Use
getArray()
- Values: A D
Example usage
Creation of entries
Below is an example of the usage of the ConfigEntry
s in the
CompilerConfiguration
system, here we add a few entries:
/* Enable Behaviour-C fixes */
config.addConfig(ConfigEntry("behavec:preinline_args", true));
/* Enable pretty code generation for DGen */
config.addConfig(ConfigEntry("dgen:pretty_code", true));
/* Enable entry point test generation for DGen */
config.addConfig(ConfigEntry("dgen:emit_entrypoint_test", true));
/* Set the mapping to hashing of entity names (TODO: This should be changed before release) */
config.addConfig(ConfigEntry("emit:mapper", "hashmapper"));
Retrieval of entries
Later on we can retrieve these entries, the below is code from the
DGen
class which emits the C code), here we check for any object files
that should be linked in:
//NOTE: Change to system compiler (maybe, we need to choose a good C compiler)
string[] compileArgs = ["clang", "-o", "tlang.out", file.name()];
// Check for object files to be linked in
string[] objectFilesLink;
if(config.hasConfig("linker:link_files"))
{
objectFilesLink = config.getConfig("linker:link_files").getArray();
gprintln("Object files to be linked in: "~to!(string)(objectFilesLink));
}
else
{
gprintln("No files to link in");
}
Pid ccPID = spawnProcess(compileArgs~objectFilesLink);