From 2a12c310a66e42783a524cd58f040454c1c36197 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Fri, 16 Dec 2022 14:53:33 +0200 Subject: [PATCH] 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` --- source/tlang/compiler/codegen/emit/core.d | 70 ++++---------- source/tlang/compiler/codegen/emit/dgen.d | 92 ++++++++++++++++--- source/tlang/compiler/codegen/instruction.d | 2 +- source/tlang/compiler/typecheck/core.d | 4 +- .../compiler/typecheck/dependency/core.d | 38 +++++--- source/tlang/testing/simple_function_decls.t | 6 +- 6 files changed, 127 insertions(+), 85 deletions(-) diff --git a/source/tlang/compiler/codegen/emit/core.d b/source/tlang/compiler/codegen/emit/core.d index 0d2e408e..6ef09bc7 100644 --- a/source/tlang/compiler/codegen/emit/core.d +++ b/source/tlang/compiler/codegen/emit/core.d @@ -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; diff --git a/source/tlang/compiler/codegen/emit/dgen.d b/source/tlang/compiler/codegen/emit/dgen.d index c34ac88c..b0f4f029 100644 --- a/source/tlang/compiler/codegen/emit/dgen.d +++ b/source/tlang/compiler/codegen/emit/dgen.d @@ -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 ""; } @@ -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 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); - } } } \ No newline at end of file diff --git a/source/tlang/compiler/codegen/instruction.d b/source/tlang/compiler/codegen/instruction.d index 3cab4f20..b8f85fca 100644 --- a/source/tlang/compiler/codegen/instruction.d +++ b/source/tlang/compiler/codegen/instruction.d @@ -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) { diff --git a/source/tlang/compiler/typecheck/core.d b/source/tlang/compiler/typecheck/core.d index d1ae0ad6..54e9d1fe 100644 --- a/source/tlang/compiler/typecheck/core.d +++ b/source/tlang/compiler/typecheck/core.d @@ -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())); } diff --git a/source/tlang/compiler/typecheck/dependency/core.d b/source/tlang/compiler/typecheck/dependency/core.d index d934ac96..905585f0 100644 --- a/source/tlang/compiler/typecheck/dependency/core.d +++ b/source/tlang/compiler/typecheck/dependency/core.d @@ -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); } } diff --git a/source/tlang/testing/simple_function_decls.t b/source/tlang/testing/simple_function_decls.t index e8ec7f40..3f78bdc1 100644 --- a/source/tlang/testing/simple_function_decls.t +++ b/source/tlang/testing/simple_function_decls.t @@ -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)); + } \ No newline at end of file