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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
import std.stdio;
|
||||
writeln("\n");
|
||||
gprintln("transform(): "~to!(string)(instruction));
|
||||
transformDepth++;
|
||||
|
||||
// At any return decrement the depth
|
||||
scope(exit)
|
||||
{
|
||||
transformDepth--;
|
||||
}
|
||||
|
||||
/* VariableAssignmentInstr */
|
||||
if(cast(VariableAssignmentInstr)instruction)
|
||||
|
@ -94,10 +112,12 @@ public final class DCodeEmitter : CodeEmitter
|
|||
varDecWantsConsumeVarAss = true;
|
||||
|
||||
// Fetch the variable assignment instruction
|
||||
gprintln("Before crash: "~to!(string)(getCurrentInstruction()));
|
||||
nextInstruction();
|
||||
Instruction varAssInstr = getCurrentInstruction();
|
||||
// gprintln("Before crash: "~to!(string)(getCurrentInstruction()));
|
||||
// nextInstruction();
|
||||
// Instruction varAssInstr = getCurrentInstruction();
|
||||
|
||||
VariableAssignmentInstr varAssInstr = varDecInstr.getAssignmentInstr();
|
||||
|
||||
// Generate the code to emit
|
||||
return varDecInstr.varType~" "~renamedSymbol~" = "~transform(varAssInstr)~";";
|
||||
}
|
||||
|
@ -139,6 +159,8 @@ public final class DCodeEmitter : CodeEmitter
|
|||
|
||||
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);
|
||||
}
|
||||
/* FuncCallInstr */
|
||||
|
@ -199,6 +221,56 @@ public final class DCodeEmitter : CodeEmitter
|
|||
|
||||
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)~">";
|
||||
}
|
||||
|
@ -379,6 +451,8 @@ public final class DCodeEmitter : CodeEmitter
|
|||
{
|
||||
//TODO: Implement me
|
||||
|
||||
if(cmp(typeChecker.getModule().getName(), "simple_functions") == 0)
|
||||
{
|
||||
// NOTE: Remove this printf
|
||||
file.writeln(`
|
||||
// NOTE: The below is testing code and should be removed
|
||||
|
@ -390,6 +464,16 @@ int main()
|
|||
printf("k: %u\n", t_7b6d477c5859059f16bc9da72fc8cc3b);
|
||||
return 0;
|
||||
}`);
|
||||
}
|
||||
else
|
||||
{
|
||||
file.writeln(`
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -80,15 +80,26 @@ public final class VariableDeclaration : StorageDeclaration
|
|||
/* Type of the variable being declared */
|
||||
public const string varType;
|
||||
|
||||
/* VariableAssignmentInstr-instruction to be assigned */
|
||||
private VariableAssignmentInstr varAssInstr;
|
||||
|
||||
//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.length = len;
|
||||
this.varType = varType;
|
||||
|
||||
this.varAssInstr = varAssInstr;
|
||||
|
||||
addInfo = "varName: "~varName;
|
||||
}
|
||||
|
||||
public VariableAssignmentInstr getAssignmentInstr()
|
||||
{
|
||||
return varAssInstr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final class FetchValueVar : Value
|
||||
|
@ -288,4 +299,50 @@ public final class ReturnInstruction : Instruction
|
|||
{
|
||||
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) */
|
||||
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
|
||||
currentTokens ~= new Token("==", line, column);
|
||||
|
||||
|
@ -808,6 +815,14 @@ unittest
|
|||
currentLexer.performLex();
|
||||
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)]);
|
||||
|
||||
// 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
|
||||
*
|
||||
* TODO: Check kanban
|
||||
* TOOD: THis should return something
|
||||
*/
|
||||
private void parseIf()
|
||||
private IfStatement parseIf()
|
||||
{
|
||||
gprintln("parseIf(): Enter", DebugType.WARNING);
|
||||
|
||||
IfStatement ifStmt;
|
||||
Branch[] branches;
|
||||
|
||||
while (hasTokens())
|
||||
{
|
||||
{
|
||||
Expression currentBranchCondition;
|
||||
Statement[] currentBranchBody;
|
||||
|
||||
/* This will only be called once (it is what caused a call to parseIf()) */
|
||||
if (getSymbolType(getCurrentToken()) == SymbolType.IF)
|
||||
{
|
||||
|
@ -125,7 +132,7 @@ public final class Parser
|
|||
nextToken();
|
||||
|
||||
/* Parse an expression (for the condition) */
|
||||
parseExpression();
|
||||
currentBranchCondition = parseExpression();
|
||||
expect(SymbolType.RBRACE, getCurrentToken());
|
||||
|
||||
/* Opening { */
|
||||
|
@ -133,9 +140,14 @@ public final class Parser
|
|||
expect(SymbolType.OCURLY, getCurrentToken());
|
||||
|
||||
/* Parse the if' statement's body AND expect a closing curly */
|
||||
parseBody();
|
||||
currentBranchBody = parseBody();
|
||||
expect(SymbolType.CCURLY, getCurrentToken());
|
||||
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 */
|
||||
else if (getSymbolType(getCurrentToken()) == SymbolType.ELSE)
|
||||
|
@ -154,7 +166,7 @@ public final class Parser
|
|||
nextToken();
|
||||
|
||||
/* Parse an expression (for the condition) */
|
||||
parseExpression();
|
||||
currentBranchCondition = parseExpression();
|
||||
expect(SymbolType.RBRACE, getCurrentToken());
|
||||
|
||||
/* Opening { */
|
||||
|
@ -162,18 +174,28 @@ public final class Parser
|
|||
expect(SymbolType.OCURLY, getCurrentToken());
|
||||
|
||||
/* Parse the if' statement's body AND expect a closing curly */
|
||||
parseBody();
|
||||
currentBranchBody = parseBody();
|
||||
expect(SymbolType.CCURLY, getCurrentToken());
|
||||
nextToken();
|
||||
|
||||
/* Create a branch node */
|
||||
Branch branch = new Branch(currentBranchCondition, currentBranchBody);
|
||||
parentToContainer(branch, currentBranchBody);
|
||||
branches ~= branch;
|
||||
}
|
||||
/* Check for opening curly (just an "else" statement) */
|
||||
else if (getSymbolType(getCurrentToken()) == SymbolType.OCURLY)
|
||||
{
|
||||
/* Parse the if' statement's body (starting with `{` AND expect a closing curly */
|
||||
parseBody();
|
||||
currentBranchBody = parseBody();
|
||||
expect(SymbolType.CCURLY, getCurrentToken());
|
||||
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 */
|
||||
break;
|
||||
}
|
||||
|
@ -191,6 +213,13 @@ public final class Parser
|
|||
}
|
||||
|
||||
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()
|
||||
|
@ -490,7 +519,7 @@ public final class Parser
|
|||
/* If it is a branch */
|
||||
else if (symbol == SymbolType.IF)
|
||||
{
|
||||
parseIf();
|
||||
statements ~= parseIf();
|
||||
}
|
||||
/* If it is a while loop */
|
||||
else if (symbol == SymbolType.WHILE)
|
||||
|
|
|
@ -497,6 +497,10 @@ public string getCharacter(SymbolType symbolIn)
|
|||
{
|
||||
return "}";
|
||||
}
|
||||
else if(symbolIn == SymbolType.EQUALS)
|
||||
{
|
||||
return "==";
|
||||
}
|
||||
else
|
||||
{
|
||||
gprintln("getCharacter: No back-mapping for "~to!(string)(symbolIn), DebugType.ERROR);
|
||||
|
|
|
@ -550,4 +550,119 @@ public final class ReturnStmt : Statement
|
|||
{
|
||||
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.codegen.instruction;
|
||||
import std.container.slist;
|
||||
import std.algorithm : reverse;
|
||||
|
||||
/**
|
||||
* The Parser only makes sure syntax
|
||||
|
@ -272,6 +273,23 @@ public final class TypeChecker
|
|||
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()
|
||||
{
|
||||
return codeQueue.empty;
|
||||
|
@ -761,7 +779,7 @@ public final class TypeChecker
|
|||
VariableAssignmentInstr varAssInstr = new VariableAssignmentInstr(variableName, valueInstr);
|
||||
varAssInstr.context = variableAssignmentContext;
|
||||
|
||||
addInstrB(varAssInstr);
|
||||
addInstr(varAssInstr);
|
||||
}
|
||||
/* TODO: Add support */
|
||||
/**
|
||||
|
@ -782,7 +800,21 @@ public final class TypeChecker
|
|||
Variable variablePNode = cast(Variable)dnode.getEntity();
|
||||
gprintln("HELLO FELLA");
|
||||
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 */
|
||||
varDecInstr.context = variablePNode.context;
|
||||
|
@ -791,7 +823,7 @@ public final class TypeChecker
|
|||
addInstrB(varDecInstr);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/* TODO: Add class init, see #8 */
|
||||
|
@ -835,6 +867,8 @@ public final class TypeChecker
|
|||
vAInstr.context = vasa.getContext();
|
||||
|
||||
addInstrB(vAInstr);
|
||||
|
||||
gprintln("VariableAssignmentStdAlone", DebugType.ERROR);
|
||||
}
|
||||
/**
|
||||
* Return statement (ReturnStmt)
|
||||
|
@ -858,6 +892,92 @@ public final class TypeChecker
|
|||
returnInstr.context = returnStatement.getContext();
|
||||
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 */
|
||||
else
|
||||
{
|
||||
|
|
|
@ -299,6 +299,11 @@ public class DNode
|
|||
|
||||
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 */
|
||||
/* 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) */
|
||||
/* Set context for expression and the variable itself */
|
||||
varExp.setContext(context);
|
||||
gprintln("Context (after): "~to!(string)(varExp.getContext().getContainer()));
|
||||
Entity bruh = tc.getResolver().resolveBest(context.getContainer(), path);
|
||||
bruh.setContext(context);
|
||||
|
||||
|
@ -1171,12 +1179,15 @@ public class DNodeGenerator
|
|||
gprintln("generalPass(): Processing entity: "~entity.toString());
|
||||
|
||||
Entity ent = cast(Entity)entity;
|
||||
if(ent && ent.getModifierType() != InitScope.STATIC && ignoreInitScope)
|
||||
{
|
||||
writeln("Did we just skip someone?");
|
||||
writeln(ent);
|
||||
continue;
|
||||
}
|
||||
// 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("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)
|
||||
|
@ -1243,25 +1254,9 @@ public class DNodeGenerator
|
|||
}
|
||||
|
||||
|
||||
/* Set this variable as a dependency of this module */
|
||||
// node.needs(variableDNode);
|
||||
|
||||
/* Set as visited */
|
||||
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(variable.getAssignment())
|
||||
{
|
||||
|
@ -1278,21 +1273,12 @@ public class DNodeGenerator
|
|||
VariableAssignmentNode varAssignNode = new VariableAssignmentNode(this, varAssign);
|
||||
varAssignNode.needs(expressionNode);
|
||||
|
||||
/* This assignment is now dependent on the variable declaration */
|
||||
varAssignNode.needs(variableDNode);
|
||||
|
||||
/* 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 */
|
||||
node.needs(variableDNode);
|
||||
/* 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
|
||||
|
@ -1365,7 +1351,56 @@ public class DNodeGenerator
|
|||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
|
|
|
@ -217,6 +217,7 @@ public final class Resolver
|
|||
// }
|
||||
|
||||
/* Try find the Entity within the current Contaier */
|
||||
gprintln("resolveUp("~to!(string)(currentContainer)~", "~name~")");
|
||||
Entity entity = resolveWithin(currentContainer, name);
|
||||
gprintln("Poes");
|
||||
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