mirror of https://github.com/tbklang/tlang.git
App
- Added newline to release info print - Fixed module docstring Commands - Added new command-line options: `syntaxcheck`, `typecheck` - Added todo to `help` command - Re-ordered commands for order of appearance in help text Compiler - Added docstring to `beginCompilation(string[])` function Mapper - Added debug print of the Container being used for the symbol lookup CodeEmitter - Re-worked CodeEmitter class to use a single so-called "selected queue" - Added methods to move back and forth between said "selected queue", get the length, etc. - Remove old queue-specific methods DGen - Use the new CodeEmitter "selected-queue" functionality - Emit function definitions now supported Exceptions - Added this keyword Check - Added support for SymbolTYpe.OCURLY and SymbolType.CCURLY to `getCharacter(SymbolType)` Data - Added a `hasParams()` method to the Function entity type TypeChecker - Added support for emitting function definitions (required DNode.poes = [] (cleaning), codeQueue cleaning etc.) - Added `getInitQueue()` method to make a copy of the current "scratchpad" `codeQueue` - Build up a copy of the global queue now (make a copy similiar to what we did for `getInitQueue()` but inline) - Added a debug print Dependency - Added a FIXME note for issue #46 - Added a TODO relating to `static DNode[] poes` Test cases - Added test case `simple_function_decls.t` to test function definition code emit - Updated test case `simple_variables.t` to note that the T code generates invalid C code README - Build instructions now generate coverage files (`.lst`s) - Updated link to documentation
This commit is contained in:
parent
f17d38b74e
commit
8a481fb0ac
|
@ -3,16 +3,16 @@ tlang
|
||||||
|
|
||||||
Official Tristan Language project compiler
|
Official Tristan Language project compiler
|
||||||
|
|
||||||
## Docs
|
## Documentation
|
||||||
|
|
||||||
Docs are available [here](http://deavmi.assigned.network/secret/tlang).
|
Docs are available [here](http://deavmi.assigned.network/projects/tlang/).
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
To build you will need `dmd` and `dub` installed. You can then run the following:
|
To build you will need `dmd` and `dub` installed. You can then run the following:
|
||||||
|
|
||||||
```
|
```
|
||||||
dub test
|
dub test --coverage
|
||||||
dub build
|
dub build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
/**
|
/**
|
||||||
* Tristan's programming language
|
* TLP reference compiler
|
||||||
*
|
*
|
||||||
* This is TOP SECRET code, not for RELEASE!
|
* This is the entry point for the TLP
|
||||||
* Violators WILL BE PUT UP AGAINST A WALL AND
|
* reference compiler.
|
||||||
* SHOT!
|
*/
|
||||||
*/
|
|
||||||
|
|
||||||
module tlang;
|
module tlang;
|
||||||
|
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
|
@ -14,7 +12,7 @@ import commandline.args;
|
||||||
void main(string[] args)
|
void main(string[] args)
|
||||||
{
|
{
|
||||||
/* TODO: Replace with something else */
|
/* TODO: Replace with something else */
|
||||||
writeln("tlang NO_PUBLISH_RELEASE");
|
writeln("tlang NO_PUBLISH_RELEASE\n");
|
||||||
|
|
||||||
/* Parse the command-line arguments */
|
/* Parse the command-line arguments */
|
||||||
parseCommandLine(args);
|
parseCommandLine(args);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* Commands
|
* Commands
|
||||||
*
|
*
|
||||||
* All command-line arguments and their impementations
|
* All command-line arguments and their impementations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module commandline.commands;
|
module commandline.commands;
|
||||||
|
|
||||||
|
@ -10,19 +10,11 @@ import jcli;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import compiler.compiler : beginCompilation;
|
import compiler.compiler : beginCompilation;
|
||||||
import std.exception : ErrnoException;
|
import std.exception : ErrnoException;
|
||||||
import compiler.lexer : Lexer;
|
import compiler.lexer : Lexer, Token;
|
||||||
|
import compiler.parsing.core : Parser;
|
||||||
|
import compiler.typecheck.core : TypeChecker;
|
||||||
|
|
||||||
// import jcli.cli;
|
//TODO: Re-order the definitions below so that they appear with compile first, then lex, parse, ..., help
|
||||||
|
|
||||||
@Command("help", "Shows the help screen")
|
|
||||||
struct helpCommand
|
|
||||||
{
|
|
||||||
/* TODO: Add missing implementation for this */
|
|
||||||
void onExecute()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile the given source file from start to finish
|
* Compile the given source file from start to finish
|
||||||
|
@ -40,11 +32,6 @@ struct compileCommand
|
||||||
void onExecute()
|
void onExecute()
|
||||||
{
|
{
|
||||||
writeln("Compiling source file: "~sourceFile);
|
writeln("Compiling source file: "~sourceFile);
|
||||||
|
|
||||||
/* TODO: Read file */
|
|
||||||
string sourceCode = "";
|
|
||||||
|
|
||||||
|
|
||||||
beginCompilation([sourceFile]);
|
beginCompilation([sourceFile]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,7 +42,7 @@ struct compileCommand
|
||||||
@Command("lex", "Performs tokenization of the given file(s)")
|
@Command("lex", "Performs tokenization of the given file(s)")
|
||||||
struct lexCommand
|
struct lexCommand
|
||||||
{
|
{
|
||||||
@ArgPositional("source file", "The source file to compile")
|
@ArgPositional("source file", "The source file to lex")
|
||||||
string sourceFile;
|
string sourceFile;
|
||||||
|
|
||||||
void onExecute()
|
void onExecute()
|
||||||
|
@ -72,6 +59,7 @@ struct lexCommand
|
||||||
data.length = fSize;
|
data.length = fSize;
|
||||||
data = file.rawRead(data);
|
data = file.rawRead(data);
|
||||||
string sourceText = cast(string)data;
|
string sourceText = cast(string)data;
|
||||||
|
file.close();
|
||||||
|
|
||||||
/* Begin lexing process */
|
/* Begin lexing process */
|
||||||
Lexer lexer = new Lexer(sourceText);
|
Lexer lexer = new Lexer(sourceText);
|
||||||
|
@ -92,4 +80,175 @@ struct lexCommand
|
||||||
writeln("Could not open source file "~sourceFile);
|
writeln("Could not open source file "~sourceFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command("syntaxcheck", "Check the syntax of the program")
|
||||||
|
struct parseCommand
|
||||||
|
{
|
||||||
|
@ArgPositional("source file", "The source file to check syntax of")
|
||||||
|
string sourceFile;
|
||||||
|
|
||||||
|
/* TODO: Add missing implementation for this */
|
||||||
|
void onExecute()
|
||||||
|
{
|
||||||
|
// TODO: Add call to typechecker here
|
||||||
|
|
||||||
|
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 */
|
||||||
|
Lexer lexer = new Lexer(sourceText);
|
||||||
|
if(lexer.performLex())
|
||||||
|
{
|
||||||
|
Token[] tokens = lexer.getTokens();
|
||||||
|
writeln("=== Tokens ===\n");
|
||||||
|
writeln(tokens);
|
||||||
|
|
||||||
|
// TODO: Catch exception
|
||||||
|
Parser parser = new Parser(tokens);
|
||||||
|
// TODO: Do something with the returned module
|
||||||
|
auto modulel = parser.parse();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* TODO: Is the lexer.performLex() return value used? */
|
||||||
|
writeln("There was an error whilst performing tokenization");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(ErrnoException e)
|
||||||
|
{
|
||||||
|
/* TODO: Use gogga error */
|
||||||
|
writeln("Could not open source file "~sourceFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command("typecheck", "Perform typechecking on the program")
|
||||||
|
struct typecheckCommand
|
||||||
|
{
|
||||||
|
@ArgPositional("source file", "The source file to typecheck")
|
||||||
|
string sourceFile;
|
||||||
|
|
||||||
|
/* TODO: Add missing implementation for this */
|
||||||
|
void onExecute()
|
||||||
|
{
|
||||||
|
// TODO: Add call to typechecker here
|
||||||
|
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 */
|
||||||
|
Lexer lexer = new Lexer(sourceText);
|
||||||
|
if(lexer.performLex())
|
||||||
|
{
|
||||||
|
Token[] tokens = lexer.getTokens();
|
||||||
|
writeln("=== Tokens ===\n");
|
||||||
|
writeln(tokens);
|
||||||
|
|
||||||
|
// TODO: Catch exception
|
||||||
|
Parser parser = new Parser(tokens);
|
||||||
|
// TODO: Do something with the returned module
|
||||||
|
auto modulel = parser.parse();
|
||||||
|
|
||||||
|
//TODO: collect results here
|
||||||
|
//TODO: catch exceptions
|
||||||
|
TypeChecker typeChecker = new TypeChecker(modulel);
|
||||||
|
typeChecker.beginCheck();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* TODO: Is the lexer.performLex() return value used? */
|
||||||
|
writeln("There was an error whilst performing tokenization");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(ErrnoException e)
|
||||||
|
{
|
||||||
|
/* TODO: Use gogga error */
|
||||||
|
writeln("Could not open source file "~sourceFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Command("emit", "Perform emitting on the program")
|
||||||
|
// struct emitCommand
|
||||||
|
// {
|
||||||
|
// @ArgPositional("source file", "The source file to emit")
|
||||||
|
// string sourceFile;
|
||||||
|
|
||||||
|
// /* TODO: Add missing implementation for this */
|
||||||
|
// void onExecute()
|
||||||
|
// {
|
||||||
|
// // TODO: Add call to typechecker here
|
||||||
|
// 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 */
|
||||||
|
// Lexer lexer = new Lexer(sourceText);
|
||||||
|
// if(lexer.performLex())
|
||||||
|
// {
|
||||||
|
// Token[] tokens = lexer.getTokens();
|
||||||
|
// writeln("=== Tokens ===\n");
|
||||||
|
// writeln(tokens);
|
||||||
|
|
||||||
|
// // TODO: Catch exception
|
||||||
|
// Parser parser = new Parser(tokens);
|
||||||
|
// // TODO: Do something with the returned module
|
||||||
|
// auto modulel = parser.parse();
|
||||||
|
|
||||||
|
// //TODO: collect results here
|
||||||
|
// //TODO: catch exceptions
|
||||||
|
// TypeChecker typeChecker = new TypeChecker(modulel);
|
||||||
|
// typeChecker.beginCheck();
|
||||||
|
|
||||||
|
// //TODO: emit is basically full cpmpile or nah? we should write emit to stdout actually
|
||||||
|
// //or nah?
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// /* TODO: Is the lexer.performLex() return value used? */
|
||||||
|
// writeln("There was an error whilst performing tokenization");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// 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 */
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -8,6 +8,8 @@ import std.stdio;
|
||||||
import std.file;
|
import std.file;
|
||||||
import compiler.codegen.instruction : Instruction;
|
import compiler.codegen.instruction : Instruction;
|
||||||
import std.range : walkLength;
|
import std.range : walkLength;
|
||||||
|
import gogga;
|
||||||
|
import std.conv : to;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Perhaps have an interface that can emit(Context/Parent, Statement)
|
* TODO: Perhaps have an interface that can emit(Context/Parent, Statement)
|
||||||
|
@ -19,65 +21,157 @@ public abstract class CodeEmitter
|
||||||
{
|
{
|
||||||
protected TypeChecker typeChecker;
|
protected TypeChecker typeChecker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The selected queue is the queue to be used
|
||||||
|
* when using the cursor instructions such as
|
||||||
|
* `nextInstruction()`, `previousInstruction()`
|
||||||
|
* etc.
|
||||||
|
*/
|
||||||
|
private Instruction[] selectedQueue;
|
||||||
|
|
||||||
|
public enum QueueType
|
||||||
|
{
|
||||||
|
ALLOC_QUEUE,
|
||||||
|
GLOBALS_QUEUE,
|
||||||
|
FUNCTION_DEF_QUEUE
|
||||||
|
}
|
||||||
|
|
||||||
|
private ulong queueCursor = 0;
|
||||||
|
|
||||||
|
public final void selectQueue(QueueType queueType, string funcDefName = "")
|
||||||
|
{
|
||||||
|
// Move the cursor back to the starting position
|
||||||
|
resetCursor();
|
||||||
|
|
||||||
|
if(queueType == QueueType.ALLOC_QUEUE)
|
||||||
|
{
|
||||||
|
selectedQueue = initQueue;
|
||||||
|
}
|
||||||
|
else if(queueType == QueueType.GLOBALS_QUEUE)
|
||||||
|
{
|
||||||
|
selectedQueue = globalCodeQueue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//TODO: Ensure valid name by lookup via tc
|
||||||
|
|
||||||
|
selectedQueue = functionBodyInstrs[funcDefName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void resetCursor()
|
||||||
|
{
|
||||||
|
queueCursor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void nextInstruction()
|
||||||
|
{
|
||||||
|
// TODO: Sanity check on length
|
||||||
|
|
||||||
|
queueCursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void previousInstruction()
|
||||||
|
{
|
||||||
|
// TODO: Sanity check on lenght
|
||||||
|
|
||||||
|
queueCursor--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final bool hasInstructions()
|
||||||
|
{
|
||||||
|
return queueCursor < selectedQueue.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Instruction getCurrentInstruction()
|
||||||
|
{
|
||||||
|
return selectedQueue[queueCursor];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required queues
|
* Required queues
|
||||||
*/
|
*/
|
||||||
private Instruction[] initQueue;
|
private Instruction[] initQueue;
|
||||||
private Instruction[] codeQueue;
|
private Instruction[] globalCodeQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Required queues (maps to them)
|
||||||
|
*/
|
||||||
|
private Instruction[][string] functionBodyInstrs;
|
||||||
|
|
||||||
// alias instructions = codeQueue;
|
|
||||||
|
|
||||||
protected File file;
|
protected File file;
|
||||||
|
|
||||||
|
public final ulong getQueueLength()
|
||||||
private ulong codeQueueIdx = 0;
|
|
||||||
|
|
||||||
|
|
||||||
public final Instruction getCurrentCodeInstruction()
|
|
||||||
{
|
{
|
||||||
return codeQueue[codeQueueIdx];
|
return selectedQueue.length;
|
||||||
}
|
|
||||||
|
|
||||||
public final bool hasCodeInstructions()
|
|
||||||
{
|
|
||||||
return codeQueueIdx < codeQueue.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void nextCodeInstruction()
|
|
||||||
{
|
|
||||||
codeQueueIdx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void previousCodeInstruction()
|
|
||||||
{
|
|
||||||
codeQueueIdx--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public final ulong getInitQueueLen()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public final string[] getFunctionDefinitionNames()
|
||||||
{
|
{
|
||||||
return initQueue.length;
|
return functionBodyInstrs.keys();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final ulong getCodeQueueLen()
|
/**
|
||||||
|
* TODO: Make some sort of like cursor object here that lets you move for function
|
||||||
|
* or actually just have a function cuirsor
|
||||||
|
*/
|
||||||
|
private ulong globalCurrentFunctionDefintionCodeQueueIdx = 0;
|
||||||
|
private string currentFunctionDefinitionName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves thr cursor (for the CFDCQ) back to the starting
|
||||||
|
* position (zero)
|
||||||
|
*/
|
||||||
|
public final void resetCFDCQCursor()
|
||||||
{
|
{
|
||||||
return codeQueue.length;
|
globalCurrentFunctionDefintionCodeQueueIdx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final bool hasFunctionDefinitionInstructions()
|
||||||
|
{
|
||||||
|
return globalCurrentFunctionDefintionCodeQueueIdx < functionBodyInstrs[currentFunctionDefinitionName].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void nextFunctionDefinitionCode()
|
||||||
|
{
|
||||||
|
globalCurrentFunctionDefintionCodeQueueIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void previousFunctionDefinitionCode()
|
||||||
|
{
|
||||||
|
globalCurrentFunctionDefintionCodeQueueIdx--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Instruction getCurrentFunctionDefinitionInstruction()
|
||||||
|
{
|
||||||
|
return functionBodyInstrs[currentFunctionDefinitionName][globalCurrentFunctionDefintionCodeQueueIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setCurrentFunctionDefinition(string functionDefinitionName)
|
||||||
|
{
|
||||||
|
currentFunctionDefinitionName = functionDefinitionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
this(TypeChecker typeChecker, File file)
|
this(TypeChecker typeChecker, File file)
|
||||||
{
|
{
|
||||||
this.typeChecker = typeChecker;
|
this.typeChecker = typeChecker;
|
||||||
|
|
||||||
/* Extract the allocation queue, the code queue */
|
/* Extract the allocation queue, the code queue */
|
||||||
foreach(Instruction currentInstruction; typeChecker.getInitQueue())
|
initQueue = typeChecker.getInitQueue();
|
||||||
{
|
globalCodeQueue = typeChecker.getGlobalCodeQueue();
|
||||||
initQueue~=currentInstruction;
|
|
||||||
}
|
/* Extract the function definitions string-queue mapping */
|
||||||
foreach(Instruction currentInstruction; typeChecker.getCodeQueue())
|
functionBodyInstrs = typeChecker.getFunctionBodyCodeQueues();
|
||||||
{
|
gprintln("CodeEmitter: Got number of function defs: "~to!(string)(functionBodyInstrs));
|
||||||
codeQueue~=currentInstruction;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.file = file;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,17 +12,14 @@ import gogga;
|
||||||
import std.range : walkLength;
|
import std.range : walkLength;
|
||||||
import std.string : wrap;
|
import std.string : wrap;
|
||||||
import std.process : spawnProcess, Pid, ProcessException, wait;
|
import std.process : spawnProcess, Pid, ProcessException, wait;
|
||||||
import compiler.typecheck.dependency.core : Context;
|
import compiler.typecheck.dependency.core : Context, FunctionData, DNode;
|
||||||
import compiler.codegen.mapper : SymbolMapper;
|
import compiler.codegen.mapper : SymbolMapper;
|
||||||
import compiler.symbols.data : SymbolType, Variable;
|
import compiler.symbols.data : SymbolType, Variable, Function;
|
||||||
import compiler.symbols.check : getCharacter;
|
import compiler.symbols.check : getCharacter;
|
||||||
import misc.utils : Stack;
|
import misc.utils : Stack;
|
||||||
|
|
||||||
public final class DCodeEmitter : CodeEmitter
|
public final class DCodeEmitter : CodeEmitter
|
||||||
{
|
{
|
||||||
private Stack!(Instruction) varAssStack;
|
|
||||||
|
|
||||||
|
|
||||||
// Set to true when processing a variable declaration
|
// Set to true when processing a variable declaration
|
||||||
// which expects an assignment. Set to false when
|
// which expects an assignment. Set to false when
|
||||||
// said variable assignment has been processed
|
// said variable assignment has been processed
|
||||||
|
@ -32,12 +29,12 @@ public final class DCodeEmitter : CodeEmitter
|
||||||
this(TypeChecker typeChecker, File file)
|
this(TypeChecker typeChecker, File file)
|
||||||
{
|
{
|
||||||
super(typeChecker, file);
|
super(typeChecker, file);
|
||||||
|
|
||||||
varAssStack = new Stack!(Instruction)();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string transform(const Instruction instruction)
|
public override string transform(const Instruction instruction)
|
||||||
{
|
{
|
||||||
|
gprintln("transform(): "~to!(string)(instruction));
|
||||||
|
|
||||||
/* VariableAssignmentInstr */
|
/* VariableAssignmentInstr */
|
||||||
if(cast(VariableAssignmentInstr)instruction)
|
if(cast(VariableAssignmentInstr)instruction)
|
||||||
{
|
{
|
||||||
|
@ -92,8 +89,8 @@ public final class DCodeEmitter : CodeEmitter
|
||||||
varDecWantsConsumeVarAss = true;
|
varDecWantsConsumeVarAss = true;
|
||||||
|
|
||||||
// Fetch the variable assignment instruction
|
// Fetch the variable assignment instruction
|
||||||
nextCodeInstruction();
|
nextInstruction();
|
||||||
Instruction varAssInstr = getCurrentCodeInstruction();
|
Instruction varAssInstr = getCurrentInstruction();
|
||||||
|
|
||||||
// Generate the code to emit
|
// Generate the code to emit
|
||||||
return varDecInstr.varType~" "~renamedSymbol~" = "~transform(varAssInstr)~";";
|
return varDecInstr.varType~" "~renamedSymbol~" = "~transform(varAssInstr)~";";
|
||||||
|
@ -140,12 +137,17 @@ public final class DCodeEmitter : CodeEmitter
|
||||||
// Emit header comment (NOTE: Change this to a useful piece of text)
|
// Emit header comment (NOTE: Change this to a useful piece of text)
|
||||||
emitHeaderComment("Place any extra information by code generator here"); // NOTE: We can pass a string with extra information to it if we want to
|
emitHeaderComment("Place any extra information by code generator here"); // NOTE: We can pass a string with extra information to it if we want to
|
||||||
|
|
||||||
gprintln("Static allocations needed: "~to!(string)(getInitQueueLen()));
|
|
||||||
emitStaticAllocations();
|
emitStaticAllocations();
|
||||||
|
|
||||||
gprintln("Code emittings needed: "~to!(string)(getCodeQueueLen()));
|
gprintln("Function definitions needed: "~to!(string)(1)); //TODO: fix counter here
|
||||||
|
emitFunctionDefinitions();
|
||||||
|
|
||||||
|
gprintln("\n\n\n");
|
||||||
|
|
||||||
emitCodeQueue();
|
emitCodeQueue();
|
||||||
|
|
||||||
|
gprintln("\n\n\n");
|
||||||
|
|
||||||
//TODO: Emit function definitions
|
//TODO: Emit function definitions
|
||||||
|
|
||||||
//TODO: Emit main (entry point)
|
//TODO: Emit main (entry point)
|
||||||
|
@ -190,17 +192,109 @@ public final class DCodeEmitter : CodeEmitter
|
||||||
*/
|
*/
|
||||||
private void emitStaticAllocations()
|
private void emitStaticAllocations()
|
||||||
{
|
{
|
||||||
|
selectQueue(QueueType.ALLOC_QUEUE);
|
||||||
|
gprintln("Static allocations needed: "~to!(string)(getQueueLength()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TOOD: We should have an nextInstruction() esque thing for this
|
||||||
|
*/
|
||||||
|
private void emitFunctionDefinitions()
|
||||||
|
{
|
||||||
|
Instruction[][string] functionBodyInstrs = typeChecker.getFunctionBodyCodeQueues();
|
||||||
|
|
||||||
|
string[] functionNames = getFunctionDefinitionNames();
|
||||||
|
|
||||||
|
gprintln("WOAH: "~to!(string)(functionNames));
|
||||||
|
|
||||||
|
foreach(string currentFunctioName; functionNames)
|
||||||
|
{
|
||||||
|
emitFunctionDefinition(currentFunctioName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private string generateSignature(Function func)
|
||||||
|
{
|
||||||
|
string signature;
|
||||||
|
|
||||||
|
// <type> <functionName> (
|
||||||
|
signature = func.getType()~" "~func.getName()~"(";
|
||||||
|
|
||||||
|
// Generate parameter list
|
||||||
|
if(func.hasParams())
|
||||||
|
{
|
||||||
|
Variable[] parameters = func.getParams();
|
||||||
|
string parameterString;
|
||||||
|
|
||||||
|
for(ulong parIdx = 0; parIdx < parameters.length; parIdx++)
|
||||||
|
{
|
||||||
|
Variable currentParameter = parameters[parIdx];
|
||||||
|
parameterString~=currentParameter.getType()~" "~currentParameter.getName();
|
||||||
|
|
||||||
|
if(parIdx != (parameters.length-1))
|
||||||
|
{
|
||||||
|
parameterString~=", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signature~=parameterString;
|
||||||
|
}
|
||||||
|
|
||||||
|
// )
|
||||||
|
signature~=")";
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void emitFunctionDefinition(string functionName)
|
||||||
|
{
|
||||||
|
// // Reset the cursor
|
||||||
|
// resetCFDCQCursor();
|
||||||
|
|
||||||
|
// // Set the function we want to examine in CodeEmitter
|
||||||
|
// setCurrentFunctionDefinition(functionName);
|
||||||
|
selectQueue(QueueType.FUNCTION_DEF_QUEUE, functionName);
|
||||||
|
|
||||||
|
//TODO: Look at nested definitions or nah? (Context!!)
|
||||||
|
//TODO: And what about methods defined in classes? Those should technically be here too
|
||||||
|
Function functionEntity = cast(Function)typeChecker.getResolver().resolveBest(typeChecker.getModule(), functionName); //TODO: Remove `auto`
|
||||||
|
|
||||||
|
// Emit the function signature
|
||||||
|
file.writeln(generateSignature(functionEntity));
|
||||||
|
|
||||||
|
// Emit opening curly brace
|
||||||
|
file.writeln(getCharacter(SymbolType.OCURLY));
|
||||||
|
|
||||||
|
// Emit body
|
||||||
|
while(hasInstructions())
|
||||||
|
{
|
||||||
|
Instruction curFuncBodyInstr = getCurrentInstruction();
|
||||||
|
|
||||||
|
string emit = transform(curFuncBodyInstr);
|
||||||
|
gprintln("emitFunctionDefinition("~functionName~"): Emit: "~emit);
|
||||||
|
file.writeln("\t"~emit);
|
||||||
|
|
||||||
|
nextInstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit closing curly brace
|
||||||
|
file.writeln(getCharacter(SymbolType.CCURLY));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void emitCodeQueue()
|
private void emitCodeQueue()
|
||||||
{
|
{
|
||||||
while(hasCodeInstructions())
|
selectQueue(QueueType.GLOBALS_QUEUE);
|
||||||
|
gprintln("Code emittings needed: "~to!(string)(getQueueLength()));
|
||||||
|
|
||||||
|
while(hasInstructions())
|
||||||
{
|
{
|
||||||
Instruction currentInstruction = getCurrentCodeInstruction();
|
Instruction currentInstruction = getCurrentInstruction();
|
||||||
file.writeln(transform(currentInstruction));
|
file.writeln(transform(currentInstruction));
|
||||||
|
|
||||||
nextCodeInstruction();
|
nextInstruction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@ module compiler.codegen.mapper;
|
||||||
|
|
||||||
import compiler.typecheck.core;
|
import compiler.typecheck.core;
|
||||||
import compiler.symbols.data;
|
import compiler.symbols.data;
|
||||||
|
import std.conv : to;
|
||||||
|
import gogga;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SymbolMapper
|
* SymbolMapper
|
||||||
|
@ -28,6 +30,8 @@ public final class SymbolMapper
|
||||||
auto entity = tc.getResolver().resolveBest(container, entityNameIn); //TODO: Remove `auto`
|
auto entity = tc.getResolver().resolveBest(container, entityNameIn); //TODO: Remove `auto`
|
||||||
string entityNameAbsolute = tc.getResolver().generateName(tc.getModule(), entity);
|
string entityNameAbsolute = tc.getResolver().generateName(tc.getModule(), entity);
|
||||||
|
|
||||||
|
gprintln("symbolLookup(): "~to!(string)(container));
|
||||||
|
|
||||||
// Hash the absolute path name
|
// Hash the absolute path name
|
||||||
// FIXME: Ensure these hashes are unique (use the smbyol table!)
|
// FIXME: Ensure these hashes are unique (use the smbyol table!)
|
||||||
import std.digest : toHexString, LetterCase;
|
import std.digest : toHexString, LetterCase;
|
||||||
|
|
|
@ -13,6 +13,12 @@ import core.stdc.stdlib;
|
||||||
import compiler.codegen.emit.core;
|
import compiler.codegen.emit.core;
|
||||||
import compiler.codegen.emit.dgen;
|
import compiler.codegen.emit.dgen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs compilation of the provided module(s)
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* sourceFiles = The module(s) to perform compilation with
|
||||||
|
*/
|
||||||
void beginCompilation(string[] sourceFiles)
|
void beginCompilation(string[] sourceFiles)
|
||||||
{
|
{
|
||||||
/* TODO: Begin compilation process, take in data here */
|
/* TODO: Begin compilation process, take in data here */
|
||||||
|
|
|
@ -17,8 +17,6 @@ public class ParserException : TError
|
||||||
super(message);
|
super(message);
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class SyntaxError : ParserException
|
public final class SyntaxError : ParserException
|
||||||
|
@ -30,7 +28,7 @@ public final class SyntaxError : ParserException
|
||||||
this(Parser parser, SymbolType expected, Token providedToken)
|
this(Parser parser, SymbolType expected, Token providedToken)
|
||||||
{
|
{
|
||||||
this.expected = expected;
|
this.expected = expected;
|
||||||
provided = getSymbolType(providedToken);
|
this.provided = getSymbolType(providedToken);
|
||||||
this.providedToken = providedToken;
|
this.providedToken = providedToken;
|
||||||
|
|
||||||
super(parser, "Syntax error: Expected "~to!(string)(expected)~" but got "~to!(string)(provided)~", see "~providedToken.toString());
|
super(parser, "Syntax error: Expected "~to!(string)(expected)~" but got "~to!(string)(provided)~", see "~providedToken.toString());
|
||||||
|
|
|
@ -482,6 +482,14 @@ public string getCharacter(SymbolType symbolIn)
|
||||||
{
|
{
|
||||||
return "/";
|
return "/";
|
||||||
}
|
}
|
||||||
|
else if(symbolIn == SymbolType.OCURLY)
|
||||||
|
{
|
||||||
|
return "{";
|
||||||
|
}
|
||||||
|
else if(symbolIn == SymbolType.CCURLY)
|
||||||
|
{
|
||||||
|
return "}";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gprintln("getCharacter: No back-mapping for "~to!(string)(symbolIn), DebugType.ERROR);
|
gprintln("getCharacter: No back-mapping for "~to!(string)(symbolIn), DebugType.ERROR);
|
||||||
|
|
|
@ -253,6 +253,11 @@ public class Function : TypedEntity, Container
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool hasParams()
|
||||||
|
{
|
||||||
|
return params.length != 0;
|
||||||
|
}
|
||||||
|
|
||||||
public void addStatement(Statement statement)
|
public void addStatement(Statement statement)
|
||||||
{
|
{
|
||||||
this.bodyStatements~=statement;
|
this.bodyStatements~=statement;
|
||||||
|
|
|
@ -86,43 +86,144 @@ public final class TypeChecker
|
||||||
gprintln(tree);
|
gprintln(tree);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Grab functionData ??? */
|
|
||||||
FunctionData[string] functions = grabFunctionDefs();
|
|
||||||
gprintln("Defined functions: "~to!(string)(functions));
|
|
||||||
/* TODO: Disable, this is just to peep */
|
|
||||||
// foreach(FunctionData funcData; functions.values)
|
|
||||||
// {
|
|
||||||
// DNode funcNode = funcData.generate();
|
|
||||||
// DNode[] actionListFunc = funcNode.poes;
|
|
||||||
// doTypeCheck(actionListFunc);
|
|
||||||
// printTypeQueue();
|
|
||||||
// gprintln(funcNode.print());
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* TODO: Work in progress (NEW!!!) */
|
|
||||||
/* Get the action-list (linearised bottom up graph) */
|
/* Get the action-list (linearised bottom up graph) */
|
||||||
DNode[] actionList = rootNode.poes;
|
DNode[] actionList = rootNode.poes;
|
||||||
doTypeCheck(actionList);
|
doTypeCheck(actionList);
|
||||||
printTypeQueue();
|
printTypeQueue();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: What's next?
|
* After processing globals executions the instructions will
|
||||||
*
|
* be placed into `codeQueue`, therefore copy them from the temporary
|
||||||
* 1. Fetch the tree from the DNodeGenerator
|
* scratchpad queue into `globalCodeQueue`.
|
||||||
*/
|
*
|
||||||
|
* Then clean the codeQueue for next use
|
||||||
|
*/
|
||||||
|
foreach(Instruction curGlobInstr; codeQueue)
|
||||||
|
{
|
||||||
|
globalCodeQueue~=curGlobInstr;
|
||||||
|
}
|
||||||
|
codeQueue.clear();
|
||||||
|
assert(codeQueue.empty() == true);
|
||||||
|
|
||||||
|
//FIXME: Look at this, ffs why is it static
|
||||||
|
//Clear tree/linearized version (todo comment)
|
||||||
|
DNode.poes=[];
|
||||||
|
|
||||||
|
/* Grab functionData ??? */
|
||||||
|
FunctionData[string] functionDefinitions = grabFunctionDefs();
|
||||||
|
gprintln("Defined functions: "~to!(string)(functionDefinitions));
|
||||||
|
|
||||||
|
foreach(FunctionData funcData; functionDefinitions.values)
|
||||||
|
{
|
||||||
|
assert(codeQueue.empty() == true);
|
||||||
|
|
||||||
|
|
||||||
|
DNode funcNode = funcData.generate();
|
||||||
|
//NOTE: We need to call this, it generates tree but also does the linearization
|
||||||
|
//NOTE: Rename that
|
||||||
|
funcNode.print();
|
||||||
|
DNode[] actionListFunc = funcNode.poes;
|
||||||
|
|
||||||
|
//TODO: Would this not mess with our queues?
|
||||||
|
doTypeCheck(actionListFunc);
|
||||||
|
printTypeQueue();
|
||||||
|
gprintln(funcNode.print());
|
||||||
|
|
||||||
|
// The current code queue would be the function's body instructions
|
||||||
|
// a.k.a. the `codeQueue`
|
||||||
|
// functionBodies[funcData.name] = codeQueue;
|
||||||
|
|
||||||
|
|
||||||
|
// The call to `doTypeCheck()` above adds to this queue
|
||||||
|
// so we should clean it out before the next run
|
||||||
|
//
|
||||||
|
// NOTE: Static allocations in? Well, we don't clean init queue
|
||||||
|
// so is it fine then? We now have seperate dependency trees,
|
||||||
|
// we should make checking methods that check the `initQueue`
|
||||||
|
// whenever we come past a `ClassStaticNode` for example
|
||||||
|
// codeQueue.clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy over the function code queue into
|
||||||
|
* the function code queue respective key.
|
||||||
|
*
|
||||||
|
* Then clear the scratchpad code queue
|
||||||
|
*/
|
||||||
|
functionBodyCodeQueues[funcData.name]=[];
|
||||||
|
foreach(Instruction curFuncInstr; codeQueue)
|
||||||
|
{
|
||||||
|
//TODO: Think about class funcs? Nah
|
||||||
|
functionBodyCodeQueues[funcData.name]~=curFuncInstr;
|
||||||
|
gprintln("FuncDef ("~funcData.name~"): Adding body instruction: "~to!(string)(curFuncInstr));
|
||||||
|
}
|
||||||
|
codeQueue.clear();
|
||||||
|
|
||||||
|
// Clear the linearization for the next round
|
||||||
|
DNode.poes=[];
|
||||||
|
|
||||||
|
gprintln("FUNCDEF DONE: "~to!(string)(functionBodyCodeQueues[funcData.name]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main code queue */
|
|
||||||
private SList!(Instruction) codeQueue;
|
/**
|
||||||
|
* Function definitions
|
||||||
|
*
|
||||||
|
* Holds their action lists which are to be used for the
|
||||||
|
* (later) emitting of their X-lang emit code
|
||||||
|
*/
|
||||||
|
//FUnctionDeifnition should couple `linearizedList` but `functionEntity`
|
||||||
|
// private FunctionDefinition[string] functionDefinitions2; //TODO: Use this
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concrete queues
|
||||||
|
*
|
||||||
|
* These queues below are finalized and not used as a scratchpad.
|
||||||
|
*
|
||||||
|
* 1. Global code queue
|
||||||
|
* - This accounts for the globals needing to be executed
|
||||||
|
* 2. Function body code queues
|
||||||
|
* - This accounts for (every) function definition's code queue
|
||||||
|
*/
|
||||||
|
private Instruction[] globalCodeQueue;
|
||||||
|
private Instruction[][string] functionBodyCodeQueues;
|
||||||
|
|
||||||
|
public Instruction[] getGlobalCodeQueue()
|
||||||
|
{
|
||||||
|
return globalCodeQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instruction[][string] getFunctionBodyCodeQueues()
|
||||||
|
{
|
||||||
|
return functionBodyCodeQueues;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Main code queue (used for temporary passes) */
|
||||||
|
private SList!(Instruction) codeQueue; //TODO: Rename to `currentCodeQueue`
|
||||||
|
|
||||||
/* Initialization queue */
|
/* Initialization queue */
|
||||||
private SList!(Instruction) initQueue;
|
private SList!(Instruction) initQueue;
|
||||||
|
|
||||||
public SList!(Instruction) getInitQueue()
|
|
||||||
|
//TODO: CHange to oneshot in the function
|
||||||
|
public Instruction[] getInitQueue()
|
||||||
{
|
{
|
||||||
return initQueue;
|
Instruction[] initQueueConcrete;
|
||||||
|
|
||||||
|
foreach(Instruction currentInstruction; initQueue)
|
||||||
|
{
|
||||||
|
initQueueConcrete~=currentInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
return initQueueConcrete;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adds an initialization instruction to the initialization queue (at the back) */
|
/* Adds an initialization instruction to the initialization queue (at the back) */
|
||||||
|
@ -176,10 +277,17 @@ public final class TypeChecker
|
||||||
return codeQueue.empty;
|
return codeQueue.empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SList!(Instruction) getCodeQueue()
|
// public Instruction[] getCodeQueue()
|
||||||
{
|
// {
|
||||||
return codeQueue;
|
// Instruction[] codeQueueConcrete;
|
||||||
}
|
|
||||||
|
// foreach(Instruction currentInstruction; codeQueue)
|
||||||
|
// {
|
||||||
|
// codeQueueConcrete~=currentInstruction;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return codeQueueConcrete;
|
||||||
|
// }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prints the current contents of the code-queue
|
* Prints the current contents of the code-queue
|
||||||
|
@ -702,7 +810,8 @@ public final class TypeChecker
|
||||||
/* TODO: Get the STatement */
|
/* TODO: Get the STatement */
|
||||||
Statement statement = dnode.getEntity();
|
Statement statement = dnode.getEntity();
|
||||||
|
|
||||||
gprintln("Generic DNode typecheck(): Begin");
|
gprintln("Generic DNode typecheck(): Begin (examine: "~to!(string)(dnode)~" )");
|
||||||
|
|
||||||
|
|
||||||
/* VariableAssignmentStdAlone */
|
/* VariableAssignmentStdAlone */
|
||||||
if(cast(VariableAssignmentStdAlone)statement)
|
if(cast(VariableAssignmentStdAlone)statement)
|
||||||
|
|
|
@ -163,7 +163,8 @@ public class DNode
|
||||||
private DNode[] dependencies;
|
private DNode[] dependencies;
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: Commen this
|
||||||
|
//NOTE: This is the linearized version
|
||||||
public static DNode[] poes;
|
public static DNode[] poes;
|
||||||
|
|
||||||
this(DNodeGenerator dnodegen, Statement entity)
|
this(DNodeGenerator dnodegen, Statement entity)
|
||||||
|
@ -1280,6 +1281,11 @@ public class DNodeGenerator
|
||||||
|
|
||||||
/* TODO: CHeck avriable name even */
|
/* TODO: CHeck avriable name even */
|
||||||
gprintln("YEAST ENJOYER");
|
gprintln("YEAST ENJOYER");
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: The below assert fails for function definitions trying to refer to global values
|
||||||
|
// as a reoslveBest (up) is needed. We should firstly check if within fails, if so,
|
||||||
|
// resolveBest, if that fails, then it is an error (see #46)
|
||||||
assert(tc.getResolver().resolveWithin(c, vAsStdAl.getVariableName()));
|
assert(tc.getResolver().resolveWithin(c, vAsStdAl.getVariableName()));
|
||||||
gprintln("YEAST ENJOYER");
|
gprintln("YEAST ENJOYER");
|
||||||
Variable variable = cast(Variable)tc.getResolver().resolveWithin(c, vAsStdAl.getVariableName());
|
Variable variable = cast(Variable)tc.getResolver().resolveWithin(c, vAsStdAl.getVariableName());
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
module simple_function_decls;
|
||||||
|
|
||||||
|
int j = 21;
|
||||||
|
int k = 22;
|
||||||
|
|
||||||
|
int apple(int j)
|
||||||
|
{
|
||||||
|
int h = 69;
|
||||||
|
}
|
||||||
|
|
||||||
|
int banana(int j)
|
||||||
|
{
|
||||||
|
int h = 64;
|
||||||
|
k=1;
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ module simple_variables_decls_ass;
|
||||||
|
|
||||||
int x = 1+2*2/1-6;
|
int x = 1+2*2/1-6;
|
||||||
|
|
||||||
discard "TDOO: Technically also not allowed (not compile-time constant in C)"
|
discard "TDOO: Technically also not allowed (not compile-time constant in C)";
|
||||||
int y = 2+x;
|
int y = 2+x;
|
||||||
|
|
||||||
discard "TODO: Technically the below should not be allowed as we cannot do it in C - sadly";
|
discard "TODO: Technically the below should not be allowed as we cannot do it in C - sadly";
|
||||||
|
|
Loading…
Reference in New Issue