325 lines
8.5 KiB
D
325 lines
8.5 KiB
D
/**
|
|
* Commands
|
|
*
|
|
* All command-line arguments and their impementations
|
|
*/
|
|
|
|
module commandline.commands;
|
|
|
|
import jcli;
|
|
import std.stdio;
|
|
import misc.exceptions : TError;
|
|
import std.exception : ErrnoException;
|
|
import compiler.lexer.core : Lexer, Token;
|
|
import compiler.parsing.core : Parser;
|
|
import compiler.typecheck.core : TypeChecker;
|
|
import gogga;
|
|
import compiler.core : Compiler, beginCompilation;
|
|
import compiler.configuration : ConfigEntry;
|
|
import std.conv : to;
|
|
import compiler.codegen.mapper.core : SymbolMappingTechnique;
|
|
|
|
//TODO: Re-order the definitions below so that they appear with compile first, then lex, parse, ..., help
|
|
|
|
public enum VerbosityLevel
|
|
{
|
|
info,
|
|
warning,
|
|
error,
|
|
debugg
|
|
}
|
|
|
|
// TODO: Add base command as verbosity is something we will always want to control
|
|
// TODO: Try get inheritane working as we may be able to set things then
|
|
|
|
// Stuff that all commands need
|
|
mixin template BaseCommand()
|
|
{
|
|
@ArgPositional("source file", "The source file to compile")
|
|
string sourceFile;
|
|
|
|
@ArgNamed("verbose|v", "Verbosity level")
|
|
@(ArgConfig.optional)
|
|
VerbosityLevel debugLevel;
|
|
|
|
void BaseCommandInit(Compiler compiler)
|
|
{
|
|
// Set the verbosity level
|
|
compiler.getConfig().addConfig(ConfigEntry("verbosity", debugLevel));
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Base requirements for Emit+
|
|
*/
|
|
mixin template EmitBase()
|
|
{
|
|
@ArgGroup("Emit", "Options pertaining to the code emitter")
|
|
{
|
|
@ArgNamed("symbol-mapper|sm", "The symbol mapping technique to use")
|
|
@(ArgConfig.optional)
|
|
SymbolMappingTechnique symbolTechnique;
|
|
|
|
@ArgNamed("prettygen|pg", "Generate pretty-printed code")
|
|
@(ArgConfig.optional)
|
|
bool prettyPrintCodeGen;
|
|
|
|
@ArgNamed("output|o", "Filename of generated object file")
|
|
@(ArgConfig.optional)
|
|
string outputFilename = "tlangout.c";
|
|
|
|
@ArgNamed("entrypointTest|et", "Whether or not to emit entrypoint testing code")
|
|
@(ArgConfig.optional)
|
|
bool entrypointTestEmit = true; // TODO: Change this later to `false` of course
|
|
|
|
@ArgNamed("library-link|ll", "Paths to any object files to ,ink in during the linking phase")
|
|
@(ArgConfig.optional)
|
|
@(ArgConfig.aggregate)
|
|
string[] bruh;
|
|
}
|
|
|
|
void EmitBaseInit(Compiler compiler)
|
|
{
|
|
// Set the symbol mapper technique
|
|
compiler.getConfig().addConfig(ConfigEntry("emit:mapper", symbolTechnique));
|
|
|
|
// Set whether pretty-printed code should be generated
|
|
compiler.getConfig().addConfig(ConfigEntry("dgen:pretty_code", prettyPrintCodeGen));
|
|
|
|
// Set whether or not to enable the entry point testing code
|
|
compiler.getConfig().addConfig(ConfigEntry("dgen:emit_entrypoint_test", entrypointTestEmit));
|
|
|
|
// Set the paths to the object files to link in
|
|
compiler.getConfig().addConfig(ConfigEntry("linker:link_files", bruh));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Base requirements for TypeChecker+
|
|
*/
|
|
mixin template TypeCheckerBase()
|
|
{
|
|
|
|
}
|
|
|
|
/**
|
|
* Compile the given source file from start to finish
|
|
*/
|
|
@Command("compile", "Compiles the given file(s)")
|
|
struct compileCommand
|
|
{
|
|
mixin BaseCommand!();
|
|
|
|
|
|
|
|
mixin EmitBase!();
|
|
|
|
|
|
void onExecute()
|
|
{
|
|
try
|
|
{
|
|
/* Read the source file's data */
|
|
File file;
|
|
file.open(sourceFile, "r");
|
|
ulong fSize = file.size();
|
|
byte[] data;
|
|
data.length = fSize;
|
|
data = file.rawRead(data);
|
|
string sourceText = cast(string)data;
|
|
file.close();
|
|
|
|
/* Begin lexing process */
|
|
File outFile;
|
|
outFile.open(outputFilename, "w");
|
|
Compiler compiler = new Compiler(sourceText, outFile);
|
|
|
|
/* Setup general configuration parameters */
|
|
BaseCommandInit(compiler);
|
|
|
|
/* Perform tokenization */
|
|
compiler.doLex();
|
|
writeln("=== Tokens ===\n");
|
|
writeln(compiler.getTokens());
|
|
|
|
/* Perform parsing */
|
|
compiler.doParse();
|
|
// TODO: Do something with the returned module
|
|
auto modulel = compiler.getModule();
|
|
|
|
/* Perform typechecking/codegen */
|
|
compiler.doTypeCheck();
|
|
|
|
/**
|
|
* Configure the emitter and then perform code emit
|
|
*/
|
|
EmitBaseInit(compiler);
|
|
compiler.doEmit();
|
|
}
|
|
catch(TError t)
|
|
{
|
|
gprintln(t.msg, DebugType.ERROR);
|
|
}
|
|
catch(ErrnoException e)
|
|
{
|
|
/* TODO: Use gogga error */
|
|
writeln("Could not open source file "~sourceFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Only perform tokenization of the given source files
|
|
*/
|
|
@Command("lex", "Performs tokenization of the given file(s)")
|
|
struct lexCommand
|
|
{
|
|
mixin BaseCommand!();
|
|
|
|
void onExecute()
|
|
{
|
|
writeln("Performing tokenization on file: "~sourceFile);
|
|
|
|
try
|
|
{
|
|
/* Read the source file's data */
|
|
File file;
|
|
file.open(sourceFile, "r");
|
|
ulong fSize = file.size();
|
|
byte[] data;
|
|
data.length = fSize;
|
|
data = file.rawRead(data);
|
|
string sourceText = cast(string)data;
|
|
file.close();
|
|
|
|
/* Begin lexing process */
|
|
Compiler compiler = new Compiler(sourceText, File());
|
|
|
|
/* Setup general configuration parameters */
|
|
BaseCommandInit(compiler);
|
|
|
|
|
|
compiler.doLex();
|
|
writeln("=== Tokens ===\n");
|
|
writeln(compiler.getTokens());
|
|
}
|
|
catch(TError t)
|
|
{
|
|
gprintln(t.msg, DebugType.ERROR);
|
|
}
|
|
catch(ErrnoException e)
|
|
{
|
|
/* TODO: Use gogga error */
|
|
writeln("Could not open source file "~sourceFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Command("syntaxcheck", "Check the syntax of the program")
|
|
struct parseCommand
|
|
{
|
|
mixin BaseCommand!();
|
|
|
|
|
|
/* TODO: Add missing implementation for this */
|
|
void onExecute()
|
|
{
|
|
try
|
|
{
|
|
/* Read the source file's data */
|
|
File file;
|
|
file.open(sourceFile, "r");
|
|
ulong fSize = file.size();
|
|
byte[] data;
|
|
data.length = fSize;
|
|
data = file.rawRead(data);
|
|
string sourceText = cast(string)data;
|
|
file.close();
|
|
|
|
/* Begin lexing process */
|
|
Compiler compiler = new Compiler(sourceText, File());
|
|
|
|
/* Setup general configuration parameters */
|
|
BaseCommandInit(compiler);
|
|
|
|
compiler.doLex();
|
|
writeln("=== Tokens ===\n");
|
|
writeln(compiler.getTokens());
|
|
|
|
/* Perform parsing */
|
|
compiler.doParse();
|
|
// TODO: Do something with the returned module
|
|
auto modulel = compiler.getModule();
|
|
}
|
|
catch(TError t)
|
|
{
|
|
gprintln(t.msg, DebugType.ERROR);
|
|
}
|
|
catch(ErrnoException e)
|
|
{
|
|
/* TODO: Use gogga error */
|
|
writeln("Could not open source file "~sourceFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Command("typecheck", "Perform typechecking on the program")
|
|
struct typecheckCommand
|
|
{
|
|
mixin BaseCommand!();
|
|
|
|
|
|
void onExecute()
|
|
{
|
|
try
|
|
{
|
|
/* Read the source file's data */
|
|
File file;
|
|
file.open(sourceFile, "r");
|
|
ulong fSize = file.size();
|
|
byte[] data;
|
|
data.length = fSize;
|
|
data = file.rawRead(data);
|
|
string sourceText = cast(string)data;
|
|
file.close();
|
|
|
|
/* Begin lexing process */
|
|
Compiler compiler = new Compiler(sourceText, File());
|
|
|
|
/* Setup general configuration parameters */
|
|
BaseCommandInit(compiler);
|
|
|
|
compiler.doLex();
|
|
writeln("=== Tokens ===\n");
|
|
writeln(compiler.getTokens());
|
|
|
|
/* Perform parsing */
|
|
compiler.doParse();
|
|
// TODO: Do something with the returned module
|
|
auto modulel = compiler.getModule();
|
|
|
|
/* Perform typechecking/codegen */
|
|
compiler.doTypeCheck();
|
|
}
|
|
catch(TError t)
|
|
{
|
|
gprintln(t.msg, DebugType.ERROR);
|
|
}
|
|
catch(ErrnoException e)
|
|
{
|
|
/* TODO: Use gogga error */
|
|
writeln("Could not open source file "~sourceFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Command("help", "Shows the help screen")
|
|
struct helpCommand
|
|
{
|
|
/* TODO: Add missing implementation for this */
|
|
void onExecute()
|
|
{
|
|
/* TODO: We want to show the commands list, not a seperate help command */
|
|
}
|
|
} |