Instruction

- Removed all `emit()` methods (this is now done in the language-specific emitter - DGen)

CoreEmitter

- Added docstrings
- Added required `transform(Instruction)` method which must transform each provided Instruction into a string (a.k.a. do the actual emit()-ting)

DGen

- Migrated C-emit code into the overrided `transform(Instruction)` method
This commit is contained in:
Tristan B. Velloza Kildaire 2022-12-12 15:36:07 +02:00
parent 092e4e4130
commit b0d9d2aabe
3 changed files with 111 additions and 82 deletions

View File

@ -6,6 +6,7 @@ import std.container.slist : SList;
import compiler.codegen.instruction;
import std.stdio;
import std.file;
import compiler.codegen.instruction : Instruction;
/**
* TODO: Perhaps have an interface that can emit(Context/Parent, Statement)
@ -40,7 +41,24 @@ public abstract class CodeEmitter
this.file = file;
}
/**
* Begins the emit process
*/
public abstract void emit();
/**
* Finalizes the emitting process (only
* to be called after the `emit()` finishes)
*/
public abstract void finalize();
/**
* Transforms or emits a single Instruction
* and returns the transformation
*
* Params:
* instruction = The Instruction to transform/emit
* Returns: The Instruction emit as a string
*/
public abstract string transform(Instruction instruction);
}

View File

