From ec7d8cf4240b24a2f6fdbd8071195c9efe08d573 Mon Sep 17 00:00:00 2001 From: "Tristan B. Velloza Kildaire" Date: Wed, 11 Jan 2023 10:43:29 +0200 Subject: [PATCH] Instruction - Added a new instruction, `ForLoop`, which contains a pre-run Instruction and a `Branch` instruction, coupled with some flags DGen - Added a TODO for WhileLoops (we need to implement do-while loops) - Implemented C code emitting in `emit()` for `ForLoop` instruction Check - Added missing back-mapping for `SymbolType.SMALLER_THAN` Data - Added new parser node type `ForLoop` Parser - Fixed typo in `parseWhile()` - Implemented `parseDoWhile()` for do-while loops - Implemented `parseFor()` for for-loops - Implemented `parseStatement()` for singular statement parsing - `parseStatement()` can now have the terminating symbol specified, defaults to `SymbolType.SEMICOLON` - `parseName()` and `parseAssignment()` now also accept a terminating symbol parameter as per `parseStatement()`'s behavior - `parseBody()` now makes multiple calls to `parseStatement()` for singular Statement parsing (dead code below still to be removed) - Removed commented-out unittests - Unittests that read from files now have the file source code embedded - Added unit test for while loops, for-loops (unfinished) and some other smaller language constructs (roughly 70% coverage) TypeChecker (CodeGen) - Do-while loops will fail if used (for now) - Added for-loop code generation Dependency - Implemented `generalStatement()` for statement processing - `generalPass()` now makes calls to `generalStatement()` Tests - Added `simple_for_loops.t` to test for-loops - Added `simple_do_while.t` to test do-while loops --- source/tlang/compiler/codegen/emit/dgen.d | 54 ++ source/tlang/compiler/codegen/instruction.d | 37 + source/tlang/compiler/parsing/core.d | 800 +++++++++++++++--- source/tlang/compiler/symbols/check.d | 4 + source/tlang/compiler/symbols/data.d | 87 ++ source/tlang/compiler/typecheck/core.d | 53 ++ .../compiler/typecheck/dependency/core.d | 619 ++++++++------ source/tlang/testing/simple_do_while.t | 14 + source/tlang/testing/simple_for_loops.t | 13 + 9 files changed, 1304 insertions(+), 377 deletions(-) create mode 100644 source/tlang/testing/simple_do_while.t create mode 100644 source/tlang/testing/simple_for_loops.t diff --git a/source/tlang/compiler/codegen/emit/dgen.d b/source/tlang/compiler/codegen/emit/dgen.d index 7860fd28..ec9de257 100644 --- a/source/tlang/compiler/codegen/emit/dgen.d +++ b/source/tlang/compiler/codegen/emit/dgen.d @@ -273,6 +273,8 @@ public final class DCodeEmitter : CodeEmitter } /** * While loops (WhileLoopInstruction) + * + * TODO: Add do-while check */ else if(cast(WhileLoopInstruction)instruction) { @@ -299,6 +301,44 @@ public final class DCodeEmitter : CodeEmitter return emit; } + /** + * For loops (ForLoopInstruction) + */ + else if(cast(ForLoopInstruction)instruction) + { + ForLoopInstruction forLoopInstr = cast(ForLoopInstruction)instruction; + + BranchInstruction branchInstruction = forLoopInstr.getBranchInstruction(); + Value conditionInstr = branchInstruction.getConditionInstr(); + Instruction[] bodyInstructions = branchInstruction.getBodyInstructions(); + + string emit = "for("; + + // Emit potential pre-run instruction + emit ~= forLoopInstr.hasPreRunInstruction() ? transform(forLoopInstr.getPreRunInstruction()) : ";"; + + // Condition + emit ~= transform(conditionInstr)~";"; + + // NOTE: We are leaving the post-iteration blank due to us including it in the body + // TODO: We can hoist bodyInstructions[$] maybe if we want to generate it as C-for-loops + // if(forLoopInstr.hasPostIterationInstruction()) + emit ~= ")\n"; + + // Open curly (begin body) + emit~=genTabs(transformDepth)~"{\n"; + + /* Transform each body statement */ + foreach(Instruction curBodyInstr; bodyInstructions) + { + emit~=genTabs(transformDepth)~"\t"~transform(curBodyInstr)~"\n"; + } + + // Close curly (body end) + emit~=genTabs(transformDepth)~"}"; + + return emit; + } return ""; } @@ -508,6 +548,20 @@ int main() printf("result: %d\n", result); assert(result == 3); + return 0; +}`); + } + else if(cmp(typeChecker.getModule().getName(), "simple_for_loops") == 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 97441f0a..c7b44d18 100644 --- a/source/tlang/compiler/codegen/instruction.d +++ b/source/tlang/compiler/codegen/instruction.d @@ -335,6 +335,43 @@ public final class WhileLoopInstruction : Instruction } } +public final class ForLoopInstruction : Instruction +{ + private Instruction preRunInstruction; + private BranchInstruction branchInstruction; + private bool hasPostIterate; + + this(BranchInstruction branchInstruction, Instruction preRunInstruction = null, bool hasPostIterate = false) + { + this.branchInstruction = branchInstruction; + this.preRunInstruction = preRunInstruction; + + addInfo = (hasPreRunInstruction() ? "PreRun: "~to!(string)(preRunInstruction)~", " : "")~"Branch: "~to!(string)(branchInstruction); + + this.hasPostIterate = hasPostIterate; + } + + public bool hasPostIterationInstruction() + { + return hasPostIterate; + } + + public Instruction getPreRunInstruction() + { + return preRunInstruction; + } + + public bool hasPreRunInstruction() + { + return !(preRunInstruction is null); + } + + 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 e410fce8..f72505fa 100644 --- a/source/tlang/compiler/parsing/core.d +++ b/source/tlang/compiler/parsing/core.d @@ -241,7 +241,7 @@ public final class Parser branchCondition = parseExpression(); expect(SymbolType.RBRACE, getCurrentToken()); - /* Openening { */ + /* Opening { */ nextToken(); expect(SymbolType.OCURLY, getCurrentToken()); @@ -268,7 +268,124 @@ public final class Parser return whileLoop; } - public VariableAssignmentStdAlone parseAssignment() + private WhileLoop parseDoWhile() + { + gprintln("parseDoWhile(): Enter", DebugType.WARNING); + + Expression branchCondition; + Statement[] branchBody; + + /* Pop off the `do` */ + nextToken(); + + /* Expect an opening curly `{` */ + expect(SymbolType.OCURLY, getCurrentToken()); + + /* Parse the do-while statement's body AND expect a closing curly */ + branchBody = parseBody(); + expect(SymbolType.CCURLY, getCurrentToken()); + nextToken(); + + /* Expect a `while` */ + expect(SymbolType.WHILE, getCurrentToken()); + nextToken(); + + /* Expect an opening brace `(` */ + expect(SymbolType.LBRACE, getCurrentToken()); + nextToken(); + + /* Parse the condition */ + branchCondition = parseExpression(); + expect(SymbolType.RBRACE, getCurrentToken()); + nextToken(); + + /* Expect a semicolon */ + expect(SymbolType.SEMICOLON, 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 and marked as a do-while loop */ + WhileLoop whileLoop = new WhileLoop(branch, true); + + /* Parent the branch to the WhileLoop */ + parentToContainer(whileLoop, [branch]); + + gprintln("parseDoWhile(): Leave", DebugType.WARNING); + + return whileLoop; + } + + // TODO: Finish implementing this + // TODO: We need to properly parent and build stuff + // TODO: We ASSUME there is always pre-run, condition and post-iteration + public ForLoop parseFor() + { + gprintln("parseFor(): Enter", DebugType.WARNING); + + Expression branchCondition; + Statement[] branchBody; + + /* Pop of the token `for` */ + nextToken(); + + /* Expect an opening smooth brace `(` */ + expect(SymbolType.LBRACE, getCurrentToken()); + nextToken(); + + /* Expect a single Statement */ + // TODO: Make optional, add parser lookahead check + Statement preRunStatement = parseStatement(); + + /* Expect an expression */ + // TODO: Make optional, add parser lookahead check + branchCondition = parseExpression(); + + /* Expect a semi-colon, then move on */ + expect(SymbolType.SEMICOLON, getCurrentToken()); + nextToken(); + + /* Expect a post-iteration statement with `)` as terminator */ + // TODO: Make optional, add parser lookahead check + Statement postIterationStatement = parseStatement(SymbolType.RBRACE); + + /* Expect an opening curly `{` and parse the body */ + expect(SymbolType.OCURLY, getCurrentToken()); + branchBody = parseBody(); + + /* Expect a closing curly and move on */ + expect(SymbolType.CCURLY, getCurrentToken()); + nextToken(); + + gprintln("Yo: "~getCurrentToken().toString()); + + /* Create the Branch coupling the body statements (+post iteration statement) and condition */ + Branch forBranch = new Branch(branchCondition, branchBody~postIterationStatement); + + /* Create the for loop */ + ForLoop forLoop = new ForLoop(forBranch, preRunStatement); + + // TODO: Set `forLoop.hasPostIterate` + + /* Parent the pre-run statement to its for loop */ + parentToContainer(forLoop, [preRunStatement]); + + /* Parent the body of the branch (body statements + post iteration statement) */ + parentToContainer(forBranch, branchBody~postIterationStatement); + + /* Parent the Branch to its for loop */ + parentToContainer(forLoop, [forBranch]); + + gprintln("parseFor(): Leave", DebugType.WARNING); + + return forLoop; + } + + public VariableAssignmentStdAlone parseAssignment(SymbolType terminatingSymbol = SymbolType.SEMICOLON) { /* Generated Assignment statement */ VariableAssignmentStdAlone assignment; @@ -286,15 +403,18 @@ public final class Parser assignment = new VariableAssignmentStdAlone(identifier, assignmentExpression); /* TODO: Support for (a=1)? */ - /* Expect a semicolon */ - expect(SymbolType.SEMICOLON, getCurrentToken()); + /* Expect a the terminating symbol */ + // expect(SymbolType.SEMICOLON, getCurrentToken()); + expect(terminatingSymbol, getCurrentToken()); + + /* Move off terminating symbol */ nextToken(); return assignment; } - public Statement parseName() + public Statement parseName(SymbolType terminatingSymbol = SymbolType.SEMICOLON) { Statement ret; @@ -328,7 +448,7 @@ public final class Parser else if(type == SymbolType.ASSIGN) { previousToken(); - ret = parseAssignment(); + ret = parseAssignment(terminatingSymbol); } /* Any other case */ else @@ -511,6 +631,12 @@ public final class Parser */ bool closedBeforeExit; + // TODO: Once issue #75 is closed, remove this + bool useParseStatement = true; + + // NOTE: See issue #75 - could we make a general `parseStatement()` + // and then call that in a loop here rather? This would make certain things + // a little easier like where we need to parse only a single statement while (hasTokens()) { /* Get the token */ @@ -519,14 +645,47 @@ public final class Parser gprintln("parseBody(): SymbolType=" ~ to!(string)(symbol)); + // TODO: Once issue #75 is closed, remove this + if(useParseStatement) + { + /* If it is a class definition */ + if(symbol == SymbolType.CLASS) + { + /* Parse the class and add its statements */ + statements ~= parseClass(); + } + /* If it is a struct definition */ + else if(symbol == SymbolType.STRUCT) + { + /* Parse the struct and add it to the statements */ + statements ~= parseStruct(); + } + /* If it is closing the body `}` */ + else if(symbol == SymbolType.CCURLY) + { + gprintln("parseBody(): Exiting body by }", DebugType.WARNING); + + closedBeforeExit = true; + break; + } + else + { + statements ~= parseStatement(); + continue; + } + } + + // TODO: Once issue #75 is closed, remove the below checks + // NOTE: Below coce may become out-dated as we try implement the above + /* If it is a type */ - if (symbol == SymbolType.IDENT_TYPE) + if(symbol == SymbolType.IDENT_TYPE) { /* Might be a function, might be a variable, or assignment */ statements ~= parseName(); } /* If it is an accessor */ - else if (isAccessor(tok)) + else if(isAccessor(tok)) { statements ~= parseAccessor(); } @@ -536,33 +695,36 @@ public final class Parser statements ~= parseInitScope(); } /* If it is a branch */ - else if (symbol == SymbolType.IF) + else if(symbol == SymbolType.IF) { statements ~= parseIf(); } /* If it is a while loop */ - else if (symbol == SymbolType.WHILE) + else if(symbol == SymbolType.WHILE) { statements ~= parseWhile(); } + /* If it is a do-while loop */ + else if(symbol == SymbolType.DO) + { + statements ~= parseDoWhile(); + } /* If it is a function call (further inspection needed) */ - else if (symbol == SymbolType.IDENT_TYPE) + else if(symbol == SymbolType.IDENT_TYPE) { /* Function calls can have dotted identifiers */ parseFuncCall(); } /* If it is closing the body `}` */ - else if (symbol == SymbolType.CCURLY) + else if(symbol == SymbolType.CCURLY) { - // gprintln("Error"); - // nextToken(); gprintln("parseBody(): Exiting body by }", DebugType.WARNING); closedBeforeExit = true; break; } /* If it is a class definition */ - else if (symbol == SymbolType.CLASS) + else if(symbol == SymbolType.CLASS) { /* Parse the class and add its statements */ statements ~= parseClass(); @@ -1442,21 +1604,77 @@ public final class Parser } } - private void parseStatement() + // TODO: This ic currently dead code and ought to be used/implemented + private Statement parseStatement(SymbolType terminatingSymbol = SymbolType.SEMICOLON) { gprintln("parseStatement(): Enter", DebugType.WARNING); - /* TODO: Implement parse statement */ + /* Get the token */ + Token tok = getCurrentToken(); + SymbolType symbol = getSymbolType(tok); - /** - * TODO: We should remove the `;` from parseFuncCall - * And rather do the following here: - * - * 1. parseFuncCall() - * 2. expect(;) - */ + gprintln("parseStatement(): SymbolType=" ~ to!(string)(symbol)); + + Statement statement; + + /* If it is a type */ + if(symbol == SymbolType.IDENT_TYPE) + { + /* Might be a function, might be a variable, or assignment */ + statement = parseName(terminatingSymbol); + } + /* If it is an accessor */ + else if(isAccessor(tok)) + { + statement = parseAccessor(); + } + /* If it is a modifier */ + else if(isModifier(tok)) + { + statement = parseInitScope(); + } + /* If it is a branch */ + else if(symbol == SymbolType.IF) + { + statement = parseIf(); + } + /* If it is a while loop */ + else if(symbol == SymbolType.WHILE) + { + statement = parseWhile(); + } + /* If it is a do-while loop */ + else if(symbol == SymbolType.DO) + { + statement = parseDoWhile(); + } + /* If it is a for loop */ + else if(symbol == SymbolType.FOR) + { + statement = parseFor(); + } + /* If it is a function call (further inspection needed) */ + else if(symbol == SymbolType.IDENT_TYPE) + { + /* Function calls can have dotted identifiers */ + parseFuncCall(); + } + /* If it is the return keyword */ + //TODO: We should add a flag to prevent return being used in generla bodies? or wait we have a non parseBiody already + else if(symbol == SymbolType.RETURN) + { + /* Parse the return statement */ + statement = parseReturn(); + } + /* Error out */ + else + { + expect("parseStatement(): Unknown symbol: " ~ getCurrentToken().getToken()); + } gprintln("parseStatement(): Leave", DebugType.WARNING); + + return statement; } private FunctionCall parseFuncCall() @@ -1633,75 +1851,9 @@ public final class Parser } } -// unittest -// { -// /* TODO: Add some unit tests */ -// import std.file; -// import std.stdio; -// import compiler.lexer; - -// isUnitTest = true; - -// string sourceFile = "source/tlang/testing/basic1.t"; - -// File sourceFileFile; -// sourceFileFile.open(sourceFile); /* TODO: Error handling with ANY file I/O */ -// ulong fileSize = sourceFileFile.size(); -// byte[] fileBytes; -// fileBytes.length = fileSize; -// fileBytes = sourceFileFile.rawRead(fileBytes); -// sourceFileFile.close(); - - - -// /* TODO: Open source file */ -// string sourceCode = cast(string)fileBytes; -// // string sourceCode = "hello \"world\"|| "; -// //string sourceCode = "hello \"world\"||"; /* TODO: Implement this one */ -// // string sourceCode = "hello;"; -// Lexer currentLexer = new Lexer(sourceCode); -// assert(currentLexer.performLex()); - - -// Parser parser = new Parser(currentLexer.getTokens()); -// parser.parse(); -// } - - -unittest -{ - /* TODO: Add some unit tests */ - import std.file; - import std.stdio; - import compiler.lexer; - - isUnitTest = true; - - // string sourceFile = "source/tlang/testing/basic1.t"; - - // File sourceFileFile; - // sourceFileFile.open(sourceFile); /* TODO: Error handling with ANY file I/O */ - // ulong fileSize = sourceFileFile.size(); - // byte[] fileBytes; - // fileBytes.length = fileSize; - // fileBytes = sourceFileFile.rawRead(fileBytes); - // sourceFileFile.close(); - - - - // /* TODO: Open source file */ - // string sourceCode = cast(string)fileBytes; - // // string sourceCode = "hello \"world\"|| "; - // //string sourceCode = "hello \"world\"||"; /* TODO: Implement this one */ - // // string sourceCode = "hello;"; - // Lexer currentLexer = new Lexer(sourceCode); - // assert(currentLexer.performLex()); - - - // Parser parser = new Parser(currentLexer.getTokens()); - // parser.parse(); -} - +/** + * Basic Module test case + */ unittest { @@ -1709,23 +1861,10 @@ unittest import std.stdio; import compiler.lexer; - string sourceFile = "source/tlang/testing/simple1_module_positive.t"; - - File sourceFileFile; - sourceFileFile.open(sourceFile); /* TODO: Error handling with ANY file I/O */ - ulong fileSize = sourceFileFile.size(); - byte[] fileBytes; - fileBytes.length = fileSize; - fileBytes = sourceFileFile.rawRead(fileBytes); - sourceFileFile.close(); + string sourceCode = ` +module myModule; +`; - - - /* TODO: Open source file */ - string sourceCode = cast(string)fileBytes; - // string sourceCode = "hello \"world\"|| "; - //string sourceCode = "hello \"world\"||"; /* TODO: Implement this one */ - // string sourceCode = "hello;"; Lexer currentLexer = new Lexer(sourceCode); assert(currentLexer.performLex()); @@ -1754,20 +1893,28 @@ unittest import compiler.lexer; import compiler.typecheck.core; - string sourceFile = "source/tlang/testing/simple2_name_recognition.t"; - - File sourceFileFile; - sourceFileFile.open(sourceFile); /* TODO: Error handling with ANY file I/O */ - ulong fileSize = sourceFileFile.size(); - byte[] fileBytes; - fileBytes.length = fileSize; - fileBytes = sourceFileFile.rawRead(fileBytes); - sourceFileFile.close(); + string sourceCode = ` +module myModule; +class myClass1 +{ + class myClass1_1 + { + int entity; + } + class myClass2 + { + int inner; + } +} + +class myClass2 +{ + int outer; +} +`; - /* TODO: Open source file */ - string sourceCode = cast(string)fileBytes; Lexer currentLexer = new Lexer(sourceCode); assert(currentLexer.performLex()); @@ -1894,4 +2041,417 @@ unittest { assert(false); } +} + +/** + * Function definition test case + */ +unittest +{ + import std.stdio; + import compiler.lexer; + import compiler.typecheck.core; + + + string sourceCode = ` +module parser_function_def; + +int myFunction(int i, int j) +{ + int k = i + j; + + return k+1; +} +`; + + + Lexer currentLexer = new Lexer(sourceCode); + assert(currentLexer.performLex()); + + + Parser parser = new Parser(currentLexer.getTokens()); + + try + { + Module modulle = parser.parse(); + + /* Module name must be parser_while */ + assert(cmp(modulle.getName(), "parser_function_def")==0); + TypeChecker tc = new TypeChecker(modulle); + + + /* Find the function named `myFunction` */ + Entity func = tc.getResolver().resolveBest(modulle, "myFunction"); + assert(func); + assert(cast(Function)func); // Ensure it is a Funciton + + /* Get the function's body */ + Container funcContainer = cast(Container)func; + assert(funcContainer); + Statement[] functionStatements = funcContainer.getStatements(); + + // Two parameters, 1 local and a return + assert(functionStatements.length == 4); + + /* First statement should be a variable (param) */ + VariableParameter varPar1 = cast(VariableParameter)functionStatements[0]; + assert(varPar1); + assert(cmp(varPar1.getName(), "i") == 0); + + /* Second statement should be a variable (param) */ + VariableParameter varPar2 = cast(VariableParameter)functionStatements[1]; + assert(varPar2); + assert(cmp(varPar2.getName(), "j") == 0); + + /* ThirdFirst statement should be a variable (local) */ + Variable varLocal = cast(Variable)functionStatements[2]; + assert(varLocal); + assert(cmp(varLocal.getName(), "k") == 0); + + /* Last statement should be a return */ + assert(cast(ReturnStmt)functionStatements[3]); + } + catch(TError e) + { + assert(false); + } +} + +/** + * While loop test case (nested) + */ +unittest +{ + import std.stdio; + import compiler.lexer; + import compiler.typecheck.core; + + + string sourceCode = ` +module parser_while; + +void function() +{ + int i = 0; + while(i) + { + int p = i; + + while(i) + { + int f; + } + } +} +`; + + + Lexer currentLexer = new Lexer(sourceCode); + assert(currentLexer.performLex()); + + + Parser parser = new Parser(currentLexer.getTokens()); + + try + { + Module modulle = parser.parse(); + + /* Module name must be parser_while */ + assert(cmp(modulle.getName(), "parser_while")==0); + TypeChecker tc = new TypeChecker(modulle); + + + /* Find the function named `function` */ + Entity func = tc.getResolver().resolveBest(modulle, "function"); + assert(func); + assert(cast(Function)func); // Ensure it is a Funciton + + /* Get the function's body */ + Container funcContainer = cast(Container)func; + assert(funcContainer); + Statement[] functionStatements = funcContainer.getStatements(); + assert(functionStatements.length == 2); + + /* Find the while loop within the function's body */ + WhileLoop potentialWhileLoop; + foreach(Statement curStatement; functionStatements) + { + potentialWhileLoop = cast(WhileLoop)curStatement; + + if(potentialWhileLoop) + { + break; + } + } + + /* This must pass if we found the while loop */ + assert(potentialWhileLoop); + + /* Grab the branch of the while loop */ + Branch whileBranch = potentialWhileLoop.getBranch(); + assert(whileBranch); + + /* Ensure that we have one statement in this branch's body and that it is a Variable and next is a while loop */ + Statement[] whileBranchStatements = whileBranch.getStatements(); + assert(whileBranchStatements.length == 2); + assert(cast(Variable)whileBranchStatements[0]); + assert(cast(WhileLoop)whileBranchStatements[1]); + + /* The inner while loop also has a similiar structure, only one variable */ + WhileLoop innerLoop = cast(WhileLoop)whileBranchStatements[1]; + Branch innerWhileBranch = innerLoop.getBranch(); + assert(innerWhileBranch); + Statement[] innerWhileBranchStatements = innerWhileBranch.getStatements(); + assert(innerWhileBranchStatements.length == 1); + assert(cast(Variable)innerWhileBranchStatements[0]); + } + catch(TError e) + { + assert(false); + } +} + +/** + * Do-while loop tests (TODO: Add this) + */ + +/** + * For loop tests (TODO: Add this) + */ +/** + * While loop test case (nested) + */ +unittest +{ + import std.stdio; + import compiler.lexer; + import compiler.typecheck.core; + + + string sourceCode = ` +module parser_for; + +void function() +{ + int i = 0; + for(int idx = i; idx < i; idx=idx+1) + { + i = i + 1; + + for(int idxInner = idx; idxInner < idx; idxInner = idxInner +1) + { + + } + } +} +`; + + + Lexer currentLexer = new Lexer(sourceCode); + assert(currentLexer.performLex()); + + + Parser parser = new Parser(currentLexer.getTokens()); + + try + { + Module modulle = parser.parse(); + + /* Module name must be parser_while */ + assert(cmp(modulle.getName(), "parser_for")==0); + TypeChecker tc = new TypeChecker(modulle); + + + /* Find the function named `function` */ + Entity func = tc.getResolver().resolveBest(modulle, "function"); + assert(func); + assert(cast(Function)func); // Ensure it is a Funciton + + /* Get the function's body */ + Container funcContainer = cast(Container)func; + assert(funcContainer); + Statement[] functionStatements = funcContainer.getStatements(); + assert(functionStatements.length == 2); + + /* First statement should be a variable declaration */ + assert(cast(Variable)functionStatements[0]); + + /* Next statement should be a for loop */ + ForLoop outerLoop = cast(ForLoop)functionStatements[1]; + assert(outerLoop); + + /* Get the body of the for-loop which should be [preRun, Branch] */ + Statement[] outerLoopBody = outerLoop.getStatements(); + assert(outerLoopBody.length == 2); + + /* We should have a preRun Statement */ + assert(outerLoop.hasPreRunStatement()); + + /* The first should be the [preRun, ] which should be a Variable (declaration) */ + Variable preRunVarDec = cast(Variable)(outerLoopBody[0]); + assert(preRunVarDec); + + /* Next up is the branch */ + Branch outerLoopBranch = cast(Branch)outerLoopBody[1]; + assert(outerLoopBranch); + + /* The branch should have a condition */ + Expression outerLoopBranchCondition = outerLoopBranch.getCondition(); + assert(outerLoopBranchCondition); + + /* The branch should have a body made up of [varAssStdAlone, forLoop, postIteration] */ + Statement[] outerLoopBranchBody = outerLoopBranch.getStatements(); + assert(outerLoopBranchBody.length == 3); + + /* Check for [varAssStdAlone, ] */ + VariableAssignmentStdAlone outerLoopBranchBodyStmt1 = cast(VariableAssignmentStdAlone)outerLoopBranchBody[0]; + assert(outerLoopBranchBodyStmt1); + + /* Check for [, forLoop, ] */ + ForLoop innerLoop = cast(ForLoop)outerLoopBranchBody[1]; + assert(innerLoop); + + /* Check for [, postIteration] */ + VariableAssignmentStdAlone outerLoopBranchBodyStmt3 = cast(VariableAssignmentStdAlone)outerLoopBranchBody[2]; + assert(outerLoopBranchBodyStmt3); + + + // /* The outer loop should have a Variable as pre-run Statement */ + // Statement preRunStatement = outerLoop.getPreLoopStatement(); + // assert(preRunStatement); + // assert(cast(Variable)preRunStatement); + + // /* The outer loop should have a variable assignment as the post-iteration statement */ + // Statement postIrerationStatement = outerLoop.getPreIterationStatement(); + // assert(postIrerationStatement); + // assert(cast(VariableAssignmentStdAlone)postIrerationStatement); + + // /* Extract the statements of the body of the outer loop */ + // Branch outerLoopBranch = outerLoop.getBranch(); + // assert(outerLoopBranch); + // Statement[] outerLoopBody = outerLoopBranch.getStatements(); + // assert(outerLoopBody.length == 2); + + // /* First statement is a VarAssStdAlone */ + // assert(cast(VariableAssignmentStdAlone)outerLoopBody[0]); + + // /* Second statement is a for loop */ + // ForLoop innerLoop = cast(ForLoop)outerLoopBody[1]; + // assert(innerLoop); + + // /* The inner loop should have a Variable as pre-run Statement */ + // Statement innerPreRunStatement = innerLoop.getPreLoopStatement(); + // assert(innerPreRunStatement); + // assert(cast(Variable)innerPreRunStatement); + + // /* The inner loop should have a variable assignment as the post-iteration statement */ + // Statement innerPostIrerationStatement = outerLoop.getPreIterationStatement(); + // assert(innerPostIrerationStatement); + // assert(cast(VariableAssignmentStdAlone)innerPostIrerationStatement); + + // /* Extract the statements of the body of the inner loop */ + // Branch innerLoopBranch = innerLoop.getBranch(); + // assert(innerLoopBranch); + // Statement[] innerLoopBody = innerLoopBranch.getStatements(); + // assert(innerLoopBody.length == 0); + } + catch(TError e) + { + assert(false); + } +} + +/** + * If statement tests + */ +unittest +{ + import std.stdio; + import compiler.lexer; + import compiler.typecheck.core; + + + string sourceCode = ` +module parser_if; + +void function() +{ + int i = 0; + if(i) + { + int p = -i; + } + else if(i) + { + int p = 3+(i*9); + } + else if(i) + { + + } + else + { + + } +} +`; + + + Lexer currentLexer = new Lexer(sourceCode); + assert(currentLexer.performLex()); + + + Parser parser = new Parser(currentLexer.getTokens()); + + try + { + Module modulle = parser.parse(); + + /* Module name must be parser_while */ + assert(cmp(modulle.getName(), "parser_if")==0); + TypeChecker tc = new TypeChecker(modulle); + + /* Find the function named `function` */ + Entity func = tc.getResolver().resolveBest(modulle, "function"); + assert(func); + assert(cast(Function)func); // Ensure it is a Funciton + + /* Get the function's body */ + Container funcContainer = cast(Container)func; + assert(funcContainer); + Statement[] functionStatements = funcContainer.getStatements(); + assert(functionStatements.length == 2); + + /* Second statement is an if statemnet */ + IfStatement ifStatement = cast(IfStatement)functionStatements[1]; + assert(ifStatement); + + /* Extract the branches (should be 4) */ + Branch[] ifStatementBranches = ifStatement.getBranches(); + assert(ifStatementBranches.length == 4); + + /* First branch should have one statement which is a variable declaration */ + Statement[] firstBranchBody = ifStatementBranches[0].getStatements(); + assert(firstBranchBody.length == 1); + assert(cast(Variable)firstBranchBody[0]); + + /* Second branch should have one statement which is a variable declaration */ + Statement[] secondBranchBody = ifStatementBranches[1].getStatements(); + assert(secondBranchBody.length == 1); + assert(cast(Variable)secondBranchBody[0]); + + /* Third branch should have no statements */ + Statement[] thirdBranchBody = ifStatementBranches[2].getStatements(); + assert(thirdBranchBody.length == 0); + + /* Forth branch should have no statements */ + Statement[] fourthBranchBody = ifStatementBranches[3].getStatements(); + assert(fourthBranchBody.length == 0); + + // TODO: @Tristan Add this + } + catch(TError e) + { + assert(false); + } } \ No newline at end of file diff --git a/source/tlang/compiler/symbols/check.d b/source/tlang/compiler/symbols/check.d index ff31fb8c..64ff2a05 100644 --- a/source/tlang/compiler/symbols/check.d +++ b/source/tlang/compiler/symbols/check.d @@ -501,6 +501,10 @@ public string getCharacter(SymbolType symbolIn) { return "=="; } + else if(symbolIn == SymbolType.SMALLER_THAN) + { + return "<"; + } else { gprintln("getCharacter: No back-mapping for "~to!(string)(symbolIn), DebugType.ERROR); diff --git a/source/tlang/compiler/symbols/data.d b/source/tlang/compiler/symbols/data.d index 9dd19285..0b6e3c4b 100644 --- a/source/tlang/compiler/symbols/data.d +++ b/source/tlang/compiler/symbols/data.d @@ -668,6 +668,93 @@ public final class WhileLoop : Entity, Container } } +public final class ForLoop : Entity, Container +{ + private Statement preLoopStatement; + private Branch branch; + private bool hasPostIterate; + private static ulong forStmtContainerRollingNameCounter = 0; + + /** + * Creates a new For Loop parser node + * + * Params: + * + * preLoopStatement = The Statement to run before + * beginning the first iteration + * branch = The Branch that makes up this for + * loop + */ + this(Branch branch, Statement preLoopStatement = null, bool hasPostIterate = false) + { + forStmtContainerRollingNameCounter++; + super("forStmt_"~to!(string)(forStmtContainerRollingNameCounter)); + + this.preLoopStatement = preLoopStatement; + this.branch = branch; + this.hasPostIterate = hasPostIterate; + + weight = 2; + } + + public bool hasPostIterateStatement() + { + return hasPostIterate; + } + + public bool hasPreRunStatement() + { + return !(preLoopStatement is null); + } + + public Branch getBranch() + { + return branch; + } + + public Statement getPreRunStatement() + { + return preLoopStatement; + } + + public override void addStatement(Statement statement) + { + // You should only be adding one branch to a for 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 for loop + assert(branch is null); + + branch = (cast(Branch[])statements)[0]; + } + + public override Statement[] getStatements() + { + // If there is a pre-run statement then prepend it + if(hasPreRunStatement()) + { + return cast(Statement[])[preLoopStatement, branch]; + } + // If not, then just the Branch container + else + { + return cast(Statement[])[branch]; + } + } + + public override string toString() + { + return "ForLoop"; + } +} + /** * Branch * diff --git a/source/tlang/compiler/typecheck/core.d b/source/tlang/compiler/typecheck/core.d index 0790cc48..d7a8fc47 100644 --- a/source/tlang/compiler/typecheck/core.d +++ b/source/tlang/compiler/typecheck/core.d @@ -978,6 +978,13 @@ public final class TypeChecker { WhileLoop whileLoop = cast(WhileLoop)statement; + // FIXME: Do-while loops are still being considered in terms of dependency construction + if(whileLoop.isDoWhile) + { + gprintln("Still looking at dependency construction in this thing (do while loops )"); + assert(false); + } + Branch branch = whileLoop.getBranch(); /* The condition `Value` instruction should be on the stack */ @@ -1015,6 +1022,52 @@ public final class TypeChecker whileLoopInstruction.context = whileLoop.getContext(); addInstrB(whileLoopInstruction); } + /** + * For loop (ForLoop) + */ + else if(cast(ForLoop)statement) + { + ForLoop forLoop = cast(ForLoop)statement; + + /* Pop-off the Value-instruction for the condition */ + Value valueInstrCondition = cast(Value)popInstr(); + assert(valueInstrCondition); + + /* Calculate the number of instructions representing the body to tailPopInstr() */ + ulong bodyTailPopNumber = forLoop.getBranch().getStatements().length; + gprintln("bodyTailPopNumber: "~to!(string)(bodyTailPopNumber)); + + /* Pop off the body instructions, then reverse final list */ + Instruction[] bodyInstructions; + for(ulong idx = 0; idx < bodyTailPopNumber; idx++) + { + bodyInstructions ~= tailPopInstr(); + } + bodyInstructions = reverse(bodyInstructions); + + // Create a branch instruction coupling the condition instruction + body instructions (in corrected order) + BranchInstruction branchInstr = new BranchInstruction(valueInstrCondition, bodyInstructions); + + + /* If there is a pre-run instruction */ + Instruction preRunInstruction; + if(forLoop.hasPreRunStatement()) + { + preRunInstruction = tailPopInstr(); + } + + /** + * Code gen + * + * 1. Create the ForLoopInstruction containing the BranchInstruction and + * preRunInstruction + * 2. Set the context + * 3. Add the instruction + */ + ForLoopInstruction forLoopInstruction = new ForLoopInstruction(branchInstr, preRunInstruction); + forLoopInstruction.context = forLoop.context; + addInstrB(forLoopInstruction); + } /* 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 536862b3..dcd0f0ba 100644 --- a/source/tlang/compiler/typecheck/dependency/core.d +++ b/source/tlang/compiler/typecheck/dependency/core.d @@ -1134,6 +1134,362 @@ public class DNodeGenerator return newDNode; } + // TODO: Work in progress + private DNode generalStatement(Container c, Context context, Statement entity) + { + // /* Pool the container as `node` */ + // Entity namedContainer = cast(Entity)c; + // assert(namedContainer); + // DNode node = pool(namedContainer); + + + + + + + /** + * Variable paremeters (for functions) + */ + if(cast(VariableParameter)entity) + { + VariableParameter varParamDec = cast(VariableParameter)entity; + + // Set context + entity.setContext(context); + + // Pool and mark as visited + // NOTE: I guess for now use VariableDNode as that is what is used in expressionPass + // with the poolT! constrcutor, doing otherwise causes a cast failure and hence + // null: /git/tlang/tlang/issues/52#issuecomment-325 + DNode dnode = poolT!(VariableNode, Variable)(varParamDec); + dnode.markVisited(); + + return null; + } + /** + * Variable declarations + */ + else if(cast(Variable)entity) + { + /* Get the Variable and information */ + Variable variable = cast(Variable)entity; + + /* TODO: 25Oct new */ + // Context d = new Context( cast(Container)modulle, InitScope.STATIC); + entity.setContext(context); + /* TODO: Above 25oct new */ + + Type variableType = tc.getType(c, variable.getType()); + assert(variableType); /* TODO: Handle invalid variable type */ + DNode variableDNode = poolT!(StaticVariableDeclaration, Variable)(variable); + writeln("Hello"); + writeln("VarType: "~to!(string)(variableType)); + + /* Basic type */ + if(cast(Primitive)variableType) + { + /* Do nothing */ + } + /* Class-type */ + else if(cast(Clazz)variableType) + { + writeln("Literally hello"); + + /* Get the static class dependency */ + ClassStaticNode classDependency = classPassStatic(cast(Clazz)variableType); + + /* Make this variable declaration depend on static initalization of the class */ + variableDNode.needs(classDependency); + } + /* Struct-type */ + else if(cast(Struct)variableType) + { + + } + /* Anything else */ + else + { + /* This should never happen */ + assert(false); + } + + + /* Set as visited */ + variableDNode.markVisited(); + + /* If there is an assignment attached to this */ + if(variable.getAssignment()) + { + /* Extract the assignment */ + VariableAssignment varAssign = variable.getAssignment(); + + /* Set the Context of the assignment to the current context */ + varAssign.setContext(context); + + /* Pool the assignment to get a DNode */ + DNode expressionNode = expressionPass(varAssign.getExpression(), context); + + /* This assignment depends on an expression being evaluated */ + VariableAssignmentNode varAssignNode = new VariableAssignmentNode(this, varAssign); + varAssignNode.needs(expressionNode); + + /* The variable declaration is dependant on the assignment */ + variableDNode.needs(varAssignNode); + } + + /* The current container is dependent on this variable declaration */ + // node.needs(variableDNode); + return variableDNode; + } + /** + * Variable asignments + */ + else if(cast(VariableAssignmentStdAlone)entity) + { + VariableAssignmentStdAlone vAsStdAl = cast(VariableAssignmentStdAlone)entity; + vAsStdAl.setContext(context); + + /* TODO: CHeck avriable name even */ + gprintln("YEAST ENJOYER"); + + + // 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().resolveBest(c, vAsStdAl.getVariableName())); + gprintln("YEAST ENJOYER"); + Variable variable = cast(Variable)tc.getResolver().resolveBest(c, vAsStdAl.getVariableName()); + assert(variable); + + + /* Pool the variable */ + DNode varDecDNode = pool(variable); + + /* TODO: Make sure a DNode exists (implying it's been declared already) */ + if(varDecDNode.isVisisted()) + { + /* Pool varass stdalone */ + DNode vStdAlDNode = pool(vAsStdAl); + // node.needs(vStdAlDNode); + + DNode expression = expressionPass(vAsStdAl.getExpression(), context); + vStdAlDNode.needs(expression); + + return vStdAlDNode; + } + else + { + Parser.expect("Cannot reference variable "~vAsStdAl.getVariableName()~" which exists but has not been declared yet"); + return null; + } + } + /** + * Function definitions + */ + else if(cast(Function)entity) + { + // /* Grab the function */ + Function func = cast(Function)entity; + + /* Add funtion definition */ + gprintln("Hello"); + addFunctionDef(tc, func); + + return null; + } + /** + * Return statement + */ + else if(cast(ReturnStmt)entity) + { + ReturnStmt returnStatement = cast(ReturnStmt)entity; + returnStatement.setContext(context); + + DNode returnStatementDNode = pool(returnStatement); + + /* Process the return expression */ + Expression returnExpression = returnStatement.getReturnExpression(); + DNode returnExpressionDNode = expressionPass(returnExpression, context); + + /* Make return depend on the return expression */ + returnStatementDNode.needs(returnExpressionDNode); + + /* Make this container depend on this return statement */ + // node.needs(returnStatementDNode); + return returnStatementDNode; + } + /** + * If statements + */ + else if(cast(IfStatement)entity) + { + IfStatement ifStatement = cast(IfStatement)entity; + ifStatement.setContext(context); + DNode ifStatementDNode = pool(ifStatement); + + /* Add each branch as a dependency */ + foreach(Branch branch; ifStatement.getBranches()) + { + DNode branchDNode = pool(branch); + // Set context of branch (it is parented by the IfStmt) + // NOTE: This is dead code as the above is done by Parser and + // we need not set context here, only matters at the generalPass + // call later (context being passed in) as a starting point + branch.setContext(new Context(ifStatement, context.initScope)); + + // Extract the potential branch condition + Expression branchCondition = branch.getCondition(); + + // Check if this branch has a condition + if(!(branchCondition is null)) + { + // We use container of IfStmt and nt IfStmt otself as nothing can really be + // contained in it that the condition expression would be able to lookup + DNode branchConditionDNode = expressionPass(branchCondition, context); + branchDNode.needs(branchConditionDNode); + } + + gprintln("branch parentOf(): "~to!(string)(branch.parentOf())); + assert(branch.parentOf()); + gprintln("branch generalPass(context="~to!(string)(context.getContainer())~")"); + + // When generalPass()'ing a branch's body we don't want to pass in `context` + // as that is containing the branch container and hence we skip anything IN the + // branch container + // NOTE: Check initScope + Context branchContext = new Context(branch, context.initScope); + DNode branchStatementsDNode = generalPass(branch, branchContext); + branchDNode.needs(branchStatementsDNode); + + /* Make the if statement depend on this branch */ + ifStatementDNode.needs(branchDNode); + } + + /* Make this container depend on this if statement */ + // node.needs(ifStatementDNode); + return 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) + { + // 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 + // TODO: I don't think we really need to reverse this? + // Logically we should, but the typechecker will add this things in the correct order anyways? + // We need to look into this! + // Our nodes at the back will always be placed at the back, and the expression will end ip upfront + // i think it is a problem oif maybe other expressions are left on the stack but is that ever a problem + //now with the statement <-> instruction mapping (like will that ever even occur?) + else + { + // Pass over the statements in the branch's body + Context branchContext = new Context(whileBranch, InitScope.STATIC); + DNode branchBodyDNode = generalPass(whileBranch, branchContext); + + // Make the branchDNode depend on the body dnode (above) + branchDNode.needs(branchBodyDNode); + + + // 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); + } + + /* 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 whileLoopDNode; + } + /** + * For loops + */ + else if(cast(ForLoop)entity) + { + ForLoop forLoop = cast(ForLoop)entity; + forLoop.setContext(context); + DNode forLoopDNode = pool(forLoop); + + + // Check for a pre-run statement + if(forLoop.hasPreRunStatement()) + { + Statement preRunStatement = forLoop.getPreRunStatement(); + DNode preRunStatementDNode = generalStatement(c, context, preRunStatement); + forLoopDNode.needs(preRunStatementDNode); + } + + // Get the branch + Branch forLoopBranch = forLoop.getBranch(); + Expression forLoopCondition = forLoopBranch.getCondition(); + + // TODO: The below context won't work until we make the `preLoopStatement` (and maybe `postIterationStatement`??) + // a part of the body of the for-loop (see issue #78) + // Pass over the condition expression + DNode forLoopConditionDNode = expressionPass(forLoopCondition, new Context(forLoop, InitScope.STATIC)); + forLoopDNode.needs(forLoopConditionDNode); + + + // TODO: What we need here now is effectively the equivalent of the Parser's `parseStatement()` + // (i.e. for a single statement), so this body of code should be `generalStatement(Container, Context, Statement)` + // and should be called within this loop + + // We want to generalPass the Branch Container and the context if within the Branch container + DNode branchDNode = generalPass(forLoopBranch, new Context(forLoopBranch, InitScope.STATIC)); + forLoopDNode.needs(branchDNode); + + return forLoopDNode; + } + + return null; + } + + /** + * Performs a general pass over the Statement(s) in the given container + * and with the given Context + * + * Params: + * c = the Container on which to pass through all of its elements + * context = the Context to use for the pass + * + * Returns: a DNode for the Container c + */ private DNode generalPass(Container c, Context context) { Entity namedContainer = cast(Entity)c; @@ -1189,267 +1545,16 @@ public class DNodeGenerator // continue; // } - /** - * Variable paremeters (for functions) - */ - if(cast(VariableParameter)entity) + DNode statementDNode = generalStatement(c, context, entity); + if(statementDNode is null) { - VariableParameter varParamDec = cast(VariableParameter)entity; - - // Set context - entity.setContext(context); - - // Pool and mark as visited - // NOTE: I guess for now use VariableDNode as that is what is used in expressionPass - // with the poolT! constrcutor, doing otherwise causes a cast failure and hence - // null: /git/tlang/tlang/issues/52#issuecomment-325 - DNode dnode = poolT!(VariableNode, Variable)(varParamDec); - dnode.markVisited(); + gprintln("Not adding dependency '"~to!(string)(statementDNode)~"' as it is null"); } - /** - * Variable declarations - */ - else if(cast(Variable)entity) + else { - /* Get the Variable and information */ - Variable variable = cast(Variable)entity; - - /* TODO: 25Oct new */ - // Context d = new Context( cast(Container)modulle, InitScope.STATIC); - entity.setContext(context); - /* TODO: Above 25oct new */ - - Type variableType = tc.getType(c, variable.getType()); - assert(variableType); /* TODO: Handle invalid variable type */ - DNode variableDNode = poolT!(StaticVariableDeclaration, Variable)(variable); - writeln("Hello"); - writeln("VarType: "~to!(string)(variableType)); - - /* Basic type */ - if(cast(Primitive)variableType) - { - /* Do nothing */ - } - /* Class-type */ - else if(cast(Clazz)variableType) - { - writeln("Literally hello"); - - /* Get the static class dependency */ - ClassStaticNode classDependency = classPassStatic(cast(Clazz)variableType); - - /* Make this variable declaration depend on static initalization of the class */ - variableDNode.needs(classDependency); - } - /* Struct-type */ - else if(cast(Struct)variableType) - { - - } - /* Anything else */ - else - { - /* This should never happen */ - assert(false); - } - - - /* Set as visited */ - variableDNode.markVisited(); - - /* If there is an assignment attached to this */ - if(variable.getAssignment()) - { - /* Extract the assignment */ - VariableAssignment varAssign = variable.getAssignment(); - - /* Set the Context of the assignment to the current context */ - varAssign.setContext(context); - - /* Pool the assignment to get a DNode */ - DNode expressionNode = expressionPass(varAssign.getExpression(), context); - - /* This assignment depends on an expression being evaluated */ - VariableAssignmentNode varAssignNode = new VariableAssignmentNode(this, varAssign); - varAssignNode.needs(expressionNode); - - /* The variable declaration is dependant on the assignment */ - variableDNode.needs(varAssignNode); - } - - /* The current container is dependent on this variable declaration */ - node.needs(variableDNode); - } - /** - * Variable asignments - */ - else if(cast(VariableAssignmentStdAlone)entity) - { - VariableAssignmentStdAlone vAsStdAl = cast(VariableAssignmentStdAlone)entity; - vAsStdAl.setContext(context); - - /* TODO: CHeck avriable name even */ - gprintln("YEAST ENJOYER"); - - - // 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().resolveBest(c, vAsStdAl.getVariableName())); - gprintln("YEAST ENJOYER"); - Variable variable = cast(Variable)tc.getResolver().resolveBest(c, vAsStdAl.getVariableName()); - assert(variable); - - - /* Pool the variable */ - DNode varDecDNode = pool(variable); - - /* TODO: Make sure a DNode exists (implying it's been declared already) */ - if(varDecDNode.isVisisted()) - { - /* Pool varass stdalone */ - DNode vStdAlDNode = pool(vAsStdAl); - node.needs(vStdAlDNode); - - DNode expression = expressionPass(vAsStdAl.getExpression(), context); - vStdAlDNode.needs(expression); - } - else - { - Parser.expect("Cannot reference variable "~vAsStdAl.getVariableName()~" which exists but has not been declared yet"); - } - } - /** - * Function definitions - */ - else if(cast(Function)entity) - { - // /* Grab the function */ - Function func = cast(Function)entity; - - /* Add funtion definition */ - gprintln("Hello"); - addFunctionDef(tc, func); - } - /** - * Return statement - */ - else if(cast(ReturnStmt)entity) - { - ReturnStmt returnStatement = cast(ReturnStmt)entity; - returnStatement.setContext(context); - - DNode returnStatementDNode = pool(returnStatement); - - /* Process the return expression */ - Expression returnExpression = returnStatement.getReturnExpression(); - DNode returnExpressionDNode = expressionPass(returnExpression, context); - - /* Make return depend on the return expression */ - returnStatementDNode.needs(returnExpressionDNode); - - /* Make this container depend on this return statement */ - node.needs(returnStatementDNode); - } - /** - * If statements - */ - else if(cast(IfStatement)entity) - { - IfStatement ifStatement = cast(IfStatement)entity; - ifStatement.setContext(context); - DNode ifStatementDNode = pool(ifStatement); - - /* Add each branch as a dependency */ - foreach(Branch branch; ifStatement.getBranches()) - { - DNode branchDNode = pool(branch); - // Set context of branch (it is parented by the IfStmt) - // NOTE: This is dead code as the above is done by Parser and - // we need not set context here, only matters at the generalPass - // call later (context being passed in) as a starting point - branch.setContext(new Context(ifStatement, context.initScope)); - - // Extract the potential branch condition - Expression branchCondition = branch.getCondition(); - - // Check if this branch has a condition - if(!(branchCondition is null)) - { - // We use container of IfStmt and nt IfStmt otself as nothing can really be - // contained in it that the condition expression would be able to lookup - DNode branchConditionDNode = expressionPass(branchCondition, context); - branchDNode.needs(branchConditionDNode); - } - - gprintln("branch parentOf(): "~to!(string)(branch.parentOf())); - assert(branch.parentOf()); - gprintln("branch generalPass(context="~to!(string)(context.getContainer())~")"); - - // When generalPass()'ing a branch's body we don't want to pass in `context` - // as that is containing the branch container and hence we skip anything IN the - // branch container - // NOTE: Check initScope - Context branchContext = new Context(branch, context.initScope); - DNode branchStatementsDNode = generalPass(branch, branchContext); - branchDNode.needs(branchStatementsDNode); - - /* Make the if statement depend on this branch */ - ifStatementDNode.needs(branchDNode); - } - - /* 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); + node.needs(statementDNode); } + } return node; diff --git a/source/tlang/testing/simple_do_while.t b/source/tlang/testing/simple_do_while.t new file mode 100644 index 00000000..aa2e8de8 --- /dev/null +++ b/source/tlang/testing/simple_do_while.t @@ -0,0 +1,14 @@ +module simple_do_while; + +int function(int i) +{ + int test = 2; + do + { + i = i - 1; + test = test + i; + } + while(i); + + return test; +} \ No newline at end of file diff --git a/source/tlang/testing/simple_for_loops.t b/source/tlang/testing/simple_for_loops.t new file mode 100644 index 00000000..efdc3203 --- /dev/null +++ b/source/tlang/testing/simple_for_loops.t @@ -0,0 +1,13 @@ +module simple_for_loops; + +int function(int i) +{ + int test = 0; + + for(int idx = 0; idx < i; idx=idx+1) + { + test = test + 1; + } + + return test; +} \ No newline at end of file