Instruction

- Added new instruction `WhileLoopInstruction`

DGen

- Added support for emitting while-loops (so far just plain while loops) (`WhileLoopInstruction` in `emit()`)
- Added baked-in entry point testing code for while loops in `emitEntryPoint()`

Parsing

- Added missing plumbing for while loop parser nodes in `parseWhile()`

Data

- Fixed some typos
- Removed dead/unused "deps" code from `Entity`
- Added some documentation comments
- Added `WhileLoop` type for parser nodes

TypeChecker

- Removed TODO in comment for already-implemented/completed if-statements
- Added while-loop code generation support (only while-loops, no do-whiles)

Dependency

- Added while-loop dependency generation support (so far only while-loops, no do-whiles)

Tests

- Added new test case `simple_while.t` for testing while loops
This commit is contained in:
Tristan B. Velloza Kildaire 2023-01-04 12:03:50 +02:00
parent 4f899c69e2
commit 22c4e8d5a1
7 changed files with 296 additions and 29 deletions

View File

@ -271,6 +271,34 @@ public final class DCodeEmitter : CodeEmitter
return emit; 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(<expr>)` 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 "<TODO: Base emit: "~to!(string)(instruction)~">"; return "<TODO: Base emit: "~to!(string)(instruction)~">";
} }
@ -451,17 +479,35 @@ public final class DCodeEmitter : CodeEmitter
{ {
//TODO: Implement me //TODO: Implement me
// Test for `simple_functions.t` (function call testing)
if(cmp(typeChecker.getModule().getName(), "simple_functions") == 0) if(cmp(typeChecker.getModule().getName(), "simple_functions") == 0)
{ {
// NOTE: Remove this printf file.writeln(`
file.writeln(`
// NOTE: The below is testing code and should be removed
#include<stdio.h> #include<stdio.h>
#include<assert.h>
int main() int main()
{ {
assert(t_7b6d477c5859059f16bc9da72fc8cc3b == 22);
printf("k: %u\n", t_7b6d477c5859059f16bc9da72fc8cc3b); printf("k: %u\n", t_7b6d477c5859059f16bc9da72fc8cc3b);
banana(1); banana(1);
assert(t_7b6d477c5859059f16bc9da72fc8cc3b == 72);
printf("k: %u\n", t_7b6d477c5859059f16bc9da72fc8cc3b); printf("k: %u\n", t_7b6d477c5859059f16bc9da72fc8cc3b);
return 0;
}`);
}
else if(cmp(typeChecker.getModule().getName(), "simple_while") == 0)
{
file.writeln(`
#include<stdio.h>
#include<assert.h>
int main()
{
int result = function(3);
printf("result: %d\n", result);
assert(result == 3);
return 0; return 0;
}`); }`);
} }

View File

@ -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 public final class BranchInstruction : Instruction
{ {
private Value branchConditionInstr; private Value branchConditionInstr;

View File

@ -217,15 +217,19 @@ public final class Parser
/* Create the if statement with the branches */ /* Create the if statement with the branches */
ifStmt = new IfStatement(branches); ifStmt = new IfStatement(branches);
/* Parent the branches to the IfStatement */
parentToContainer(ifStmt, cast(Statement[])branches); parentToContainer(ifStmt, cast(Statement[])branches);
return ifStmt; return ifStmt;
} }
private void parseWhile() private WhileLoop parseWhile()
{ {
gprintln("parseWhile(): Enter", DebugType.WARNING); gprintln("parseWhile(): Enter", DebugType.WARNING);
Expression branchCondition;
Statement[] branchBody;
/* Pop off the `while` */ /* Pop off the `while` */
nextToken(); nextToken();
@ -234,7 +238,7 @@ public final class Parser
nextToken(); nextToken();
/* Parse an expression (for the condition) */ /* Parse an expression (for the condition) */
parseExpression(); branchCondition = parseExpression();
expect(SymbolType.RBRACE, getCurrentToken()); expect(SymbolType.RBRACE, getCurrentToken());
/* Openening { */ /* Openening { */
@ -242,11 +246,26 @@ public final class Parser
expect(SymbolType.OCURLY, getCurrentToken()); expect(SymbolType.OCURLY, getCurrentToken());
/* Parse the while' statement's body AND expect a closing curly */ /* Parse the while' statement's body AND expect a closing curly */
parseBody(); branchBody = parseBody();
expect(SymbolType.CCURLY, getCurrentToken()); expect(SymbolType.CCURLY, getCurrentToken());
nextToken(); 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); gprintln("parseWhile(): Leave", DebugType.WARNING);
return whileLoop;
} }
public VariableAssignmentStdAlone parseAssignment() public VariableAssignmentStdAlone parseAssignment()
@ -524,7 +543,7 @@ public final class Parser
/* If it is a while loop */ /* If it is a while loop */
else if (symbol == SymbolType.WHILE) else if (symbol == SymbolType.WHILE)
{ {
parseWhile(); statements ~= parseWhile();
} }
/* If it is a function call (further inspection needed) */ /* If it is a function call (further inspection needed) */
else if (symbol == SymbolType.IDENT_TYPE) else if (symbol == SymbolType.IDENT_TYPE)

View File

@ -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 public class Entity : Statement
{ {
/* Accesor type */ /* Accessor type */
private AccessorType accessorType = AccessorType.PUBLIC; private AccessorType accessorType = AccessorType.PUBLIC;
/* Function/Modifier type */ /* Function/Modifier type */
@ -194,16 +198,6 @@ public class Entity : Statement
{ {
return name; return name;
} }
private Entity[] deps;
public Entity[] getDeps()
{
return deps;
}
public void addDep(Entity entity)
{
deps ~= entity;
}
} }
/* TODO: DO we need intermediary class, TypedEntity */ /* 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 public final class ReturnStmt : Statement
{ {
// The Expression being returned // The Expression being returned
@ -554,6 +554,9 @@ public final class ReturnStmt : Statement
/** /**
* IfStatement * IfStatement
*
* Represents an if statement with branches of code
* and conditions per each
*/ */
public final class IfStatement : Entity, Container 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 <code>Branch</code> that makes up this while
* loop
* isDoWhile = If <code>true</code> then interpret this as a
* do-while loop, however if <code>false</code>
* 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 * Branch
* *
@ -613,6 +684,15 @@ public final class Branch : Entity, Container
private static ulong branchContainerRollingNameCounter = 0; private static ulong branchContainerRollingNameCounter = 0;
/**
* Creates a new Branch which will couple a condition
* as an instance of <code>Expression</code> and a body
* of <code>Statement</code>(s) apart of it
*
* Params:
* condition = The condition as an <code>Expression</code>
* branch = The body of <code>Statement</code>(s) making up the branch
*/
this(Expression condition, Statement[] branch) this(Expression condition, Statement[] branch)
{ {
branchContainerRollingNameCounter++; branchContainerRollingNameCounter++;
@ -620,7 +700,6 @@ public final class Branch : Entity, Container
this.branchCondition = condition; this.branchCondition = condition;
this.branchBody = branch; this.branchBody = branch;
} }
/** /**
@ -634,18 +713,22 @@ public final class Branch : Entity, Container
return !(branchCondition is null); return !(branchCondition is null);
} }
/**
* Returns the condition of the branch
*
* Returns: The condition as an instance of <code>Expression</code>
*/
public Expression getCondition() public Expression getCondition()
{ {
return branchCondition; return branchCondition;
} }
public Statement[] getBody() public Statement[] getBody()
{ {
return branchBody; return branchBody;
} }
public override void addStatement(Statement statement) public override void addStatement(Statement statement)
{ {
branchBody ~= statement; branchBody ~= statement;

View File

@ -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); branchInstructions=reverse(branchInstructions);
/** /**
@ -971,6 +971,50 @@ public final class TypeChecker
gprintln("If!"); 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 */ /* Branch */
else if(cast(Branch)statement) else if(cast(Branch)statement)
{ {

View File

@ -1401,6 +1401,55 @@ public class DNodeGenerator
/* Make this container depend on this if statement */ /* Make this container depend on this if statement */
node.needs(ifStatementDNode); 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; return node;

View File

@ -1,11 +1,20 @@
module simple_while; module simple_while;
int main() int function(int i)
{ {
int j = 0; int test = 0;
j=2;
while(j < 10) 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;
}