tlang/source/tlang/compiler/codegen/emit/core.d

171 lines
4.1 KiB
D

module compiler.codegen.emit.core;
import compiler.symbols.data;
import compiler.typecheck.core;
import std.container.slist : SList;
import compiler.codegen.instruction;
import std.stdio;
import std.file;
import compiler.codegen.instruction : Instruction;
import std.range : walkLength;
import gogga;
import std.conv : to;
import compiler.configuration : CompilerConfiguration;
import compiler.codegen.mapper.core : SymbolMapper;
/**
* TODO: Perhaps have an interface that can emit(Context/Parent, Statement)
*/
/* TODO: Module linking (general overhaul required) */
public abstract class CodeEmitter
{
protected TypeChecker typeChecker;
protected File file;
protected CompilerConfiguration config;
protected SymbolMapper mapper;
/**
* 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];
}
public final ulong getCursor()
{
return queueCursor;
}
public final ulong getSelectedQueueLength()
{
return selectedQueue.length;
}
public final ulong getQueueLength()
{
return selectedQueue.length;
}
/**
* Required queues
*/
private Instruction[] initQueue;
private Instruction[] globalCodeQueue;
/**
* Required queues (maps to them)
*/
private Instruction[][string] functionBodyInstrs;
public final ulong getFunctionDefinitionsCount()
{
return functionBodyInstrs.keys().length;
}
public final string[] getFunctionDefinitionNames()
{
return functionBodyInstrs.keys();
}
// TODO: Add allow for custom symbol mapper, use an interface or rather base class mechanism for it
this(TypeChecker typeChecker, File file, CompilerConfiguration config, SymbolMapper mapper)
{
this.typeChecker = typeChecker;
/* Extract the allocation queue, the code queue */
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;
this.config = config;
this.mapper = mapper;
}
/**
* 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);
}