diff --git a/source/tlang/compiler/codegen/emit/dgen.d b/source/tlang/compiler/codegen/emit/dgen.d index 07e23135..7860fd28 100644 --- a/source/tlang/compiler/codegen/emit/dgen.d +++ b/source/tlang/compiler/codegen/emit/dgen.d @@ -271,6 +271,34 @@ public final class DCodeEmitter : CodeEmitter return emit; } + /** + * While loops (WhileLoopInstruction) + */ + else if(cast(WhileLoopInstruction)instruction) + { + WhileLoopInstruction whileLoopInstr = cast(WhileLoopInstruction)instruction; + + BranchInstruction branchInstr = whileLoopInstr.getBranchInstruction(); + Value conditionInstr = branchInstr.getConditionInstr(); + Instruction[] bodyInstructions = branchInstr.getBodyInstructions(); + + string emit; + + /* Generate the `while()` and opening curly brace */ + emit = "while("~transform(conditionInstr)~")\n"; + emit~=genTabs(transformDepth)~"{\n"; + + /* Transform each body statement */ + foreach(Instruction curBodyInstr; bodyInstructions) + { + emit~=genTabs(transformDepth)~"\t"~transform(curBodyInstr)~"\n"; + } + + /* Closing curly brace */ + emit~=genTabs(transformDepth)~"}"; + + return emit; + } return ""; } @@ -451,17 +479,35 @@ public final class DCodeEmitter : CodeEmitter { //TODO: Implement me + // Test for `simple_functions.t` (function call testing) if(cmp(typeChecker.getModule().getName(), "simple_functions") == 0) { - // NOTE: Remove this printf - file.writeln(` -// NOTE: The below is testing code and should be removed + file.writeln(` #include +#include int main() { + assert(t_7b6d477c5859059f16bc9da72fc8cc3b == 22); printf("k: %u\n", t_7b6d477c5859059f16bc9da72fc8cc3b); + banana(1); + assert(t_7b6d477c5859059f16bc9da72fc8cc3b == 72); printf("k: %u\n", t_7b6d477c5859059f16bc9da72fc8cc3b); + + return 0; +}`); + } + else if(cmp(typeChecker.getModule().getName(), "simple_while") == 0) + { + file.writeln(` +#include +#include +int main() +{ + int result = function(3); + printf("result: %d\n", result); + assert(result == 3); + return 0; }`); } diff --git a/source/tlang/compiler/codegen/instruction.d b/source/tlang/compiler/codegen/instruction.d index ab4de752..97441f0a 100644 --- a/source/tlang/compiler/codegen/instruction.d +++ b/source/tlang/compiler/codegen/instruction.d @@ -318,6 +318,23 @@ public final class IfStatementInstruction : Instruction } } +public final class WhileLoopInstruction : Instruction +{ + private BranchInstruction branchInstruction; + + this(BranchInstruction branchInstruction) + { + this.branchInstruction = branchInstruction; + + addInfo = "Branch: "~to!(string)(branchInstruction); + } + + public BranchInstruction getBranchInstruction() + { + return branchInstruction; + } +} + public final class BranchInstruction : Instruction { private Value branchConditionInstr; diff --git a/source/tlang/compiler/parsing/core.d b/source/tlang/compiler/parsing/core.d index 984fcc35..e410fce8 100644 --- a/source/tlang/compiler/parsing/core.d +++ b/source/tlang/compiler/parsing/core.d @@ -217,15 +217,19 @@ public final class Parser /* Create the if statement with the branches */ ifStmt = new IfStatement(branches); + /* Parent the branches to the IfStatement */ parentToContainer(ifStmt, cast(Statement[])branches); return ifStmt; } - private void parseWhile() + private WhileLoop parseWhile() { gprintln("parseWhile(): Enter", DebugType.WARNING); + Expression branchCondition; + Statement[] branchBody; + /* Pop off the `while` */ nextToken(); @@ -234,7 +238,7 @@ public final class Parser nextToken(); /* Parse an expression (for the condition) */ - parseExpression(); + branchCondition = parseExpression(); expect(SymbolType.RBRACE, getCurrentToken()); /* Openening { */ @@ -242,11 +246,26 @@ public final class Parser expect(SymbolType.OCURLY, getCurrentToken()); /* Parse the while' statement's body AND expect a closing curly */ - parseBody(); + branchBody = parseBody(); expect(SymbolType.CCURLY, getCurrentToken()); nextToken(); + + /* Create a Branch node coupling the condition and body statements */ + Branch branch = new Branch(branchCondition, branchBody); + + /* Parent the branchBody to the branch */ + parentToContainer(branch, branchBody); + + /* Create the while loop with the single branch */ + WhileLoop whileLoop = new WhileLoop(branch); + + /* Parent the branch to the WhileLoop */ + parentToContainer(whileLoop, [branch]); + gprintln("parseWhile(): Leave", DebugType.WARNING); + + return whileLoop; } public VariableAssignmentStdAlone parseAssignment() @@ -524,7 +543,7 @@ public final class Parser /* If it is a while loop */ else if (symbol == SymbolType.WHILE) { - parseWhile(); + statements ~= parseWhile(); } /* If it is a function call (further inspection needed) */ else if (symbol == SymbolType.IDENT_TYPE) diff --git a/source/tlang/compiler/symbols/data.d b/source/tlang/compiler/symbols/data.d index 6d312a6e..9dd19285 100644 --- a/source/tlang/compiler/symbols/data.d +++ b/source/tlang/compiler/symbols/data.d @@ -153,10 +153,14 @@ public class Assignment : Statement } } -/* Declared variables, defined classes and fucntions */ +/** + * Entity + * + * Declared variables, defined classes and functions + */ public class Entity : Statement { - /* Accesor type */ + /* Accessor type */ private AccessorType accessorType = AccessorType.PUBLIC; /* Function/Modifier type */ @@ -194,16 +198,6 @@ public class Entity : Statement { return name; } - - private Entity[] deps; - public Entity[] getDeps() - { - return deps; - } - public void addDep(Entity entity) - { - deps ~= entity; - } } /* TODO: DO we need intermediary class, TypedEntity */ @@ -533,6 +527,12 @@ public final class FunctionCall : Call } } +/** + * ReturnStmt + * + * Represents a return statement with an expression + * to be returned + */ public final class ReturnStmt : Statement { // The Expression being returned @@ -554,6 +554,9 @@ public final class ReturnStmt : Statement /** * IfStatement + * + * Represents an if statement with branches of code + * and conditions per each */ public final class IfStatement : Entity, Container { @@ -597,6 +600,74 @@ public final class IfStatement : Entity, Container } } +/** + * WhileLoop + * + * Represents a while loop with conditional code + */ +public final class WhileLoop : Entity, Container +{ + private Branch branch; + private static ulong whileStmtContainerRollingNameCounter = 0; + public const bool isDoWhile; + + /** + * Creates a new While Loop parser node, optionally specifying + * if this is to be interpreted (in-post) as a while-loop + * or do-while loop + * + * Params: + * branch = The Branch that makes up this while + * loop + * isDoWhile = If true then interpret this as a + * do-while loop, however if false + * then a while-loop (default optional value) + */ + this(Branch branch, bool isDoWhile = false) + { + whileStmtContainerRollingNameCounter++; + super("whileStmt_"~to!(string)(whileStmtContainerRollingNameCounter)); + + this.branch = branch; + this.isDoWhile = isDoWhile; + + weight = 2; + } + + public Branch getBranch() + { + return branch; + } + + public override void addStatement(Statement statement) + { + // You should only be adding one branch to a while loop + assert(branch is null); + branch = cast(Branch)statement; + } + + public override void addStatements(Statement[] statements) + { + // Only one Branch in the given input list + assert(statements.length == 1); + + // You should only be adding one branch to a while loop + assert(branch is null); + + branch = (cast(Branch[])statements)[0]; + } + + public override Statement[] getStatements() + { + return cast(Statement[])[branch]; + } + + public override string toString() + { + return "WhileLoop"; + } +} + /** * Branch * @@ -613,6 +684,15 @@ public final class Branch : Entity, Container private static ulong branchContainerRollingNameCounter = 0; + /** + * Creates a new Branch which will couple a condition + * as an instance of Expression and a body + * of Statement(s) apart of it + * + * Params: + * condition = The condition as an Expression + * branch = The body of Statement(s) making up the branch + */ this(Expression condition, Statement[] branch) { branchContainerRollingNameCounter++; @@ -620,7 +700,6 @@ public final class Branch : Entity, Container this.branchCondition = condition; this.branchBody = branch; - } /** @@ -634,18 +713,22 @@ public final class Branch : Entity, Container return !(branchCondition is null); } + /** + * Returns the condition of the branch + * + * Returns: The condition as an instance of Expression + */ public Expression getCondition() { return branchCondition; } + public Statement[] getBody() { return branchBody; } - - public override void addStatement(Statement statement) { branchBody ~= statement; diff --git a/source/tlang/compiler/typecheck/core.d b/source/tlang/compiler/typecheck/core.d index 0bc3fa41..0790cc48 100644 --- a/source/tlang/compiler/typecheck/core.d +++ b/source/tlang/compiler/typecheck/core.d @@ -955,7 +955,7 @@ public final class TypeChecker } } - // TODO: Reverse the list to be in the correct order (it was computed backwards) + // Reverse the list to be in the correct order (it was computed backwards) branchInstructions=reverse(branchInstructions); /** @@ -971,6 +971,50 @@ public final class TypeChecker gprintln("If!"); } + /** + * While loop (WhileLoop) + */ + else if(cast(WhileLoop)statement) + { + WhileLoop whileLoop = cast(WhileLoop)statement; + + Branch branch = whileLoop.getBranch(); + + /* The condition `Value` instruction should be on the stack */ + Value valueInstrCondition = cast(Value)popInstr(); + assert(valueInstrCondition); + + /* Process the body of the while-loop with tail-popping followed by a reverse */ + Instruction[] bodyInstructions; + ulong bodyLen = branch.getBody().length; + ulong bodyIdx = 0; + + while(bodyIdx < bodyLen) + { + Instruction bodyInstr = tailPopInstr(); + bodyInstructions~=bodyInstr; + bodyIdx++; + } + + // Reverse the list to be in the correct order (it was computed backwards) + bodyInstructions=reverse(bodyInstructions); + + + // Create a branch instruction coupling the condition instruction + body instructions (in corrected order) + BranchInstruction branchInstr = new BranchInstruction(valueInstrCondition, bodyInstructions); + + + /** + * Code gen + * + * 1. Create the WhileLoopInstruction containing the BranchInstruction + * 2. Set the context + * 3. Add the instruction + */ + WhileLoopInstruction whileLoopInstruction = new WhileLoopInstruction(branchInstr); + whileLoopInstruction.context = whileLoop.getContext(); + addInstrB(whileLoopInstruction); + } /* Branch */ else if(cast(Branch)statement) { diff --git a/source/tlang/compiler/typecheck/dependency/core.d b/source/tlang/compiler/typecheck/dependency/core.d index ffc2bb13..536862b3 100644 --- a/source/tlang/compiler/typecheck/dependency/core.d +++ b/source/tlang/compiler/typecheck/dependency/core.d @@ -1401,6 +1401,55 @@ public class DNodeGenerator /* Make this container depend on this if statement */ node.needs(ifStatementDNode); } + /** + * While loops + */ + else if(cast(WhileLoop)entity) + { + WhileLoop whileLoopStmt = cast(WhileLoop)entity; + whileLoopStmt.setContext(context); + DNode whileLoopDNode = pool(whileLoopStmt); + + // Extract the branch (body Statement[] + condition) + Branch whileBranch = whileLoopStmt.getBranch(); + DNode branchDNode = pool(whileBranch); + gprintln("Branch: "~to!(string)(whileBranch)); + + // If this is a while-loop + if(!whileLoopStmt.isDoWhile) + { + gprintln("Logan", DebugType.ERROR); + + // Extract the condition + Expression branchCondition = whileBranch.getCondition(); + + // Pass the expression + DNode branchConditionDNode = expressionPass(branchCondition, context); + + // Make the branch dependent on this expression's evaluation + branchDNode.needs(branchConditionDNode); + + + // Now pass over the statements in the branch's body + Context branchContext = new Context(whileBranch, InitScope.STATIC); + DNode branchBodyDNode = generalPass(whileBranch, branchContext); + + // Finally make the branchDNode depend on the body dnode (above) + branchDNode.needs(branchBodyDNode); + } + // If this is a do-while loop + else + { + gprintln("Implement do-while loops please", DebugType.ERROR); + assert(false); + } + + /* Make the while-loop/do-while loop depend on the branchDNode */ + whileLoopDNode.needs(branchDNode); + + /* Make the node of this generalPass we are in depend on the whileLoop's DNode */ + node.needs(whileLoopDNode); + } } return node; diff --git a/source/tlang/testing/simple_while.t b/source/tlang/testing/simple_while.t index 94fc3cd1..bd909aa2 100644 --- a/source/tlang/testing/simple_while.t +++ b/source/tlang/testing/simple_while.t @@ -1,11 +1,20 @@ module simple_while; -int main() +int function(int i) { - int j = 0; - j=2; - while(j < 10) + int test = 0; + + while(i) { - j = j + 1; + int p = 1; + int f = 2; + f = p+f; + + i = i - 1; + test = i + test; } -} + + int j = 2; + + return test; +} \ No newline at end of file