Lexer
- Fixed missing flushing for issue #65 (see "Flushing fix ✅") - Added unit test for flushing fix VariableDeclaration (Instruction) - Added support for the embedding of a VariableAssignmentInstr inside (added a getter too) (a part of issue #66) - Conditional support for if statements: Added two new instructions (IfStatementInstruction and BranchInstruction). See issue #64 DGen - Added depth increment/decrement on enter/leave scope of `transform()` - Correct tabbing for nested if-statements using new method `genTabs(ulong)` (which uses the above mechanism). Makes code emitted for if statements (issue #64) look nicer. - Updated VariableDeclarations (with assignments) handling in `transform()` in the manner similar to BinOpInstr (see issue #66) - Added a TODO for formatting BinOpInstr's `transform()` a little more aesthetically nicer - Added code emitting support for if statements (the `IfStatementInstruction` instruction) (see issue #64) - Updated `emitEntryPoint()` to only emit testing C code for the correct input test file Parser - `parseIf()` now returns an instance of IfStatement which couples multiple `Branch` objects consisting of `Statement[]` and `Expression` - Ensured that each `Statement` of the generated `Statement[]` from `parseBody()` for a given `Branch` is parented to said Branch using `parentToContainer()` - Ensured each generated `Branch` in `Branch[]` is parented to the generated `IfStatement` using `parentToContainer()` - `parseBody()` now adds to its `Statement[]` build-up array the generated `IfStatement` from the call to `parseIf()` Check - Added support for back-mapping `SymbolType.EQUALS` to `getCharacter(SymbolType)` Data - Added `Branch` parser node which is a Container for body statements (`Statement[]`) - Added `IfStatement` parser node which is a Container of `Statement[]` which are actually `Branch[]` TypeChecker - Moved import for `reverse` to top of module - Implemented `tailPopInstr()` method which will pop from the back of the `codeQueue` "scratchpad" - Fixes handling of `StaticVariableDeclaration` and `VariableAssignmentNode` (fixes issue #66) - Added handling for IfStatement entities (if statement support #64) Resolution - Added a debug statement to `resolveUp(Container, string)` to print out the container to lookup from and the name being looked up Dependency - Added a default `toString()` to the DNode class which prints `[DNode: <entity toString()]` - Added a TODO and debug print related to issues #9 - Disabled InitScope.STATIC check for now as it caused issues with if statement parsing (probably due to VIRTUAL being default and therefore skipping if statment processing) - issue #69 - Cleaned up handling of Entity type `Variable` (variable declarations) - removed repeated code - Undid the VarAss->(depends on)->VarDec, reverted back to VarDec->(depends on)->VarAss, fixed by #66 (and closes it and #11) - Added support for `IfStatement` (if statements) in `generalPass(Container, Context)` Test cases - Added new test case testing nested if statements (`nested_conditions.t`) - Added another test case for if statements, `simple_conditions.t`
This commit is contained in:
parent
beb068a33c
commit
4f899c69e2
|
@ -31,11 +31,29 @@ public final class DCodeEmitter : CodeEmitter
|
||||||
super(typeChecker, file);
|
super(typeChecker, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ulong transformDepth = 0;
|
||||||
|
|
||||||
|
private string genTabs(ulong count)
|
||||||
|
{
|
||||||
|
string tabStr;
|
||||||
|
for(ulong i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
tabStr~="\t";
|
||||||
|
}
|
||||||
|
return tabStr;
|
||||||
|
}
|
||||||
|
|
||||||
public override string transform(const Instruction instruction)
|
public override string transform(const Instruction instruction)
|
||||||
{
|
{
|
||||||
import std.stdio;
|
|
||||||
writeln("\n");
|
writeln("\n");
|
||||||
gprintln("transform(): "~to!(string)(instruction));
|
gprintln("transform(): "~to!(string)(instruction));
|
||||||
|
transformDepth++;
|
||||||
|
|
||||||
|
// At any return decrement the depth
|
||||||
|
scope(exit)
|
||||||
|
{
|
||||||
|
transformDepth--;
|
||||||
|
}
|
||||||
|
|
||||||
/* VariableAssignmentInstr */
|
/* VariableAssignmentInstr */
|
||||||
if(cast(VariableAssignmentInstr)instruction)
|
if(cast(VariableAssignmentInstr)instruction)
|
||||||
|
@ -94,9 +112,11 @@ public final class DCodeEmitter : CodeEmitter
|
||||||
varDecWantsConsumeVarAss = true;
|
varDecWantsConsumeVarAss = true;
|
||||||
|
|
||||||
// Fetch the variable assignment instruction
|
// Fetch the variable assignment instruction
|
||||||
gprintln("Before crash: "~to!(string)(getCurrentInstruction()));
|
// gprintln("Before crash: "~to!(string)(getCurrentInstruction()));
|
||||||
nextInstruction();
|
// nextInstruction();
|
||||||
Instruction varAssInstr = getCurrentInstruction();
|
// Instruction varAssInstr = getCurrentInstruction();
|
||||||
|
|
||||||
|
VariableAssignmentInstr varAssInstr = varDecInstr.getAssignmentInstr();
|
||||||
|
|
||||||
// Generate the code to emit
|
// Generate the code to emit
|
||||||
return varDecInstr.varType~" "~renamedSymbol~" = "~transform(varAssInstr)~";";
|
return varDecInstr.varType~" "~renamedSymbol~" = "~transform(varAssInstr)~";";
|
||||||
|
@ -139,6 +159,8 @@ public final class DCodeEmitter : CodeEmitter
|
||||||
|
|
||||||
BinOpInstr binOpInstr = cast(BinOpInstr)instruction;
|
BinOpInstr binOpInstr = cast(BinOpInstr)instruction;
|
||||||
|
|
||||||
|
// TODO: I like having `lhs == rhs` for `==` or comparators but not spaces for `lhs+rhs`
|
||||||
|
|
||||||
return transform(binOpInstr.lhs)~to!(string)(getCharacter(binOpInstr.operator))~transform(binOpInstr.rhs);
|
return transform(binOpInstr.lhs)~to!(string)(getCharacter(binOpInstr.operator))~transform(binOpInstr.rhs);
|
||||||
}
|
}
|
||||||
/* FuncCallInstr */
|
/* FuncCallInstr */
|
||||||
|
@ -199,6 +221,56 @@ public final class DCodeEmitter : CodeEmitter
|
||||||
|
|
||||||
return "return "~transform(returnExpressionInstr)~";";
|
return "return "~transform(returnExpressionInstr)~";";
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* If statements (IfStatementInstruction)
|
||||||
|
*/
|
||||||
|
else if(cast(IfStatementInstruction)instruction)
|
||||||
|
{
|
||||||
|
IfStatementInstruction ifStatementInstruction = cast(IfStatementInstruction)instruction;
|
||||||
|
|
||||||
|
BranchInstruction[] branchInstructions = ifStatementInstruction.getBranchInstructions();
|
||||||
|
gprintln("Holla"~to!(string)(branchInstructions));
|
||||||
|
|
||||||
|
string emit;
|
||||||
|
|
||||||
|
for(ulong i = 0; i < branchInstructions.length; i++)
|
||||||
|
{
|
||||||
|
BranchInstruction curBranchInstr = branchInstructions[i];
|
||||||
|
|
||||||
|
if(curBranchInstr.hasConditionInstr())
|
||||||
|
{
|
||||||
|
Value conditionInstr = cast(Value)curBranchInstr.getConditionInstr();
|
||||||
|
|
||||||
|
string hStr = (i == 0) ? "if" : genTabs(transformDepth)~"else if";
|
||||||
|
|
||||||
|
emit~=hStr~"("~transform(conditionInstr)~")\n";
|
||||||
|
|
||||||
|
emit~=genTabs(transformDepth)~"{\n";
|
||||||
|
|
||||||
|
foreach(Instruction branchBodyInstr; curBranchInstr.getBodyInstructions())
|
||||||
|
{
|
||||||
|
emit~=genTabs(transformDepth)~"\t"~transform(branchBodyInstr)~"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
emit~=genTabs(transformDepth)~"}\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit~=genTabs(transformDepth)~"else\n";
|
||||||
|
|
||||||
|
emit~=genTabs(transformDepth)~"{\n";
|
||||||
|
|
||||||
|
foreach(Instruction branchBodyInstr; curBranchInstr.getBodyInstructions())
|
||||||
|
{
|
||||||
|
emit~=genTabs(transformDepth)~"\t"~transform(branchBodyInstr)~"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
emit~=genTabs(transformDepth)~"}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return emit;
|
||||||
|
}
|
||||||
|
|
||||||
return "<TODO: Base emit: "~to!(string)(instruction)~">";
|
return "<TODO: Base emit: "~to!(string)(instruction)~">";
|
||||||
}
|
}
|
||||||
|
@ -379,6 +451,8 @@ public final class DCodeEmitter : CodeEmitter
|
||||||
{
|
{
|
||||||
//TODO: Implement me
|
//TODO: Implement me
|
||||||
|
|
||||||
|
if(cmp(typeChecker.getModule().getName(), "simple_functions") == 0)
|
||||||
|
{
|
||||||
// NOTE: Remove this printf
|
// NOTE: Remove this printf
|
||||||
file.writeln(`
|
file.writeln(`
|
||||||
// NOTE: The below is testing code and should be removed
|
// NOTE: The below is testing code and should be removed
|
||||||
|
@ -391,6 +465,16 @@ int main()
|
||||||
return 0;
|
return 0;
|
||||||
}`);
|
}`);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file.writeln(`
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -80,15 +80,26 @@ public final class VariableDeclaration : StorageDeclaration
|
||||||
/* Type of the variable being declared */
|
/* Type of the variable being declared */
|
||||||
public const string varType;
|
public const string varType;
|
||||||
|
|
||||||
|
/* VariableAssignmentInstr-instruction to be assigned */
|
||||||
|
private VariableAssignmentInstr varAssInstr;
|
||||||
|
|
||||||
//TODO: This must take in type information
|
//TODO: This must take in type information
|
||||||
this(string varName, byte len, string varType)
|
this(string varName, byte len, string varType, VariableAssignmentInstr varAssInstr)
|
||||||
{
|
{
|
||||||
this.varName = varName;
|
this.varName = varName;
|
||||||
this.length = len;
|
this.length = len;
|
||||||
this.varType = varType;
|
this.varType = varType;
|
||||||
|
|
||||||
|
this.varAssInstr = varAssInstr;
|
||||||
|
|
||||||
addInfo = "varName: "~varName;
|
addInfo = "varName: "~varName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VariableAssignmentInstr getAssignmentInstr()
|
||||||
|
{
|
||||||
|
return varAssInstr;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class FetchValueVar : Value
|
public final class FetchValueVar : Value
|
||||||
|
@ -289,3 +300,49 @@ public final class ReturnInstruction : Instruction
|
||||||
return returnExprInstr;
|
return returnExprInstr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class IfStatementInstruction : Instruction
|
||||||
|
{
|
||||||
|
private BranchInstruction[] branchInstructions;
|
||||||
|
|
||||||
|
this(BranchInstruction[] branchInstructions)
|
||||||
|
{
|
||||||
|
this.branchInstructions = branchInstructions;
|
||||||
|
|
||||||
|
addInfo = "Branches: "~to!(string)(branchInstructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BranchInstruction[] getBranchInstructions()
|
||||||
|
{
|
||||||
|
return branchInstructions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class BranchInstruction : Instruction
|
||||||
|
{
|
||||||
|
private Value branchConditionInstr;
|
||||||
|
private Instruction[] bodyInstructions;
|
||||||
|
|
||||||
|
this(Value conditionInstr, Instruction[] bodyInstructions)
|
||||||
|
{
|
||||||
|
this.branchConditionInstr = conditionInstr;
|
||||||
|
this.bodyInstructions = bodyInstructions;
|
||||||
|
|
||||||
|
addInfo = "CondInstr: "~to!(string)(branchConditionInstr)~", BBodyInstrs: "~to!(string)(bodyInstructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool hasConditionInstr()
|
||||||
|
{
|
||||||
|
return !(branchConditionInstr is null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value getConditionInstr()
|
||||||
|
{
|
||||||
|
return branchConditionInstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instruction[] getBodyInstructions()
|
||||||
|
{
|
||||||
|
return bodyInstructions;
|
||||||
|
}
|
||||||
|
}
|
|
@ -163,6 +163,13 @@ public final class Lexer
|
||||||
/* Check for case of `==` (where we are on the first `=` sign) */
|
/* Check for case of `==` (where we are on the first `=` sign) */
|
||||||
if(currentChar == '=' && isForward() && sourceCode[position+1] == '=')
|
if(currentChar == '=' && isForward() && sourceCode[position+1] == '=')
|
||||||
{
|
{
|
||||||
|
/* Flush any current token (if exists) */
|
||||||
|
if(currentToken.length)
|
||||||
|
{
|
||||||
|
currentTokens ~= new Token(currentToken, line, column);
|
||||||
|
currentToken = "";
|
||||||
|
}
|
||||||
|
|
||||||
// Create the `==` token
|
// Create the `==` token
|
||||||
currentTokens ~= new Token("==", line, column);
|
currentTokens ~= new Token("==", line, column);
|
||||||
|
|
||||||
|
@ -808,6 +815,14 @@ unittest
|
||||||
currentLexer.performLex();
|
currentLexer.performLex();
|
||||||
gprintln("Collected "~to!(string)(currentLexer.getTokens()));
|
gprintln("Collected "~to!(string)(currentLexer.getTokens()));
|
||||||
assert(currentLexer.getTokens() == [new Token("==", 0, 0), new Token(",", 0, 0), new Token("=", 0, 0), new Token("==", 0, 0)]);
|
assert(currentLexer.getTokens() == [new Token("==", 0, 0), new Token(",", 0, 0), new Token("=", 0, 0), new Token("==", 0, 0)]);
|
||||||
|
|
||||||
|
// Test flushing of previous token
|
||||||
|
import std.algorithm.comparison;
|
||||||
|
sourceCode = "i==i=\n";
|
||||||
|
currentLexer = new Lexer(sourceCode);
|
||||||
|
currentLexer.performLex();
|
||||||
|
gprintln("Collected "~to!(string)(currentLexer.getTokens()));
|
||||||
|
assert(currentLexer.getTokens() == [new Token("i", 0, 0), new Token("==", 0, 0), new Token("i", 0, 0), new Token("=", 0, 0)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -107,13 +107,20 @@ public final class Parser
|
||||||
* Parses if statements
|
* Parses if statements
|
||||||
*
|
*
|
||||||
* TODO: Check kanban
|
* TODO: Check kanban
|
||||||
|
* TOOD: THis should return something
|
||||||
*/
|
*/
|
||||||
private void parseIf()
|
private IfStatement parseIf()
|
||||||
{
|
{
|
||||||
gprintln("parseIf(): Enter", DebugType.WARNING);
|
gprintln("parseIf(): Enter", DebugType.WARNING);
|
||||||
|
|
||||||
|
IfStatement ifStmt;
|
||||||
|
Branch[] branches;
|
||||||
|
|
||||||
while (hasTokens())
|
while (hasTokens())
|
||||||
{
|
{
|
||||||
|
Expression currentBranchCondition;
|
||||||
|
Statement[] currentBranchBody;
|
||||||
|
|
||||||
/* This will only be called once (it is what caused a call to parseIf()) */
|
/* This will only be called once (it is what caused a call to parseIf()) */
|
||||||
if (getSymbolType(getCurrentToken()) == SymbolType.IF)
|
if (getSymbolType(getCurrentToken()) == SymbolType.IF)
|
||||||
{
|
{
|
||||||
|
@ -125,7 +132,7 @@ public final class Parser
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
/* Parse an expression (for the condition) */
|
/* Parse an expression (for the condition) */
|
||||||
parseExpression();
|
currentBranchCondition = parseExpression();
|
||||||
expect(SymbolType.RBRACE, getCurrentToken());
|
expect(SymbolType.RBRACE, getCurrentToken());
|
||||||
|
|
||||||
/* Opening { */
|
/* Opening { */
|
||||||
|
@ -133,9 +140,14 @@ public final class Parser
|
||||||
expect(SymbolType.OCURLY, getCurrentToken());
|
expect(SymbolType.OCURLY, getCurrentToken());
|
||||||
|
|
||||||
/* Parse the if' statement's body AND expect a closing curly */
|
/* Parse the if' statement's body AND expect a closing curly */
|
||||||
parseBody();
|
currentBranchBody = parseBody();
|
||||||
expect(SymbolType.CCURLY, getCurrentToken());
|
expect(SymbolType.CCURLY, getCurrentToken());
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
|
/* Create a branch node */
|
||||||
|
Branch branch = new Branch(currentBranchCondition, currentBranchBody);
|
||||||
|
parentToContainer(branch, currentBranchBody);
|
||||||
|
branches ~= branch;
|
||||||
}
|
}
|
||||||
/* If we get an else as the next symbol */
|
/* If we get an else as the next symbol */
|
||||||
else if (getSymbolType(getCurrentToken()) == SymbolType.ELSE)
|
else if (getSymbolType(getCurrentToken()) == SymbolType.ELSE)
|
||||||
|
@ -154,7 +166,7 @@ public final class Parser
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
/* Parse an expression (for the condition) */
|
/* Parse an expression (for the condition) */
|
||||||
parseExpression();
|
currentBranchCondition = parseExpression();
|
||||||
expect(SymbolType.RBRACE, getCurrentToken());
|
expect(SymbolType.RBRACE, getCurrentToken());
|
||||||
|
|
||||||
/* Opening { */
|
/* Opening { */
|
||||||
|
@ -162,18 +174,28 @@ public final class Parser
|
||||||
expect(SymbolType.OCURLY, getCurrentToken());
|
expect(SymbolType.OCURLY, getCurrentToken());
|
||||||
|
|
||||||
/* Parse the if' statement's body AND expect a closing curly */
|
/* Parse the if' statement's body AND expect a closing curly */
|
||||||
parseBody();
|
currentBranchBody = parseBody();
|
||||||
expect(SymbolType.CCURLY, getCurrentToken());
|
expect(SymbolType.CCURLY, getCurrentToken());
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
|
/* Create a branch node */
|
||||||
|
Branch branch = new Branch(currentBranchCondition, currentBranchBody);
|
||||||
|
parentToContainer(branch, currentBranchBody);
|
||||||
|
branches ~= branch;
|
||||||
}
|
}
|
||||||
/* Check for opening curly (just an "else" statement) */
|
/* Check for opening curly (just an "else" statement) */
|
||||||
else if (getSymbolType(getCurrentToken()) == SymbolType.OCURLY)
|
else if (getSymbolType(getCurrentToken()) == SymbolType.OCURLY)
|
||||||
{
|
{
|
||||||
/* Parse the if' statement's body (starting with `{` AND expect a closing curly */
|
/* Parse the if' statement's body (starting with `{` AND expect a closing curly */
|
||||||
parseBody();
|
currentBranchBody = parseBody();
|
||||||
expect(SymbolType.CCURLY, getCurrentToken());
|
expect(SymbolType.CCURLY, getCurrentToken());
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
|
/* Create a branch node */
|
||||||
|
Branch branch = new Branch(null, currentBranchBody);
|
||||||
|
parentToContainer(branch, currentBranchBody);
|
||||||
|
branches ~= branch;
|
||||||
|
|
||||||
/* Exit, this is the end of the if statement as an else is reached */
|
/* Exit, this is the end of the if statement as an else is reached */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -191,6 +213,13 @@ public final class Parser
|
||||||
}
|
}
|
||||||
|
|
||||||
gprintln("parseIf(): Leave", DebugType.WARNING);
|
gprintln("parseIf(): Leave", DebugType.WARNING);
|
||||||
|
|
||||||
|
/* Create the if statement with the branches */
|
||||||
|
ifStmt = new IfStatement(branches);
|
||||||
|
|
||||||
|
parentToContainer(ifStmt, cast(Statement[])branches);
|
||||||
|
|
||||||
|
return ifStmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseWhile()
|
private void parseWhile()
|
||||||
|
@ -490,7 +519,7 @@ public final class Parser
|
||||||
/* If it is a branch */
|
/* If it is a branch */
|
||||||
else if (symbol == SymbolType.IF)
|
else if (symbol == SymbolType.IF)
|
||||||
{
|
{
|
||||||
parseIf();
|
statements ~= parseIf();
|
||||||
}
|
}
|
||||||
/* If it is a while loop */
|
/* If it is a while loop */
|
||||||
else if (symbol == SymbolType.WHILE)
|
else if (symbol == SymbolType.WHILE)
|
||||||
|
|
|
@ -497,6 +497,10 @@ public string getCharacter(SymbolType symbolIn)
|
||||||
{
|
{
|
||||||
return "}";
|
return "}";
|
||||||
}
|
}
|
||||||
|
else if(symbolIn == SymbolType.EQUALS)
|
||||||
|
{
|
||||||
|
return "==";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gprintln("getCharacter: No back-mapping for "~to!(string)(symbolIn), DebugType.ERROR);
|
gprintln("getCharacter: No back-mapping for "~to!(string)(symbolIn), DebugType.ERROR);
|
||||||
|
|
|
@ -551,3 +551,118 @@ public final class ReturnStmt : Statement
|
||||||
return returnExpression;
|
return returnExpression;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IfStatement
|
||||||
|
*/
|
||||||
|
public final class IfStatement : Entity, Container
|
||||||
|
{
|
||||||
|
private Branch[] branches;
|
||||||
|
|
||||||
|
private static ulong ifStmtContainerRollingNameCounter = 0;
|
||||||
|
|
||||||
|
this(Branch[] branches)
|
||||||
|
{
|
||||||
|
ifStmtContainerRollingNameCounter++;
|
||||||
|
super("ifStmt_"~to!(string)(ifStmtContainerRollingNameCounter));
|
||||||
|
|
||||||
|
this.branches = branches;
|
||||||
|
|
||||||
|
weight = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Branch[] getBranches()
|
||||||
|
{
|
||||||
|
return branches;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void addStatement(Statement statement)
|
||||||
|
{
|
||||||
|
branches ~= cast(Branch)statement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void addStatements(Statement[] statements)
|
||||||
|
{
|
||||||
|
branches ~= cast(Branch[])statements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Statement[] getStatements()
|
||||||
|
{
|
||||||
|
return cast(Statement[])branches;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string toString()
|
||||||
|
{
|
||||||
|
return "IfStmt";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Branch
|
||||||
|
*
|
||||||
|
* Represents a condition and code attached to
|
||||||
|
* run on said condition
|
||||||
|
*
|
||||||
|
* NOTE: I feel as though this should be a container
|
||||||
|
* with a `generalPass` applied to it in `dependency/core.d`
|
||||||
|
*/
|
||||||
|
public final class Branch : Entity, Container
|
||||||
|
{
|
||||||
|
private Expression branchCondition;
|
||||||
|
private Statement[] branchBody;
|
||||||
|
|
||||||
|
private static ulong branchContainerRollingNameCounter = 0;
|
||||||
|
|
||||||
|
this(Expression condition, Statement[] branch)
|
||||||
|
{
|
||||||
|
branchContainerRollingNameCounter++;
|
||||||
|
super("branch_"~to!(string)(branchContainerRollingNameCounter));
|
||||||
|
|
||||||
|
this.branchCondition = condition;
|
||||||
|
this.branchBody = branch;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Effectively checks if this branch is an 'else' branch
|
||||||
|
*
|
||||||
|
* Returns: <code>true</code> if so, <code>false</code>
|
||||||
|
* otherwise
|
||||||
|
*/
|
||||||
|
public bool hasCondition()
|
||||||
|
{
|
||||||
|
return !(branchCondition is null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression getCondition()
|
||||||
|
{
|
||||||
|
return branchCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Statement[] getBody()
|
||||||
|
{
|
||||||
|
return branchBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public override void addStatement(Statement statement)
|
||||||
|
{
|
||||||
|
branchBody ~= statement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void addStatements(Statement[] statements)
|
||||||
|
{
|
||||||
|
branchBody ~= statements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Statement[] getStatements()
|
||||||
|
{
|
||||||
|
return branchBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string toString()
|
||||||
|
{
|
||||||
|
return "Branch";
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import compiler.symbols.typing.core;
|
||||||
import compiler.typecheck.dependency.core;
|
import compiler.typecheck.dependency.core;
|
||||||
import compiler.codegen.instruction;
|
import compiler.codegen.instruction;
|
||||||
import std.container.slist;
|
import std.container.slist;
|
||||||
|
import std.algorithm : reverse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Parser only makes sure syntax
|
* The Parser only makes sure syntax
|
||||||
|
@ -272,6 +273,23 @@ public final class TypeChecker
|
||||||
return poppedInstr;
|
return poppedInstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pops from the tail of the code queue and returns it */
|
||||||
|
public Instruction tailPopInstr()
|
||||||
|
{
|
||||||
|
Instruction poppedInstr;
|
||||||
|
|
||||||
|
if(!codeQueue.empty)
|
||||||
|
{
|
||||||
|
// Perhaps there is a nicer way to tail popping
|
||||||
|
codeQueue.reverse();
|
||||||
|
poppedInstr = codeQueue.front();
|
||||||
|
codeQueue.removeFront();
|
||||||
|
codeQueue.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return poppedInstr;
|
||||||
|
}
|
||||||
|
|
||||||
public bool isInstrEmpty()
|
public bool isInstrEmpty()
|
||||||
{
|
{
|
||||||
return codeQueue.empty;
|
return codeQueue.empty;
|
||||||
|
@ -761,7 +779,7 @@ public final class TypeChecker
|
||||||
VariableAssignmentInstr varAssInstr = new VariableAssignmentInstr(variableName, valueInstr);
|
VariableAssignmentInstr varAssInstr = new VariableAssignmentInstr(variableName, valueInstr);
|
||||||
varAssInstr.context = variableAssignmentContext;
|
varAssInstr.context = variableAssignmentContext;
|
||||||
|
|
||||||
addInstrB(varAssInstr);
|
addInstr(varAssInstr);
|
||||||
}
|
}
|
||||||
/* TODO: Add support */
|
/* TODO: Add support */
|
||||||
/**
|
/**
|
||||||
|
@ -782,7 +800,21 @@ public final class TypeChecker
|
||||||
Variable variablePNode = cast(Variable)dnode.getEntity();
|
Variable variablePNode = cast(Variable)dnode.getEntity();
|
||||||
gprintln("HELLO FELLA");
|
gprintln("HELLO FELLA");
|
||||||
string variableName = resolver.generateName(modulle, variablePNode);
|
string variableName = resolver.generateName(modulle, variablePNode);
|
||||||
VariableDeclaration varDecInstr = new VariableDeclaration(variableName, 4, variablePNode.getType());
|
gprintln("HELLO FELLA (name): "~variableName);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// CHeck if this variable declaration has an assignment attached
|
||||||
|
VariableAssignmentInstr assignmentInstr;
|
||||||
|
if(variablePNode.getAssignment())
|
||||||
|
{
|
||||||
|
Instruction poppedInstr = popInstr();
|
||||||
|
assignmentInstr = cast(VariableAssignmentInstr)poppedInstr;
|
||||||
|
assert(assignmentInstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VariableDeclaration varDecInstr = new VariableDeclaration(variableName, 4, variablePNode.getType(), assignmentInstr);
|
||||||
|
|
||||||
/* NEW CODE (9th November 2021) Set the context */
|
/* NEW CODE (9th November 2021) Set the context */
|
||||||
varDecInstr.context = variablePNode.context;
|
varDecInstr.context = variablePNode.context;
|
||||||
|
@ -835,6 +867,8 @@ public final class TypeChecker
|
||||||
vAInstr.context = vasa.getContext();
|
vAInstr.context = vasa.getContext();
|
||||||
|
|
||||||
addInstrB(vAInstr);
|
addInstrB(vAInstr);
|
||||||
|
|
||||||
|
gprintln("VariableAssignmentStdAlone", DebugType.ERROR);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Return statement (ReturnStmt)
|
* Return statement (ReturnStmt)
|
||||||
|
@ -858,6 +892,92 @@ public final class TypeChecker
|
||||||
returnInstr.context = returnStatement.getContext();
|
returnInstr.context = returnStatement.getContext();
|
||||||
addInstrB(returnInstr);
|
addInstrB(returnInstr);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* If statement (IfStatement)
|
||||||
|
*/
|
||||||
|
else if(cast(IfStatement)statement)
|
||||||
|
{
|
||||||
|
IfStatement ifStatement = cast(IfStatement)statement;
|
||||||
|
BranchInstruction[] branchInstructions;
|
||||||
|
|
||||||
|
/* Get the if statement's branches */
|
||||||
|
Branch[] branches = ifStatement.getBranches();
|
||||||
|
assert(branches.length > 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. These would be added stack wise, so we need to pop them like backwards
|
||||||
|
* 2. Then a reversal at the end (generated instructions list)
|
||||||
|
*
|
||||||
|
* FIXME: EIther used siggned or the hack below lmao, out of boounds
|
||||||
|
*/
|
||||||
|
for(ulong branchIdx = branches.length-1; true; branchIdx--)
|
||||||
|
{
|
||||||
|
Branch branch = branches[branchIdx];
|
||||||
|
|
||||||
|
// Pop off an expression instruction (if it exists)
|
||||||
|
Value branchConditionInstr;
|
||||||
|
if(branch.hasCondition())
|
||||||
|
{
|
||||||
|
Instruction instr = popInstr();
|
||||||
|
gprintln("BranchIdx: "~to!(string)(branchIdx));
|
||||||
|
gprintln("Instr is: "~to!(string)(instr));
|
||||||
|
branchConditionInstr = cast(Value)instr;
|
||||||
|
assert(branchConditionInstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the number of body instructions to pop
|
||||||
|
ulong bodyCount = branch.getBody().length;
|
||||||
|
ulong i = 0;
|
||||||
|
Instruction[] bodyInstructions;
|
||||||
|
|
||||||
|
|
||||||
|
while(i < bodyCount)
|
||||||
|
{
|
||||||
|
Instruction bodyInstr = tailPopInstr();
|
||||||
|
bodyInstructions~=bodyInstr;
|
||||||
|
|
||||||
|
gprintln("tailPopp'd("~to!(string)(i)~"/"~to!(string)(bodyCount-1)~"): "~to!(string)(bodyInstr));
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the body instructions (correct ordering)
|
||||||
|
bodyInstructions=reverse(bodyInstructions);
|
||||||
|
|
||||||
|
// Create the branch instruction (coupling the condition instruction and body instructions)
|
||||||
|
branchInstructions~=new BranchInstruction(branchConditionInstr, bodyInstructions);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(branchIdx == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Reverse the list to be in the correct order (it was computed backwards)
|
||||||
|
branchInstructions=reverse(branchInstructions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code gen
|
||||||
|
*
|
||||||
|
* 1. Create the IfStatementInstruction containing the BranchInstruction[](s)
|
||||||
|
* 2. Set the context
|
||||||
|
* 3. Add the instruction
|
||||||
|
*/
|
||||||
|
IfStatementInstruction ifStatementInstruction = new IfStatementInstruction(branchInstructions);
|
||||||
|
ifStatementInstruction.context = ifStatement.getContext();
|
||||||
|
addInstrB(ifStatementInstruction);
|
||||||
|
|
||||||
|
gprintln("If!");
|
||||||
|
}
|
||||||
|
/* Branch */
|
||||||
|
else if(cast(Branch)statement)
|
||||||
|
{
|
||||||
|
Branch branch = cast(Branch)statement;
|
||||||
|
|
||||||
|
gprintln("Look at that y'all, cause this is it: "~to!(string)(branch));
|
||||||
|
}
|
||||||
/* Case of no matches */
|
/* Case of no matches */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -299,6 +299,11 @@ public class DNode
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string toString()
|
||||||
|
{
|
||||||
|
return "[DNode: "~to!(string)(entity)~"]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -697,9 +702,12 @@ public class DNodeGenerator
|
||||||
/* What we need to do is set the variable itself me thinks */
|
/* What we need to do is set the variable itself me thinks */
|
||||||
/* NOTE: But the above seems to also be needed */
|
/* NOTE: But the above seems to also be needed */
|
||||||
|
|
||||||
|
/* FIXME: Remove the context sets below */
|
||||||
|
|
||||||
/* NOTE: Fix is below I think (it doesn't crash then) */
|
/* NOTE: Fix is below I think (it doesn't crash then) */
|
||||||
/* Set context for expression and the variable itself */
|
/* Set context for expression and the variable itself */
|
||||||
varExp.setContext(context);
|
varExp.setContext(context);
|
||||||
|
gprintln("Context (after): "~to!(string)(varExp.getContext().getContainer()));
|
||||||
Entity bruh = tc.getResolver().resolveBest(context.getContainer(), path);
|
Entity bruh = tc.getResolver().resolveBest(context.getContainer(), path);
|
||||||
bruh.setContext(context);
|
bruh.setContext(context);
|
||||||
|
|
||||||
|
@ -1171,12 +1179,15 @@ public class DNodeGenerator
|
||||||
gprintln("generalPass(): Processing entity: "~entity.toString());
|
gprintln("generalPass(): Processing entity: "~entity.toString());
|
||||||
|
|
||||||
Entity ent = cast(Entity)entity;
|
Entity ent = cast(Entity)entity;
|
||||||
if(ent && ent.getModifierType() != InitScope.STATIC && ignoreInitScope)
|
// NOTE: COme back to and re-enable when this makes sense (IF it even needs to be here)
|
||||||
{
|
// if(ent && ent.getModifierType() != InitScope.STATIC && ignoreInitScope)
|
||||||
writeln("Did we just skip someone?");
|
// {
|
||||||
writeln(ent);
|
// writeln("Did we just skip someone?");
|
||||||
continue;
|
// writeln("InitScope: "~to!(string)(ent.getModifierType()));
|
||||||
}
|
// writeln(ent);
|
||||||
|
// //TODO: Come back to this and check it!!!!! Maybe this can be removed!
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Variable paremeters (for functions)
|
* Variable paremeters (for functions)
|
||||||
|
@ -1243,25 +1254,9 @@ public class DNodeGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set this variable as a dependency of this module */
|
|
||||||
// node.needs(variableDNode);
|
|
||||||
|
|
||||||
/* Set as visited */
|
/* Set as visited */
|
||||||
variableDNode.markVisited();
|
variableDNode.markVisited();
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FIXME
|
|
||||||
*
|
|
||||||
* I propose a major restructuring of variable and assignments
|
|
||||||
* along with typecheck and the way it does things. It doesn't
|
|
||||||
* make sense that varNode -> (depends on) varAss. No, varAss
|
|
||||||
* depends on varNode. Doing so would also then give us
|
|
||||||
* the correct ordering and NO swapping would be required.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* If there is an assignment attached to this */
|
/* If there is an assignment attached to this */
|
||||||
if(variable.getAssignment())
|
if(variable.getAssignment())
|
||||||
{
|
{
|
||||||
|
@ -1278,22 +1273,13 @@ public class DNodeGenerator
|
||||||
VariableAssignmentNode varAssignNode = new VariableAssignmentNode(this, varAssign);
|
VariableAssignmentNode varAssignNode = new VariableAssignmentNode(this, varAssign);
|
||||||
varAssignNode.needs(expressionNode);
|
varAssignNode.needs(expressionNode);
|
||||||
|
|
||||||
/* This assignment is now dependent on the variable declaration */
|
/* The variable declaration is dependant on the assignment */
|
||||||
varAssignNode.needs(variableDNode);
|
variableDNode.needs(varAssignNode);
|
||||||
|
|
||||||
/* The current container is dependent on this running */
|
|
||||||
node.needs(varAssignNode);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
/* If there is no assignment */
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* The current container is dependent on this variable declaration */
|
/* The current container is dependent on this variable declaration */
|
||||||
node.needs(variableDNode);
|
node.needs(variableDNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Variable asignments
|
* Variable asignments
|
||||||
*/
|
*/
|
||||||
|
@ -1365,7 +1351,56 @@ public class DNodeGenerator
|
||||||
/* Make this container depend on this return statement */
|
/* Make this container depend on this return statement */
|
||||||
node.needs(returnStatementDNode);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
|
|
@ -217,6 +217,7 @@ public final class Resolver
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/* Try find the Entity within the current Contaier */
|
/* Try find the Entity within the current Contaier */
|
||||||
|
gprintln("resolveUp("~to!(string)(currentContainer)~", "~name~")");
|
||||||
Entity entity = resolveWithin(currentContainer, name);
|
Entity entity = resolveWithin(currentContainer, name);
|
||||||
gprintln("Poes");
|
gprintln("Poes");
|
||||||
gprintln(entity);
|
gprintln(entity);
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
module nested_conditionals;
|
||||||
|
|
||||||
|
void banana()
|
||||||
|
{
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
if(i == 1)
|
||||||
|
{
|
||||||
|
int pp = 22+2;
|
||||||
|
|
||||||
|
if(i == 2+1+i+pp)
|
||||||
|
{
|
||||||
|
if(i == 3+i)
|
||||||
|
{
|
||||||
|
i=23;
|
||||||
|
}
|
||||||
|
else if(1 == 1)
|
||||||
|
{
|
||||||
|
i=50;
|
||||||
|
|
||||||
|
if(50 == 5+2)
|
||||||
|
{
|
||||||
|
i=51;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i=6969696;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
module simple_conditions;
|
||||||
|
|
||||||
|
int other(int arg1, int arg2)
|
||||||
|
{
|
||||||
|
return 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
void function(int i)
|
||||||
|
{
|
||||||
|
int apple = 69;
|
||||||
|
|
||||||
|
if(i == 1)
|
||||||
|
{
|
||||||
|
apple = 2;
|
||||||
|
i = i +3;
|
||||||
|
|
||||||
|
if(i == 40)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(i == 41)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(i == 2)
|
||||||
|
{
|
||||||
|
i = i +2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int banana = 24;
|
||||||
|
banana=2+i;
|
||||||
|
|
||||||
|
if(banana == 2+2+other(2,2))
|
||||||
|
{
|
||||||
|
banana=2;
|
||||||
|
banana=3;
|
||||||
|
banana = other(2,3)+other(3,4);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pp = other(80,81);
|
||||||
|
}
|
Loading…
Reference in New Issue