Instruction

- Make the name of the function const and public for FuncCallInstr

CodeEmitter

- Added methods `getCursor()`, `getSelectedQueueLength()` and `getQueueLength()`
- Removed old queue-specific methods

DGen

- Added emitting for FuncCallInstr instruction (function call support)
- Now emit globals first BEFORE function definitions
- Added debug prints per instruction to know what instruction is currently being transform()'d
- After emitting sections add newlines between each to make for neater C code
- `emitEntryPoint()` now adds a test for `simple_function_decls.t` (This should be removed soon)
- Removed incorrect TODO in `finalize()`

Dependency

- Make the `nodePool` static, to ensure pooling carries over across multiple `DNodeGenerator` instances
- Fixed handling of function calls in `expressionPass()` - do NOT add a so-called `FunctionDefNode` (remember functions are defined by `addFuncDef()`)
- Set the Context of standalone variable assignments to the Context of the Variable entity representing the variable being assigned to

TypeChecker

- Assign the Context object stored in the `FunctionCall` statement to the `FuncCallInstr`

Test cases

- Updated test case `simple_function_decls.t`
This commit is contained in:
Tristan B. Velloza Kildaire 2022-12-16 14:53:33 +02:00
parent 8a481fb0ac
commit 2a12c310a6
6 changed files with 127 additions and 85 deletions

View File

