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.stdio;
import std.file; import std.file;
import compiler.codegen.instruction : Instruction; import compiler.codegen.instruction : Instruction;
import std.range : walkLength;
/** /**
* TODO: Perhaps have an interface that can emit(Context/Parent, Statement) * TODO: Perhaps have an interface that can emit(Context/Parent, Statement)
@ -21,37 +22,63 @@ public abstract class CodeEmitter
/** /**
* Required queues * Required queues
*/ */
protected SList!(Instruction) initQueue; private Instruction[] initQueue;
protected SList!(Instruction) codeQueue; private Instruction[] codeQueue;
alias instructions = codeQueue; // alias instructions = codeQueue;
protected File file; 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); return codeQueueIdx < codeQueue.length;
currentEmitBuildUp = "";
} }
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, File file)
{ {
this.typeChecker = typeChecker; this.typeChecker = typeChecker;
/* Extract the allocation queue, the code queue */ /* Extract the allocation queue, the code queue */
initQueue = typeChecker.getInitQueue(); foreach(Instruction currentInstruction; typeChecker.getInitQueue())
codeQueue = typeChecker.getCodeQueue(); {
initQueue~=currentInstruction;
}
foreach(Instruction currentInstruction; typeChecker.getCodeQueue())
{
codeQueue~=currentInstruction;
}
this.file = file; this.file = file;
} }

View File

@ -23,7 +23,10 @@ public final class DCodeEmitter : CodeEmitter
private Stack!(Instruction) varAssStack; 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) this(TypeChecker typeChecker, File file)
@ -42,22 +45,24 @@ public final class DCodeEmitter : CodeEmitter
Context context = varAs.getContext(); Context context = varAs.getContext();
gprintln("Is ContextNull?: "~to!(string)(context is null)); 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); string typedEntityVariableName = context.tc.getResolver().generateName(context.getContainer(), typedEntityVariable);
import compiler.codegen.mapper : SymbolMapper; import compiler.codegen.mapper : SymbolMapper;
string renamedSymbol = SymbolMapper.symbolLookup(context.getContainer(), typedEntityVariableName); 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 // Generate the code to emit (only the RHS of the = sign)
//to return only RHS (and not assignment with variable) string emitCode = transform(varAs.data);
//It will then reset said bit
//TODO: We will also then need a peak (cursor rather than an iterator I think) // Reset flag
//and in such case the VariableDeclaration branch (under that bit set - once again) varDecWantsConsumeVarAss = false;
//must then progress the cursor (such that we skip it next time)
return emitCode;
} }
@ -69,7 +74,7 @@ public final class DCodeEmitter : CodeEmitter
VariableDeclaration varDecInstr = cast(VariableDeclaration)instruction; VariableDeclaration varDecInstr = cast(VariableDeclaration)instruction;
Context context = varDecInstr.getContext(); 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); 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 //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: 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~";"; 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) // 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)(walkLength(initQueue[]))); gprintln("Static allocations needed: "~to!(string)(getInitQueueLen()));
emitStaticAllocations(initQueue); emitStaticAllocations();
gprintln("Code emittings needed: "~to!(string)(walkLength(codeQueue[]))); gprintln("Code emittings needed: "~to!(string)(getCodeQueueLen()));
emitCodeQueue(codeQueue); emitCodeQueue();
//TODO: Emit function definitions //TODO: Emit function definitions
@ -163,21 +193,19 @@ public final class DCodeEmitter : CodeEmitter
* Params: * Params:
* initQueue = The allocation queue to emit static allocations from * 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 while(hasCodeInstructions())
//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)
{ {
// file.writeln(currentInstruction.emit()); Instruction currentInstruction = getCurrentCodeInstruction();
file.writeln(transform(currentInstruction)); file.writeln(transform(currentInstruction));
nextCodeInstruction();
} }
} }

View File

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