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
|
||||
|
||||
## Docs
|
||||
## Documentation
|
||||
|
||||
Docs are available [here](http://deavmi.assigned.network/secret/tlang).
|
||||
Docs are available [here](http://deavmi.assigned.network/projects/tlang/).
|
||||
|
||||
## Building
|
||||
|
||||
To build you will need `dmd` and `dub` installed. You can then run the following:
|
||||
|
||||
```
|
||||
dub test
|
||||
dub test --coverage
|
||||
dub build
|
||||
```
|
||||
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
/**
|
||||
* Tristan's programming language
|
||||
*
|
||||
* This is TOP SECRET code, not for RELEASE!
|
||||
* Violators WILL BE PUT UP AGAINST A WALL AND
|
||||
* SHOT!
|
||||
*/
|
||||
|
||||
* TLP reference compiler
|
||||
*
|
||||
* This is the entry point for the TLP
|
||||
* reference compiler.
|
||||
*/
|
||||
module tlang;
|
||||
|
||||
import std.stdio;
|
||||
|
@ -14,7 +12,7 @@ import commandline.args;
|
|||
void main(string[] args)
|
||||
{
|
||||
/* TODO: Replace with something else */
|
||||
writeln("tlang NO_PUBLISH_RELEASE");
|
||||
writeln("tlang NO_PUBLISH_RELEASE\n");
|
||||
|
||||
/* Parse the command-line arguments */
|
||||
parseCommandLine(args);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/**
|
||||
* Commands
|
||||
*
|
||||
* All command-line arguments and their impementations
|
||||
*/
|
||||
* Commands
|
||||
*
|
||||
* All command-line arguments and their impementations
|
||||
*/
|
||||
|
||||
module commandline.commands;
|
||||
|
||||
|
@ -10,19 +10,11 @@ import jcli;
|
|||
import std.stdio;
|
||||
import compiler.compiler : beginCompilation;
|
||||
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;
|
||||
|
||||
@Command("help", "Shows the help screen")
|
||||
struct helpCommand
|
||||
{
|
||||
/* TODO: Add missing implementation for this */
|
||||
void onExecute()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
//TODO: Re-order the definitions below so that they appear with compile first, then lex, parse, ..., help
|
||||
|
||||
/**
|
||||
* Compile the given source file from start to finish
|
||||
|
@ -40,11 +32,6 @@ struct compileCommand
|
|||
void onExecute()
|
||||
{
|
||||
writeln("Compiling source file: "~sourceFile);
|
||||
|
||||
/* TODO: Read file */
|
||||
string sourceCode = "";
|
||||
|
||||
|
||||
beginCompilation([sourceFile]);
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +42,7 @@ struct compileCommand
|
|||
@Command("lex", "Performs tokenization of the given file(s)")
|
||||
struct lexCommand
|
||||
{
|
||||
@ArgPositional("source file", "The source file to compile")
|
||||
@ArgPositional("source file", "The source file to lex")
|
||||
string sourceFile;
|
||||
|
||||
void onExecute()
|
||||
|
@ -72,6 +59,7 @@ struct lexCommand
|
|||
data.length = fSize;
|
||||
data = file.rawRead(data);
|
||||
string sourceText = cast(string)data;
|
||||
file.close();
|
||||
|
||||
/* Begin lexing process */
|
||||
Lexer lexer = new Lexer(sourceText);
|
||||
|
@ -93,3 +81,174 @@ struct lexCommand
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 compiler.codegen.instruction : Instruction;
|
||||
import std.range : walkLength;
|
||||
import gogga;
|
||||
import std.conv : to;
|
||||
|
||||
/**
|
||||
* TODO: Perhaps have an interface that can emit(Context/Parent, Statement)
|
||||
|
@ -19,49 +21,143 @@ public abstract class CodeEmitter
|
|||
{
|
||||
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
|
||||
*/
|
||||
private Instruction[] initQueue;
|
||||
private Instruction[] codeQueue;
|
||||
private Instruction[] globalCodeQueue;
|
||||
|
||||
/**
|
||||
* Required queues (maps to them)
|
||||
*/
|
||||
private Instruction[][string] functionBodyInstrs;
|
||||
|
||||
// alias instructions = codeQueue;
|
||||
|
||||
protected File file;
|
||||
|
||||
|
||||
private ulong codeQueueIdx = 0;
|
||||
|
||||
|
||||
public final Instruction getCurrentCodeInstruction()
|
||||
public final ulong getQueueLength()
|
||||
{
|
||||
return codeQueue[codeQueueIdx];
|
||||
}
|
||||
|
||||
public final bool hasCodeInstructions()
|
||||
{
|
||||
return codeQueueIdx < codeQueue.length;
|
||||
}
|
||||
|
||||
public final void nextCodeInstruction()
|
||||
{
|
||||
codeQueueIdx++;
|
||||
}
|
||||
|
||||
public final void previousCodeInstruction()
|
||||
{
|
||||
codeQueueIdx--;
|
||||
return selectedQueue.length;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -70,14 +166,12 @@ public abstract class CodeEmitter
|
|||
this.typeChecker = typeChecker;
|
||||
|
||||
/* Extract the allocation queue, the code queue */
|
||||
foreach(Instruction currentInstruction; typeChecker.getInitQueue())
|
||||
{
|
||||
initQueue~=currentInstruction;
|
||||
}
|
||||
foreach(Instruction currentInstruction; typeChecker.getCodeQueue())
|
||||
{
|
||||
codeQueue~=currentInstruction;
|
||||
}
|
||||
initQueue = typeChecker.getInitQueue();
|
||||
globalCodeQueue = typeChecker.getGlobalCodeQueue();
|
||||
|
||||
/* Extract the function definitions string-queue mapping */
|
||||
functionBodyInstrs = typeChecker.getFunctionBodyCodeQueues();
|
||||
gprintln("CodeEmitter: Got number of function defs: "~to!(string)(functionBodyInstrs));
|
||||
|
||||
this.file = file;
|
||||
}
|
||||
|
|
|
@ -12,17 +12,14 @@ import gogga;
|
|||
import std.range : walkLength;
|
||||
import std.string : wrap;
|
||||
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.symbols.data : SymbolType, Variable;
|
||||
import compiler.symbols.data : SymbolType, Variable, Function;
|
||||
import compiler.symbols.check : getCharacter;
|
||||
import misc.utils : Stack;
|
||||
|
||||
public final class DCodeEmitter : CodeEmitter
|
||||
{
|
||||
private Stack!(Instruction) varAssStack;
|
||||
|
||||
|
||||
// Set to true when processing a variable declaration
|
||||
// which expects an assignment. Set to false when
|
||||
// said variable assignment has been processed
|
||||
|
@ -32,12 +29,12 @@ public final class DCodeEmitter : CodeEmitter
|
|||
this(TypeChecker typeChecker, File file)
|
||||
{
|
||||
super(typeChecker, file);
|
||||
|
||||
varAssStack = new Stack!(Instruction)();
|
||||
}
|
||||
|
||||
public override string transform(const Instruction instruction)
|
||||
{
|
||||
gprintln("transform(): "~to!(string)(instruction));
|
||||
|
||||
/* VariableAssignmentInstr */
|
||||
if(cast(VariableAssignmentInstr)instruction)
|
||||
{
|
||||
|
@ -92,8 +89,8 @@ public final class DCodeEmitter : CodeEmitter
|
|||
varDecWantsConsumeVarAss = true;
|
||||
|
||||
// Fetch the variable assignment instruction
|
||||
nextCodeInstruction();
|
||||
Instruction varAssInstr = getCurrentCodeInstruction();
|
||||
nextInstruction();
|
||||
Instruction varAssInstr = getCurrentInstruction();
|
||||
|
||||
// Generate the code to emit
|
||||
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)
|
||||
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();
|
||||
|
||||
gprintln("Code emittings needed: "~to!(string)(getCodeQueueLen()));
|
||||
gprintln("Function definitions needed: "~to!(string)(1)); //TODO: fix counter here
|
||||
emitFunctionDefinitions();
|
||||
|
||||
gprintln("\n\n\n");
|
||||
|
||||
emitCodeQueue();
|
||||
|
||||
gprintln("\n\n\n");
|
||||
|
||||
//TODO: Emit function definitions
|
||||
|
||||
//TODO: Emit main (entry point)
|
||||
|
@ -190,17 +192,109 @@ public final class DCodeEmitter : CodeEmitter
|
|||
*/
|
||||
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()
|
||||
{
|
||||
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));
|
||||
|
||||
nextCodeInstruction();
|
||||
nextInstruction();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ module compiler.codegen.mapper;
|
|||
|
||||
import compiler.typecheck.core;
|
||||
import compiler.symbols.data;
|
||||
import std.conv : to;
|
||||
import gogga;
|
||||
|
||||
/**
|
||||
* SymbolMapper
|
||||
|
@ -28,6 +30,8 @@ public final class SymbolMapper
|
|||
auto entity = tc.getResolver().resolveBest(container, entityNameIn); //TODO: Remove `auto`
|
||||
string entityNameAbsolute = tc.getResolver().generateName(tc.getModule(), entity);
|
||||
|
||||
gprintln("symbolLookup(): "~to!(string)(container));
|
||||
|
||||
// Hash the absolute path name
|
||||
// FIXME: Ensure these hashes are unique (use the smbyol table!)
|
||||
import std.digest : toHexString, LetterCase;
|
||||
|
|
|
@ -13,6 +13,12 @@ import core.stdc.stdlib;
|
|||
import compiler.codegen.emit.core;
|
||||
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)
|
||||
{
|
||||
/* TODO: Begin compilation process, take in data here */
|
||||
|
|
|
@ -17,8 +17,6 @@ public class ParserException : TError
|
|||
super(message);
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public final class SyntaxError : ParserException
|
||||
|
@ -30,7 +28,7 @@ public final class SyntaxError : ParserException
|
|||
this(Parser parser, SymbolType expected, Token providedToken)
|
||||
{
|
||||
this.expected = expected;
|
||||
provided = getSymbolType(providedToken);
|
||||
this.provided = getSymbolType(providedToken);
|
||||
this.providedToken = providedToken;
|
||||
|
||||
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 "/";
|
||||
}
|
||||
else if(symbolIn == SymbolType.OCURLY)
|
||||
{
|
||||
return "{";
|
||||
}
|
||||
else if(symbolIn == SymbolType.CCURLY)
|
||||
{
|
||||
return "}";
|
||||
}
|
||||
else
|
||||
{
|
||||
gprintln("getCharacter: No back-mapping for "~to!(string)(symbolIn), DebugType.ERROR);
|
||||
|
|
|
@ -253,6 +253,11 @@ public class Function : TypedEntity, Container
|
|||
return params;
|
||||
}
|
||||
|
||||
public bool hasParams()
|
||||
{
|
||||
return params.length != 0;
|
||||
}
|
||||
|
||||
public void addStatement(Statement statement)
|
||||
{
|
||||
this.bodyStatements~=statement;
|
||||
|
|
|
@ -86,43 +86,144 @@ public final class TypeChecker
|
|||
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) */
|
||||
DNode[] actionList = rootNode.poes;
|
||||
doTypeCheck(actionList);
|
||||
printTypeQueue();
|
||||
|
||||
|
||||
/**
|
||||
* TODO: What's next?
|
||||
*
|
||||
* 1. Fetch the tree from the DNodeGenerator
|
||||
*/
|
||||
* After processing globals executions the instructions will
|
||||
* be placed into `codeQueue`, therefore copy them from the temporary
|
||||
* 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 */
|
||||
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) */
|
||||
|
@ -176,10 +277,17 @@ public final class TypeChecker
|
|||
return codeQueue.empty;
|
||||
}
|
||||
|
||||
public SList!(Instruction) getCodeQueue()
|
||||
{
|
||||
return codeQueue;
|
||||
}
|
||||
// public Instruction[] getCodeQueue()
|
||||
// {
|
||||
// Instruction[] codeQueueConcrete;
|
||||
|
||||
// foreach(Instruction currentInstruction; codeQueue)
|
||||
// {
|
||||
// codeQueueConcrete~=currentInstruction;
|
||||
// }
|
||||
|
||||
// return codeQueueConcrete;
|
||||
// }
|
||||
|
||||
/*
|
||||
* Prints the current contents of the code-queue
|
||||
|
@ -702,7 +810,8 @@ public final class TypeChecker
|
|||
/* TODO: Get the STatement */
|
||||
Statement statement = dnode.getEntity();
|
||||
|
||||
gprintln("Generic DNode typecheck(): Begin");
|
||||
gprintln("Generic DNode typecheck(): Begin (examine: "~to!(string)(dnode)~" )");
|
||||
|
||||
|
||||
/* VariableAssignmentStdAlone */
|
||||
if(cast(VariableAssignmentStdAlone)statement)
|
||||
|
|
|
@ -163,7 +163,8 @@ public class DNode
|
|||
private DNode[] dependencies;
|
||||
|
||||
|
||||
|
||||
//TODO: Commen this
|
||||
//NOTE: This is the linearized version
|
||||
public static DNode[] poes;
|
||||
|
||||
this(DNodeGenerator dnodegen, Statement entity)
|
||||
|
@ -1280,6 +1281,11 @@ public class DNodeGenerator
|
|||
|
||||
/* TODO: CHeck avriable name even */
|
||||
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()));
|
||||
gprintln("YEAST ENJOYER");
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
discard "TODO: Technically the below should not be allowed as we cannot do it in C - sadly";
|
||||
|
|
Loading…
Reference in New Issue