@ -20,6 +20,7 @@ import std.conv : to;
public abstract class CodeEmitter
{
protected TypeChecker typeChecker;
protected File file;
/**
* The selected queue is the queue to be used
@ -88,7 +89,21 @@ public abstract class CodeEmitter
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
*/
@ -100,67 +115,16 @@ public abstract class CodeEmitter
*/
private Instruction[][string] functionBodyInstrs;
protected File file;
public final ulong getQueueLength()
public final ulong getFunctionDefinitionsCount()
{
return selectedQueue.length;
return functionBodyInstrs.keys().length;
}
public final string[] getFunctionDefinitionNames()
{
return functionBodyInstrs.keys();
}
/**
* 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()
{
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;
}
this(TypeChecker typeChecker, File file)
{
this.typeChecker = typeChecker;

View File

@ -33,15 +33,20 @@ public final class DCodeEmitter : CodeEmitter
public override string transform(const Instruction instruction)
{
import std.stdio;
writeln("\n");
gprintln("transform(): "~to!(string)(instruction));
/* VariableAssignmentInstr */
if(cast(VariableAssignmentInstr)instruction)
{
gprintln("type: VariableAssignmentInstr");
VariableAssignmentInstr varAs = cast(VariableAssignmentInstr)instruction;
Context context = varAs.getContext();
gprintln("Is ContextNull?: "~to!(string)(context is null));
gprintln("Wazza contect: "~to!(string)(context.container));
auto typedEntityVariable = context.tc.getResolver().resolveBest(context.getContainer(), varAs.varName); //TODO: Remove `auto`
string typedEntityVariableName = context.tc.getResolver().generateName(context.getContainer(), typedEntityVariable);
@ -66,6 +71,8 @@ public final class DCodeEmitter : CodeEmitter
/* VariableDeclaration */
else if(cast(VariableDeclaration)instruction)
{
gprintln("type: VariableDeclaration");
VariableDeclaration varDecInstr = cast(VariableDeclaration)instruction;
Context context = varDecInstr.getContext();
@ -89,6 +96,7 @@ public final class DCodeEmitter : CodeEmitter
varDecWantsConsumeVarAss = true;
// Fetch the variable assignment instruction
gprintln("Before crash: "~to!(string)(getCurrentInstruction()));
nextInstruction();
Instruction varAssInstr = getCurrentInstruction();
@ -103,6 +111,8 @@ public final class DCodeEmitter : CodeEmitter
/* LiteralValue */
else if(cast(LiteralValue)instruction)
{
gprintln("type: LiteralValue");
LiteralValue literalValueInstr = cast(LiteralValue)instruction;
return to!(string)(literalValueInstr.data);
@ -110,6 +120,8 @@ public final class DCodeEmitter : CodeEmitter
/* FetchValueVar */
else if(cast(FetchValueVar)instruction)
{
gprintln("type: FetchValueVar");
FetchValueVar fetchValueVarInstr = cast(FetchValueVar)instruction;
Context context = fetchValueVarInstr.getContext();
@ -123,10 +135,56 @@ public final class DCodeEmitter : CodeEmitter
/* BinOpInstr */
else if(cast(BinOpInstr)instruction)
{
gprintln("type: BinOpInstr");
BinOpInstr binOpInstr = cast(BinOpInstr)instruction;
return transform(binOpInstr.lhs)~to!(string)(getCharacter(binOpInstr.operator))~transform(binOpInstr.rhs);
}
/* FuncCallInstr */
else if(cast(FuncCallInstr)instruction)
{
gprintln("type: FuncCallInstr");
FuncCallInstr funcCallInstr = cast(FuncCallInstr)instruction;
Context context = funcCallInstr.getContext();
assert(context);
Function functionToCall = cast(Function)context.tc.getResolver().resolveBest(context.getContainer(), funcCallInstr.functionName); //TODO: Remove `auto`
// TODO: SymbolLookup?
string emit = functionToCall.getName()~"(";
//TODO: Insert argument passimng code here
//NOTE: Typechecker must have checked for passing arguments to a function that doesn't take any, for example
//NOTE (Behaviour): We may want to actually have an preinliner for these arguments
//such to enforce a certain ordering. I believe this should be done in the emitter stage,
//so it is best placed here
if(functionToCall.hasParams())
{
Value[] argumentInstructions = funcCallInstr.getEvaluationInstructions();
string argumentString;
for(ulong argIdx = 0; argIdx < argumentInstructions.length; argIdx++)
{
Value currentArgumentInstr = argumentInstructions[argIdx];
argumentString~=transform(currentArgumentInstr);
if(argIdx != (argumentInstructions.length-1))
{
argumentString~=", ";
}
}
emit~=argumentString;
}
emit ~= ")";
return emit;
}
return "<TODO: Base emit: "~to!(string)(instruction)~">";
}
@ -139,12 +197,13 @@ public final class DCodeEmitter : CodeEmitter
emitStaticAllocations();
gprintln("Function definitions needed: "~to!(string)(1)); //TODO: fix counter here
emitCodeQueue();
emitFunctionDefinitions();
gprintln("\n\n\n");
emitCodeQueue();
// emitCodeQueue();
gprintln("\n\n\n");
@ -194,6 +253,8 @@ public final class DCodeEmitter : CodeEmitter
{
selectQueue(QueueType.ALLOC_QUEUE);
gprintln("Static allocations needed: "~to!(string)(getQueueLength()));
file.writeln();
}
/**
@ -201,6 +262,8 @@ public final class DCodeEmitter : CodeEmitter
*/
private void emitFunctionDefinitions()
{
gprintln("Function definitions needed: "~to!(string)(getFunctionDefinitionsCount()));
Instruction[][string] functionBodyInstrs = typeChecker.getFunctionBodyCodeQueues();
string[] functionNames = getFunctionDefinitionNames();
@ -210,9 +273,8 @@ public final class DCodeEmitter : CodeEmitter
foreach(string currentFunctioName; functionNames)
{
emitFunctionDefinition(currentFunctioName);
}
file.writeln();
}
}
private string generateSignature(Function func)
@ -251,12 +313,9 @@ public final class DCodeEmitter : CodeEmitter
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);
gprintln("emotFunctionDefinition(): Function: "~functionName~", with "~to!(string)(getSelectedQueueLength())~" many instructions");
//TODO: Look at nested definitions or nah? (Context!!)
//TODO: And what about methods defined in classes? Those should technically be here too
@ -296,15 +355,23 @@ public final class DCodeEmitter : CodeEmitter
nextInstruction();
}
file.writeln();
}
private void emitEntryPoint()
{
//TODO: Implement me
// NOTE: Remove this printf
file.writeln(`
// NOTE: The below is testing code and should be removed
#include<stdio.h>
int main()
{
printf("k: %u\n", t_0c9714cea1ccdfdd0345347c86885620);
banana(1);
printf("k: %u\n", t_0c9714cea1ccdfdd0345347c86885620);
return 0;
}`);
}
@ -326,21 +393,18 @@ int main()
//NOTE: Change to system compiler (maybe, we need to choose a good C compiler)
Pid ccPID = spawnProcess(["clang", "-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");
throw new Exception("The CC exited with a non-zero exit code ("~to!(string)(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

@ -244,7 +244,7 @@ public class FuncCallInstr : CallInstr
/* Per-argument instrructions */
private Value[] evaluationInstructions;
private string functionName;
public const string functionName;
this(string functionName, ulong argEvalInstrsSize)
{

View File

@ -713,12 +713,14 @@ public final class TypeChecker
/**
* TODO:
*
* 1. Create FUncCallInstr
* 1. Create FuncCallInstr
* 2. Evaluate args and process them?! wait done elsewhere yeah!!!
* 3. Pop arts into here
* 4. AddInstr(combining those args)
* 5. DOne
*/
funcCallInstr.context = funcCall.getContext();
addInstr(funcCallInstr);
addType(getType(func.parentOf(), func.getType()));
}

View File

@ -410,7 +410,7 @@ public class DNodeGenerator
*
* This holds unique pool entries
*/
private DNode[] nodePool;
private static DNode[] nodePool;
this(TypeChecker tc)
{
@ -582,12 +582,21 @@ public class DNodeGenerator
FunctionCall funcCall = cast(FunctionCall)exp;
gprintln("FuncCall: "~funcCall.getName());
/* TODO: We need to fetch the cached function definition here and call it */
Entity funcEntity = resolver.resolveWithin(context.container, funcCall.getName());
DNode funcDefDNode = retrieveFunctionDefinitionNode(tc.getResolver().generateName(tc.getModule(), funcEntity));
gprintln("FuncCall (FuncDefNode): "~to!(string)(funcDefDNode));
dnode.needs(funcDefDNode); /* NOTE: New code as of 4th October 2022 */
Entity funcEntity = resolver.resolveBest(context.container, funcCall.getName());
assert(funcEntity);
// FIXME: The below is failing (we probably need a forward look ahead?)
// OR use the addFuncDef list?
//WAIT! We don't need a funcDefNode actually. No, we lierally do not.
//Remmeber, they are done in a seperate pass, what we need is just our FUncCall DNode
// WHICH we have below as `dnode`!!!!
// DNode funcDefDNode = retrieveFunctionDefinitionNode(tc.getResolver().generateName(tc.getModule(), funcEntity));
// gprintln("FuncCall (FuncDefNode): "~to!(string)(funcDefDNode));
// dnode.needs(funcDefDNode); /* NOTE: New code as of 4th October 2022 */
//NOTE: Check if we need to set a context here to that of the context we occuring in
funcCall.context = context;
/**
@ -1276,9 +1285,6 @@ public class DNodeGenerator
{
VariableAssignmentStdAlone vAsStdAl = cast(VariableAssignmentStdAlone)entity;
/* Set the Context */
vAsStdAl.setContext(context);
/* TODO: CHeck avriable name even */
gprintln("YEAST ENJOYER");
@ -1286,10 +1292,14 @@ public class DNodeGenerator
// 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()));
assert(tc.getResolver().resolveBest(c, vAsStdAl.getVariableName()));
gprintln("YEAST ENJOYER");
Variable variable = cast(Variable)tc.getResolver().resolveWithin(c, vAsStdAl.getVariableName());
Variable variable = cast(Variable)tc.getResolver().resolveBest(c, vAsStdAl.getVariableName());
assert(variable);
/* Set the context of the assignment to the Context of the Variable being assigned to */
vAsStdAl.setContext(variable.getContext());
/* Pool the variable */
DNode varDecDNode = pool(variable);
@ -1394,14 +1404,14 @@ public class DNodeGenerator
/* TODO: New code from 1st October */
/* Recurse downwards */
/* FIXME: The context container must be fixed, see passClazz, we pass the euiavlent of `func` in there */
Context funcContext = new Context(tc.getModule(), InitScope.STATIC);
DNode funcDefDNode = generalPass(func, funcContext);
// Context funcContext = new Context(tc.getModule(), InitScope.STATIC);
// DNode funcDefDNode = generalPass(func, funcContext);
/**
* Save the function dnode for lookup later
*/
saveFunctionDefinitionNode(funcDefDNode);
// saveFunctionDefinitionNode(funcDefDNode);
}
}

View File

@ -3,7 +3,7 @@ module simple_function_decls;
int j = 21;
int k = 22;
int apple(int j)
int apple(int j, int arg2)
{
int h = 69;
}
@ -11,5 +11,7 @@ int apple(int j)
int banana(int j)
{
int h = 64;
k=1;
k=1+h+apple(1, apple(2, 3));
}