@ -12,6 +12,10 @@ 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.codegen.mapper : SymbolMapper;
import compiler.symbols.data : SymbolType;
import compiler.symbols.check : getCharacter;
public final class DCodeEmitter : CodeEmitter
{
@ -20,31 +24,64 @@ public final class DCodeEmitter : CodeEmitter
super(typeChecker, file);
}
public override void finalize()
public override string transform(const Instruction instruction)
{
try
/* VariableAssignmentInstr */
if(cast(VariableAssignmentInstr)instruction)
{
//NOTE: Change to system compiler (maybe, we need to choose a good C compiler)
Pid ccPID = spawnProcess(["gcc", "-o", "tlang.out", file.name()]);
VariableAssignmentInstr varAs = cast(VariableAssignmentInstr)instruction;
Context context = varAs.getContext();
//NOTE: Case where it exited and Pid now inavlid (if it happens it would throw processexception surely)?
int code = wait(ccPID);
gprintln(code);
gprintln("Is ContextNull?: "~to!(string)(context is null));
auto typedEntityVariable = context.tc.getResolver().resolveBest(context.getContainer(), varAs.varName); //TODO: Remove `auto`
string typedEntityVariableName = context.tc.getResolver().generateName(context.getContainer(), typedEntityVariable);
if(code)
{
//NOTE: Make this a TLang exception
throw new Exception("The CC exited with a non-zero exit code");
}
import compiler.codegen.mapper : SymbolMapper;
string renamedSymbol = SymbolMapper.symbolLookup(context.getContainer(), typedEntityVariableName);
return renamedSymbol~" = "~transform(varAs.data)~";";
}
catch(ProcessException e)
/* VariableDeclaration */
else if(cast(VariableDeclaration)instruction)
{
gprintln("NOTE: Case where it exited and Pid now inavlid (if it happens it would throw processexception surely)?", DebugType.ERROR);
assert(false);
VariableDeclaration varDecInstr = cast(VariableDeclaration)instruction;
Context context = varDecInstr.getContext();
auto typedEntityVariable = 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
// a custom CodeEmitter should be allowed, so let's call it a general rule)
//
//simple_variables.x -> simple_variables_x
//NOTE: We may need to create a symbol table actually and add to that and use that as these names
//could get out of hand (too long)
// NOTE: Best would be identity-mapping Entity's to a name
import compiler.codegen.mapper : SymbolMapper;
string renamedSymbol = SymbolMapper.symbolLookup(context.getContainer(), varDecInstr.varName);
return varDecInstr.varType~" "~renamedSymbol~";";
}
/* LiteralValue */
else if(cast(LiteralValue)instruction)
{
LiteralValue literalValueInstr = cast(LiteralValue)instruction;
return to!(string)(literalValueInstr.data);
}
/* BinOpInstr */
else if(cast(BinOpInstr)instruction)
{
BinOpInstr binOpInstr = cast(BinOpInstr)instruction;
return transform(binOpInstr.lhs)~to!(string)(getCharacter(binOpInstr.operator))~transform(binOpInstr.rhs);
}
return "<TODO: Base emit>";
}
public override void emit()
{
// Emit header comment (NOTE: Change this to a useful piece of text)
@ -111,7 +148,8 @@ public final class DCodeEmitter : CodeEmitter
foreach(Instruction currentInstruction; codeQueue)
{
file.writeln(currentInstruction.emit());
// file.writeln(currentInstruction.emit());
file.writeln(transform(currentInstruction));
}
}
@ -125,4 +163,39 @@ int main()
return 0;
}`);
}
public override void finalize()
{
try
{
//NOTE: Change to system compiler (maybe, we need to choose a good C compiler)
Pid ccPID = spawnProcess(["gcc", "-o", "tlang.out", file.name()]);
//NOTE: Case where it exited and Pid now inavlid (if it happens it would throw processexception surely)?
int code = wait(ccPID);
gprintln(code);
if(code)
{
//NOTE: Make this a TLang exception
throw new Exception("The CC exited with a non-zero exit code");
}
}
catch(ProcessException e)
{
gprintln("NOTE: Case where it exited and Pid now inavlid (if it happens it would throw processexception surely)?", DebugType.ERROR);
assert(false);
}
}
}

View File

@ -8,11 +8,6 @@ import compiler.symbols.data : SymbolType;
import compiler.symbols.check : getCharacter;
import gogga;
/**
* TODO: We should actually remove the emits from here probably and rather do those in DGen
* as they are C specific
*/
public class Instruction
{
/* Context for the Instruction (used in emitter for name resolution) */
@ -30,11 +25,6 @@ public class Instruction
return "[Instruction: "~this.classinfo.name~":"~addInfo~"]";
}
public string emit()
{
return "TODO: This instruction has not provided an emit text yet! (This is an error!)";
}
public final Context getContext()
{
return context;
@ -69,7 +59,7 @@ public class VariableAssignmentInstr : Instruction
/* Name of variable being declared */
public string varName; /*TODO: Might not be needed */
public Instruction data;
public const Instruction data;
this(string varName, Instruction data)
{
@ -78,21 +68,6 @@ public class VariableAssignmentInstr : Instruction
addInfo = "assignTo: "~varName~", valInstr: "~data.toString();
}
public override string emit()
{
gprintln("Is ContextNull?: "~to!(string)(context is null));
auto typedEntityVariable = context.tc.getResolver().resolveBest(context.getContainer(), 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);
return renamedSymbol~" = "~data.emit()~";";
// return "<TODO: VarAssAssignment ("~data.emit()~")";
}
}
public final class VariableDeclaration : StorageDeclaration
@ -115,33 +90,6 @@ public final class VariableDeclaration : StorageDeclaration
addInfo = "varName: "~varName;
}
/**
* Emits a string of the form:
*
* <varType> <varName>;
*
* Returns: The emitted code
*/
public override string emit()
{
auto typedEntityVariable = context.tc.getResolver().resolveBest(context.getContainer(), 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
// a custom CodeEmitter should be allowed, so let's call it a general rule)
//
//simple_variables.x -> simple_variables_x
//NOTE: We may need to create a symbol table actually and add to that and use that as these names
//could get out of hand (too long)
// NOTE: Best would be identity-mapping Entity's to a name
string renamedSymbol = symbolRename(typedEntityVariableName);
import compiler.codegen.mapper : SymbolMapper;
renamedSymbol = SymbolMapper.symbolLookup(context.getContainer(), varName);
return varType~" "~renamedSymbol~";";
}
}
public final class FetchValueVar : Value
@ -175,11 +123,6 @@ public final class LiteralValue : Value
addInfo = "Data: "~to!(string)(data)~", Length: "~to!(string)(len);
}
public override string emit()
{
return to!(string)(data);
}
}
public final class LiteralValueFloat : Value
@ -253,9 +196,9 @@ public final class StringLiteral : Value
*/
public class BinOpInstr : Value
{
private Instruction lhs;
private Instruction rhs;
private SymbolType operator;
public const Instruction lhs;
public const Instruction rhs;
public const SymbolType operator;
this(Instruction lhs, Instruction rhs, SymbolType operator)
{
@ -265,11 +208,6 @@ public class BinOpInstr : Value
addInfo = "BinOpType: "~to!(string)(operator)~", LhsValInstr: "~lhs.toString()~", RhsValInstr: "~rhs.toString();
}
public override string emit()
{
return lhs.emit()~to!(string)(getCharacter(operator))~rhs.emit();
}
}
/**