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

View File

@ -33,15 +33,20 @@ public final class DCodeEmitter : CodeEmitter
public override string transform(const Instruction instruction) public override string transform(const Instruction instruction)
{ {
import std.stdio;
writeln("\n");
gprintln("transform(): "~to!(string)(instruction)); gprintln("transform(): "~to!(string)(instruction));
/* VariableAssignmentInstr */ /* VariableAssignmentInstr */
if(cast(VariableAssignmentInstr)instruction) if(cast(VariableAssignmentInstr)instruction)
{ {
gprintln("type: VariableAssignmentInstr");
VariableAssignmentInstr varAs = cast(VariableAssignmentInstr)instruction; VariableAssignmentInstr varAs = cast(VariableAssignmentInstr)instruction;
Context context = varAs.getContext(); Context context = varAs.getContext();
gprintln("Is ContextNull?: "~to!(string)(context is null)); 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` 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);
@ -66,6 +71,8 @@ public final class DCodeEmitter : CodeEmitter
/* VariableDeclaration */ /* VariableDeclaration */
else if(cast(VariableDeclaration)instruction) else if(cast(VariableDeclaration)instruction)
{ {
gprintln("type: VariableDeclaration");
VariableDeclaration varDecInstr = cast(VariableDeclaration)instruction; VariableDeclaration varDecInstr = cast(VariableDeclaration)instruction;
Context context = varDecInstr.getContext(); Context context = varDecInstr.getContext();
@ -89,6 +96,7 @@ public final class DCodeEmitter : CodeEmitter
varDecWantsConsumeVarAss = true; varDecWantsConsumeVarAss = true;
// Fetch the variable assignment instruction // Fetch the variable assignment instruction
gprintln("Before crash: "~to!(string)(getCurrentInstruction()));
nextInstruction(); nextInstruction();
Instruction varAssInstr = getCurrentInstruction(); Instruction varAssInstr = getCurrentInstruction();
@ -103,6 +111,8 @@ public final class DCodeEmitter : CodeEmitter
/* LiteralValue */ /* LiteralValue */
else if(cast(LiteralValue)instruction) else if(cast(LiteralValue)instruction)
{ {
gprintln("type: LiteralValue");
LiteralValue literalValueInstr = cast(LiteralValue)instruction; LiteralValue literalValueInstr = cast(LiteralValue)instruction;
return to!(string)(literalValueInstr.data); return to!(string)(literalValueInstr.data);
@ -110,6 +120,8 @@ public final class DCodeEmitter : CodeEmitter
/* FetchValueVar */ /* FetchValueVar */
else if(cast(FetchValueVar)instruction) else if(cast(FetchValueVar)instruction)
{ {
gprintln("type: FetchValueVar");
FetchValueVar fetchValueVarInstr = cast(FetchValueVar)instruction; FetchValueVar fetchValueVarInstr = cast(FetchValueVar)instruction;
Context context = fetchValueVarInstr.getContext(); Context context = fetchValueVarInstr.getContext();
@ -123,10 +135,56 @@ public final class DCodeEmitter : CodeEmitter
/* BinOpInstr */ /* BinOpInstr */
else if(cast(BinOpInstr)instruction) else if(cast(BinOpInstr)instruction)
{ {
gprintln("type: BinOpInstr");
BinOpInstr binOpInstr = cast(BinOpInstr)instruction; BinOpInstr binOpInstr = cast(BinOpInstr)instruction;
return transform(binOpInstr.lhs)~to!(string)(getCharacter(binOpInstr.operator))~transform(binOpInstr.rhs); 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)~">"; return "<TODO: Base emit: "~to!(string)(instruction)~">";
} }
@ -139,12 +197,13 @@ public final class DCodeEmitter : CodeEmitter
emitStaticAllocations(); emitStaticAllocations();
gprintln("Function definitions needed: "~to!(string)(1)); //TODO: fix counter here emitCodeQueue();
emitFunctionDefinitions(); emitFunctionDefinitions();
gprintln("\n\n\n"); gprintln("\n\n\n");
emitCodeQueue(); // emitCodeQueue();
gprintln("\n\n\n"); gprintln("\n\n\n");
@ -194,6 +253,8 @@ public final class DCodeEmitter : CodeEmitter
{ {
selectQueue(QueueType.ALLOC_QUEUE); selectQueue(QueueType.ALLOC_QUEUE);
gprintln("Static allocations needed: "~to!(string)(getQueueLength())); gprintln("Static allocations needed: "~to!(string)(getQueueLength()));
file.writeln();
} }
/** /**
@ -201,6 +262,8 @@ public final class DCodeEmitter : CodeEmitter
*/ */
private void emitFunctionDefinitions() private void emitFunctionDefinitions()
{ {
gprintln("Function definitions needed: "~to!(string)(getFunctionDefinitionsCount()));
Instruction[][string] functionBodyInstrs = typeChecker.getFunctionBodyCodeQueues(); Instruction[][string] functionBodyInstrs = typeChecker.getFunctionBodyCodeQueues();
string[] functionNames = getFunctionDefinitionNames(); string[] functionNames = getFunctionDefinitionNames();
@ -210,9 +273,8 @@ public final class DCodeEmitter : CodeEmitter
foreach(string currentFunctioName; functionNames) foreach(string currentFunctioName; functionNames)
{ {
emitFunctionDefinition(currentFunctioName); emitFunctionDefinition(currentFunctioName);
file.writeln();
} }
} }
private string generateSignature(Function func) private string generateSignature(Function func)
@ -251,13 +313,10 @@ public final class DCodeEmitter : CodeEmitter
private void emitFunctionDefinition(string functionName) 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); 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: Look at nested definitions or nah? (Context!!)
//TODO: And what about methods defined in classes? Those should technically be here too //TODO: And what about methods defined in classes? Those should technically be here too
Function functionEntity = cast(Function)typeChecker.getResolver().resolveBest(typeChecker.getModule(), functionName); //TODO: Remove `auto` Function functionEntity = cast(Function)typeChecker.getResolver().resolveBest(typeChecker.getModule(), functionName); //TODO: Remove `auto`
@ -296,15 +355,23 @@ public final class DCodeEmitter : CodeEmitter
nextInstruction(); nextInstruction();
} }
file.writeln();
} }
private void emitEntryPoint() private void emitEntryPoint()
{ {
//TODO: Implement me //TODO: Implement me
// NOTE: Remove this printf
file.writeln(` file.writeln(`
// NOTE: The below is testing code and should be removed
#include<stdio.h>
int main() int main()
{ {
printf("k: %u\n", t_0c9714cea1ccdfdd0345347c86885620);
banana(1);
printf("k: %u\n", t_0c9714cea1ccdfdd0345347c86885620);
return 0; return 0;
}`); }`);
} }
@ -326,21 +393,18 @@ int main()
//NOTE: Change to system compiler (maybe, we need to choose a good C compiler) //NOTE: Change to system compiler (maybe, we need to choose a good C compiler)
Pid ccPID = spawnProcess(["clang", "-o", "tlang.out", file.name()]); 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); int code = wait(ccPID);
gprintln(code);
if(code) if(code)
{ {
//NOTE: Make this a TLang exception //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) catch(ProcessException e)
{ {
gprintln("NOTE: Case where it exited and Pid now inavlid (if it happens it would throw processexception surely)?", DebugType.ERROR); gprintln("NOTE: Case where it exited and Pid now inavlid (if it happens it would throw processexception surely)?", DebugType.ERROR);
assert(false); assert(false);
} }
} }
} }

View File

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

View File

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

View File

@ -410,7 +410,7 @@ public class DNodeGenerator
* *
* This holds unique pool entries * This holds unique pool entries
*/ */
private DNode[] nodePool; private static DNode[] nodePool;
this(TypeChecker tc) this(TypeChecker tc)
{ {
@ -582,12 +582,21 @@ public class DNodeGenerator
FunctionCall funcCall = cast(FunctionCall)exp; FunctionCall funcCall = cast(FunctionCall)exp;
gprintln("FuncCall: "~funcCall.getName()); gprintln("FuncCall: "~funcCall.getName());
/* TODO: We need to fetch the cached function definition here and call it */ /* TODO: We need to fetch the cached function definition here and call it */
Entity funcEntity = resolver.resolveWithin(context.container, funcCall.getName()); Entity funcEntity = resolver.resolveBest(context.container, funcCall.getName());
DNode funcDefDNode = retrieveFunctionDefinitionNode(tc.getResolver().generateName(tc.getModule(), funcEntity)); assert(funcEntity);
gprintln("FuncCall (FuncDefNode): "~to!(string)(funcDefDNode));
dnode.needs(funcDefDNode); /* NOTE: New code as of 4th October 2022 */ // 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; VariableAssignmentStdAlone vAsStdAl = cast(VariableAssignmentStdAlone)entity;
/* Set the Context */
vAsStdAl.setContext(context);
/* TODO: CHeck avriable name even */ /* TODO: CHeck avriable name even */
gprintln("YEAST ENJOYER"); gprintln("YEAST ENJOYER");
@ -1286,10 +1292,14 @@ public class DNodeGenerator
// FIXME: The below assert fails for function definitions trying to refer to global values // 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, // 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) // 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"); 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); assert(variable);
/* Set the context of the assignment to the Context of the Variable being assigned to */
vAsStdAl.setContext(variable.getContext());
/* Pool the variable */ /* Pool the variable */
DNode varDecDNode = pool(variable); DNode varDecDNode = pool(variable);
@ -1394,14 +1404,14 @@ public class DNodeGenerator
/* TODO: New code from 1st October */ /* TODO: New code from 1st October */
/* Recurse downwards */ /* Recurse downwards */
/* FIXME: The context container must be fixed, see passClazz, we pass the euiavlent of `func` in there */ /* 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); // Context funcContext = new Context(tc.getModule(), InitScope.STATIC);
DNode funcDefDNode = generalPass(func, funcContext); // DNode funcDefDNode = generalPass(func, funcContext);
/** /**
* Save the function dnode for lookup later * 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 j = 21;
int k = 22; int k = 22;
int apple(int j) int apple(int j, int arg2)
{ {
int h = 69; int h = 69;
} }
@ -11,5 +11,7 @@ int apple(int j)
int banana(int j) int banana(int j)
{ {
int h = 64; int h = 64;
k=1;
k=1+h+apple(1, apple(2, 3));
} }