CoreEmitter

- All operations regarding moving through (iterating over) instructions are now to be done via the instructions provided by CodeEmitter, moveback, moveforward etc.

DGen

- Re-worked the system to use new CodeEmitter semantics
- Variable assignments in declarations are oneshot now which makes it more compact, semantically better and also valid C

---

Tests

- Updated the `simple_variables.t` test case to have many binary operations chained
This commit is contained in:
Tristan B. Velloza Kildaire 2022-12-12 19:12:39 +02:00
parent e64a9ef5d1
commit 01bdb145e2
3 changed files with 92 additions and 37 deletions

View File

@ -7,6 +7,7 @@ import compiler.codegen.instruction;
import std.stdio;
import std.file;
import compiler.codegen.instruction : Instruction;
import std.range : walkLength;
/**
* TODO: Perhaps have an interface that can emit(Context/Parent, Statement)
@ -21,37 +22,63 @@ public abstract class CodeEmitter
/**
* Required queues
*/
protected SList!(Instruction) initQueue;
protected SList!(Instruction) codeQueue;
private Instruction[] initQueue;
private Instruction[] codeQueue;
alias instructions = codeQueue;
// alias instructions = codeQueue;
protected File file;
protected string currentEmitBuildUp;
private ulong codeQueueIdx = 0;
public void buildEmit(string data)
public final Instruction getCurrentCodeInstruction()
{
currentEmitBuildUp~=data;
return codeQueue[codeQueueIdx];
}
public void flushEmit()
public final bool hasCodeInstructions()
{
file.writeln(currentEmitBuildUp);
currentEmitBuildUp = "";
return codeQueueIdx < codeQueue.length;
}
public final void nextCodeInstruction()
{
codeQueueIdx++;
}
public final void previousCodeInstruction()
{
codeQueueIdx--;
}
public final ulong getInitQueueLen()
{
return initQueue.length;
}
public final ulong getCodeQueueLen()
{
return codeQueue.length;
}
this(TypeChecker typeChecker, File file)
{
this.typeChecker = typeChecker;
/* Extract the allocation queue, the code queue */
initQueue = typeChecker.getInitQueue();
codeQueue = typeChecker.getCodeQueue();
foreach(Instruction currentInstruction; typeChecker.getInitQueue())
{
initQueue~=currentInstruction;
}
foreach(Instruction currentInstruction; typeChecker.getCodeQueue())
{
codeQueue~=currentInstruction;
}
this.file = file;
}

View File

@ -23,7 +23,10 @@ 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
private bool varDecWantsConsumeVarAss = false;
this(TypeChecker typeChecker, File file)
@ -42,22 +45,24 @@ public final class DCodeEmitter : CodeEmitter
Context context = varAs.getContext();
gprintln("Is ContextNull?: "~to!(string)(context is null));
Variable typedEntityVariable = cast(Variable)context.tc.getResolver().resolveBest(context.getContainer(), varAs.varName); //TODO: Remove `auto`
auto typedEntityVariable = context.tc.getResolver().resolveBest(context.getContainer(), varAs.varName); //TODO: Remove `auto`
string typedEntityVariableName = context.tc.getResolver().generateName(context.getContainer(), typedEntityVariable);
import compiler.codegen.mapper : SymbolMapper;
string renamedSymbol = SymbolMapper.symbolLookup(context.getContainer(), typedEntityVariableName);
/* TODO: Add check for variable assigmen tto here */
if(typedEntityVariable.getAssignment())
// If we are needed as part of a VariabvleDeclaration-with-assignment
if(varDecWantsConsumeVarAss)
{
//TODO: Set a field here that gets checked for VariableDeclaration instruction
//to return only RHS (and not assignment with variable)
//It will then reset said bit
//TODO: We will also then need a peak (cursor rather than an iterator I think)
//and in such case the VariableDeclaration branch (under that bit set - once again)
//must then progress the cursor (such that we skip it next time)
// Generate the code to emit (only the RHS of the = sign)
string emitCode = transform(varAs.data);
// Reset flag
varDecWantsConsumeVarAss = false;
return emitCode;
}
@ -69,7 +74,7 @@ public final class DCodeEmitter : CodeEmitter
VariableDeclaration varDecInstr = cast(VariableDeclaration)instruction;
Context context = varDecInstr.getContext();
auto typedEntityVariable = context.tc.getResolver().resolveBest(context.getContainer(), varDecInstr.varName); //TODO: Remove `auto`
Variable typedEntityVariable = cast(Variable)context.tc.getResolver().resolveBest(context.getContainer(), varDecInstr.varName); //TODO: Remove `auto`
string typedEntityVariableName = context.tc.getResolver().generateName(context.getContainer(), typedEntityVariable);
//NOTE: We should remove all dots from generated symbol names as it won't be valid C (I don't want to say C because
@ -88,6 +93,31 @@ public final class DCodeEmitter : CodeEmitter
/* TODO: I like the hold technique */
/* TODO: Add check for variable assigmen tto here */
if(typedEntityVariable.getAssignment())
{
//TODO: Set a field here that gets checked for VariableDeclaration instruction
//to return only RHS (and not assignment with variable)
//It will then reset said bit
//TODO: We will also then need a peak (cursor rather than an iterator I think)
//and in such case the VariableDeclaration branch (under that bit set - once again)
//must then progress the cursor (such that we skip it next time)
varDecWantsConsumeVarAss = true;
// Fetch the variable assignment instruction
nextCodeInstruction();
Instruction varAssInstr = getCurrentCodeInstruction();
// Generate the code to emit
string emit = varDecInstr.varType~" "~renamedSymbol~" = "~transform(varAssInstr)~";";
return emit;
}
return varDecInstr.varType~" "~renamedSymbol~";";
@ -115,11 +145,11 @@ 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)(walkLength(initQueue[])));
emitStaticAllocations(initQueue);
gprintln("Static allocations needed: "~to!(string)(getInitQueueLen()));
emitStaticAllocations();
gprintln("Code emittings needed: "~to!(string)(walkLength(codeQueue[])));
emitCodeQueue(codeQueue);
gprintln("Code emittings needed: "~to!(string)(getCodeQueueLen()));
emitCodeQueue();
//TODO: Emit function definitions
@ -163,21 +193,19 @@ public final class DCodeEmitter : CodeEmitter
* Params:
* initQueue = The allocation queue to emit static allocations from
*/
private void emitStaticAllocations(SList!(Instruction) initQueue)
private void emitStaticAllocations()
{
}
private void emitCodeQueue(SList!(Instruction) codeQueue)
private void emitCodeQueue()
{
//TODO: Implement me
//NOTE: I think that every `Instruction` will need an `emit()` method
//of which sometimes can be recursive for instructions that are nested
foreach(Instruction currentInstruction; codeQueue)
while(hasCodeInstructions())
{
// file.writeln(currentInstruction.emit());
Instruction currentInstruction = getCurrentCodeInstruction();
file.writeln(transform(currentInstruction));
nextCodeInstruction();
}
}

View File

@ -1,5 +1,5 @@
module simple_variables;
int x = 1+2;
int x = 1+2+2+1;
int y = 2;