tlang/source/tlang/compiler/symbols/data.d

1630 lines
40 KiB
D

module tlang.compiler.symbols.data;
public import tlang.compiler.symbols.check;
import std.conv : to;
import tlang.compiler.typecheck.dependency.core : Context;
/**
* TODO: Implement the blow and use them
*
* These are just to use for keeping track of what
* valid identifiers are.
*
* Actually it might be, yeah it will
*/
public class Program
{
private string moduleName;
private Program[] importedModules;
private Statement[] statements;
this(string moduleName)
{
this.moduleName = moduleName;
}
public void addStatement(Statement statement)
{
statements ~= statement;
}
public static StatementType[] getAllOf(StatementType)(StatementType, Statement[] statements)
{
StatementType[] statementsMatched;
foreach(Statement statement; statements)
{
/* TODO: Remove null, this is for unimpemented */
if(statement !is null && cast(StatementType)statement)
{
statementsMatched ~= cast(StatementType)statement;
}
}
return statementsMatched;
}
public Variable[] getGlobals()
{
Variable[] variables;
foreach(Statement statement; statements)
{
if(typeid(statement) == typeid(Variable))
{
variables ~= cast(Variable)statement;
}
}
return variables;
}
/* TODO: Make this use weights */
public Statement[] getStatements()
{
/* Re-ordered by lowest wieght first */
Statement[] stmntsRed;
bool wCmp(Statement lhs, Statement rhs)
{
return lhs.weight < rhs.weight;
}
import std.algorithm.sorting;
stmntsRed = sort!(wCmp)(statements).release;
return stmntsRed;
}
}
public class Statement
{
public byte weight = 0;
/* !!!! BEGIN TYPE CHECK ROUTINES AND DATA !!!! */
/* TODO: Used for type checking */
public Context context;
public void setContext(Context context)
{
this.context = context;
}
public Context getContext()
{
return context;
}
/* !!!! END TYPE CHECK ROUTINES AND DATA !!!! */
private static ulong rollingCount = 0;
private Container container;
public final void parentTo(Container container)
{
this.container = container;
}
public final Container parentOf()
{
return container;
}
public override string toString()
{
return to!(string)(rollingCount++);
}
}
public enum AccessorType
{
PUBLIC, PRIVATE, PROTECTED, UNKNOWN
}
public enum InitScope
{
VIRTUAL, STATIC, UNKNOWN
}
public class Assignment : Statement
{
private string identifier;
private Expression assignmentExpression;
this(string identifier, Expression assignmentExpression)
{
this.identifier = identifier;
this.assignmentExpression = assignmentExpression;
}
}
/**
* Entity
*
* Declared variables, defined classes and functions
*/
public class Entity : Statement
{
/* Accessor type */
private AccessorType accessorType = AccessorType.PUBLIC;
/* Function/Modifier type */
private InitScope initScope;
/* Name of the entity (class's name, function's name, variable's name) */
protected string name;
/* If this entity is extern'd */
private bool isExternalEntity;
this(string name, bool isExternalEntity = false)
{
this.name = name;
this.isExternalEntity = isExternalEntity;
}
public bool isExternal()
{
return isExternalEntity;
}
public void makeExternal()
{
isExternalEntity = true;
}
public void setAccessorType(AccessorType accessorType)
{
this.accessorType = accessorType;
}
public AccessorType getAccessorType()
{
return accessorType;
}
public void setModifierType(InitScope initScope)
{
this.initScope = initScope;
}
public InitScope getModifierType()
{
return initScope;
}
public string getName()
{
return name;
}
}
/* TODO: DO we need intermediary class, TypedEntity */
import tlang.compiler.symbols.mcro : MTypeRewritable;
public class TypedEntity : Entity, MTypeRewritable
{
private string type;
/* TODO: Return type/variable type in here (do what we did for ENtity with `name/identifier`) */
this(string name, string type)
{
super(name);
this.type = type;
}
public string getType()
{
return type;
}
public void setType(string type)
{
this.type = type;
}
}
public import tlang.compiler.symbols.containers;
/**
* VariableParameter
*
* Represents a kindof-Variable which is used to indicate
* it is a function's parameter - to differentiate between
* those and other variables like local/global definitions
* and so on
*
* These are only to be used in the `Function` class (below)
*/
public final class VariableParameter : Variable
{
this(string type, string identifier)
{
super(type, identifier);
}
}
/* TODO: Don't make this a Container, or maybe (make sure I don't rely on COntainer casting for other shit
* though, also the recent changes) */
public class Function : TypedEntity, Container
{
private VariableParameter[] params;
private Statement[] bodyStatements;
this(string name, string returnType, Statement[] bodyStatements, VariableParameter[] params)
{
super(name, returnType);
// Add the parameters first THEN the function's body statements
// because they must be available before other statements
// which may reference them, Secondly they must be added (the VariableParameter(s))
// such that they are lookup-able.
addStatements(cast(Statement[])params);
// Add the funciton's body
addStatements(bodyStatements);
// Save a seperate copy of the parameters (to seperate them from the
// other body stetements)
this.params = params;
/* Weighted as 1 */
weight = 1;
}
public VariableParameter[] getParams()
{
return params;
}
public bool hasParams()
{
return params.length != 0;
}
public void addStatement(Statement statement)
{
this.bodyStatements~=statement;
}
public void addStatements(Statement[] statements)
{
this.bodyStatements~=statements;
}
public Statement[] getStatements()
{
import tlang.compiler.symbols.containers : weightReorder;
return weightReorder(bodyStatements);
}
/**
* This will sift through all the `Statement[]`'s in held
* within this Function and will find those which are Variable
*/
public Variable[] getVariables()
{
Variable[] variables;
foreach(Statement statement; bodyStatements)
{
if(statement !is null && cast(Variable)statement)
{
variables ~= cast(Variable)statement;
}
}
return variables;
}
public override string toString()
{
string argTypes;
for(ulong i = 0; i < params.length; i++)
{
Variable variable = params[i];
if(i == params.length-1)
{
argTypes ~= variable.getType();
}
else
{
argTypes ~= variable.getType() ~ ", ";
}
}
return "Function (Name: "~name~", ReturnType: "~type~", Args: "~argTypes~")";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on each `Statement` making up our body */
// NOTE: Using weight-reordered? Is that fine?
foreach(Statement curStmt; getStatements())
{
MStatementSearchable curStmtCasted = cast(MStatementSearchable)curStmt;
if(curStmtCasted)
{
matches ~= curStmtCasted.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If not ourself, then check the body statements */
else
{
/**
* First check each `Statement` that make sup our
* body and see if we can replace that, else see
* if we can recurse on each of the body statements
* and apply replacement therein
*/
// NOTE: Using weight-reordered? Is that fine?
Statement[] bodyStmts = getStatements();
for(ulong idx = 0; idx < bodyStmts.length; idx++)
{
Statement curBodyStmt = bodyStmts[idx];
/* Should we directly replace the Statement in the body? */
if(curBodyStmt == thiz)
{
// Replace the statement in the body
// NOTE: The respective Variable Param must be swapped out too if need be
// (varParams[] subsetOf Statements[])
for(ulong varParamIdx = 0; varParamIdx < params.length; varParamIdx++)
{
VariableParameter curVarParam = params[varParamIdx];
if(curVarParam == thiz)
{
params[varParamIdx] = cast(VariableParameter)that;
break;
}
}
bodyStatements[idx] = that;
// Re-parent `that` to us
that.parentTo(this);
return true;
}
/* If we cannot, then recurse (try) on it */
else if(cast(MStatementReplaceable)curBodyStmt)
{
MStatementReplaceable curBodyStmtRepl = cast(MStatementReplaceable)curBodyStmt;
if(curBodyStmtRepl.replace(thiz, that))
{
return true;
}
}
}
return false;
}
}
}
public class Variable : TypedEntity, MStatementSearchable, MStatementReplaceable
{
/* TODO: Just make this an Expression */
private VariableAssignment assignment;
this(string type, string identifier)
{
super(identifier, type);
/* Weighted as 2 */
weight = 2;
}
public void addAssignment(VariableAssignment assignment)
{
this.assignment = assignment;
}
public VariableAssignment getAssignment()
{
return assignment;
}
public override string toString()
{
return "Variable (Ident: "~name~", Type: "~type~")";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/**
* Recurse on the `VariableAssignment`
*/
MStatementSearchable innerStmt = cast(MStatementSearchable)assignment;
if(innerStmt)
{
matches ~= innerStmt.search(clazzType);
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we, the `Variable`, are the `thiz` then we cannot perform replacement */
if(this == thiz)
{
return false;
}
/* Check if we should replace the `VariableAssignment` */
else if(thiz == assignment)
{
assignment = cast(VariableAssignment)that;
return true;
}
/* Recurse on the variable assignment */
else
{
return assignment.replace(thiz, that);
}
}
}
public import tlang.compiler.symbols.expressions;
/**
* TODO: Rename to `VariableDeclarationAssignment`
*/
public class VariableAssignment : Statement, MStatementSearchable, MStatementReplaceable
{
private Expression expression;
private Variable variable;
this(Expression expression)
{
this.expression = expression;
}
public Expression getExpression()
{
return expression;
}
public Variable getVariable()
{
return variable;
}
// NOTE-to-self: Very interesting method we have here, is this just for debugging?
// (15th May 2023, whilst working on Meta)
public void setVariable(Variable variable)
{
this.variable = variable;
}
public override string toString()
{
return "[varAssignDec'd: To: "~variable.toString()~"]";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on our `Expression` (if possible) */
MStatementSearchable innerStmt = cast(MStatementSearchable)expression;
if(innerStmt)
{
matches ~= innerStmt.search(clazzType);
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* We cannot replace ourselves directly */
if(this == thiz)
{
return false;
}
/* Is the `Expression` the `thiz`, then swap out the expression */
else if(expression == thiz)
{
// TODO: Any reparenting needed?
expression = cast(Expression)that;
return true;
}
/* Recurse on the `Expression` being assigned (if possible) */
else if(cast(MStatementReplaceable)expression)
{
MStatementReplaceable replStmt = cast(MStatementReplaceable)expression;
return replStmt.replace(thiz, that);
}
/* If not matched */
else
{
return false;
}
}
}
/**
* TODO: Rename to ``
*/
public class VariableAssignmentStdAlone : Statement, MStatementSearchable, MStatementReplaceable
{
private Expression expression;
private string varName;
this(string varName, Expression expression)
{
this.varName = varName;
this.expression = expression;
/* Weighted as 2 */
weight = 2;
}
public Expression getExpression()
{
return expression;
}
public string getVariableName()
{
return varName;
}
public override string toString()
{
return "[varAssignStdAlone: To: "~varName~"]";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/**
* Recurse on the assigned `Expression`
*/
MStatementSearchable assignedStmtCasted = cast(MStatementSearchable)expression;
if(assignedStmtCasted)
{
matches ~= assignedStmtCasted.search(clazzType);
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we, the `VariableAssignmentStdAlone`, are the `thiz` then we cannot perform replacement */
if(this == thiz)
{
return false;
}
/* Check if we should replace the `Expression` being assigned? */
else if(thiz == expression)
{
expression = cast(Expression)that;
return true;
}
/* Recurse on the assigned `Expression` (if possible) */
else if(cast(MStatementReplaceable)expression)
{
MStatementReplaceable expressionCasted = cast(MStatementReplaceable)expression;
return expressionCasted.replace(thiz, that);
}
/* None */
else
{
return false;
}
}
}
// TODO: Add an ArrayAssignment thing here, would be similiar to PointerDeference
// mmmh, we would also need to ensure during typechecking/codegen/emit that we don't
// do pointer arithmetic. Makes sense we would have a ArrayAssign and expression for indexers
// but during codegen we check WHO was being assigned to and their type and based on that
// generate the correct INSTRUCTION
public final class ArrayAssignment : Statement
{
private Expression assignmentExpression;
/**
* The left hand side of:
* e.g. myArray[i][1] = 2;
*
* Therefore the `myArray[i][1]` part
*/
private ArrayIndex leftHandExpression;
this(ArrayIndex leftHandExpression, Expression assignmentExpression)
{
this.leftHandExpression = leftHandExpression;
this.assignmentExpression = assignmentExpression;
/* Weighted as 2 */
weight = 2;
}
public ArrayIndex getArrayLeft()
{
return leftHandExpression;
}
public Expression getAssignmentExpression()
{
return assignmentExpression;
}
public override string toString()
{
return "ArrayAssignment [leftHand: "~leftHandExpression.toString()~", assignmentExpr: "~assignmentExpression.toString()~"]";
}
}
public class PointerDereferenceAssignment : Statement
{
private Expression assignmentExpression;
private Expression pointerExpression;
private ulong derefCount;
this(Expression pointerExpression, Expression assignmentExpression, ulong derefCount = 1)
{
this.pointerExpression = pointerExpression;
this.assignmentExpression = assignmentExpression;
this.derefCount = derefCount;
/* Weighted as 2 */
weight = 2;
}
public Expression getExpression()
{
return assignmentExpression;
}
public Expression getPointerExpression()
{
return pointerExpression;
}
public ulong getDerefCount()
{
return derefCount;
}
public override string toString()
{
return "[pointerDeref: From: "~pointerExpression.toString()~"]";
}
}
public class IdentExpression : Expression, MStatementSearchable, MStatementReplaceable
{
/* name */
private string name;
this(string name)
{
this.name = name;
}
public string getName()
{
return name;
}
public void updateName(string newName)
{
name = newName;
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
// Nothing to replace within us
return false;
}
}
public class VariableExpression : IdentExpression
{
this(string identifier)
{
super(identifier);
}
import tlang.compiler.typecheck.core;
public override string evaluateType(TypeChecker typeChecker, Container c)
{
string type;
return null;
}
public override string toString()
{
return "[varExp: "~getName()~"]";
}
}
public class Call : IdentExpression
{
this(string ident)
{
super(ident);
}
}
// FIXME: Finish adding proper `MStatementSearchable` and `MStatementReplaceable` to `FunctionCall`
public final class FunctionCall : Call, MStatementSearchable, MStatementReplaceable
{
/* Whether this is statement-level function call or not */
/**
* Function calls either appear as part of an expression
* (i.e. from `parseExpression()`) or directly as a statement
* in the body of a `Container`. This affects how code generation
* works and hence one needs to disambiguate between the two.
*/
private bool isStatementLevel = false;
/* Argument list */
private Expression[] arguments;
this(string functionName, Expression[] arguments)
{
super(functionName);
this.arguments = arguments;
}
public override string toString()
{
return super.toString()~" "~name~"()";
}
public Expression[] getCallArguments()
{
return arguments;
}
/**
* Mark this function call as statement-level
*/
public void makeStatementLevel()
{
this.isStatementLevel = true;
}
/**
* Determines if this function call is statement-level
*
* Returns: true if so, false otherwise
*/
public bool isStatementLevelFuncCall()
{
return isStatementLevel;
}
public override Statement[] search(TypeInfo_Class clazzType)
{
// TODO: Implement me
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/**
* Recurse on each `Expression` (if possible)
*/
foreach(Expression callExp; arguments)
{
MStatementSearchable innerStmt = cast(MStatementSearchable)callExp;
if(innerStmt)
{
matches ~= innerStmt.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
// TODO: Implement me
// /* Check if our `Expression` matches, then replace */
// if(expression == thiz)
// {
// // NOTE: This legit makes no sense and won't do anything, we could remove this
// // and honestly should probably make this return false
// // FIXME: Make this return `false` (see above)
// expression = cast(Expression)that;
// return true;
// }
// /* If not direct match, then recurse and replace (if possible) */
// else if(cast(MStatementReplaceable)expression)
// {
// MStatementReplaceable replStmt = cast(MStatementReplaceable)expression;
// return replStmt.replace(thiz, that);
// }
// /* If not direct match and not replaceable */
// else
// {
// return false;
// }
return true;
}
}
/**
* ReturnStmt
*
* Represents a return statement with an expression
* to be returned
*/
public final class ReturnStmt : Statement
{
// The Expression being returned
private Expression returnExpression;
this(Expression returnExpression)
{
this.returnExpression = returnExpression;
this();
}
this()
{
/* Statement level weighting is 2 */
weight = 2;
}
public Expression getReturnExpression()
{
return returnExpression;
}
public bool hasReturnExpression()
{
return returnExpression !is null;
}
}
/**
* IfStatement
*
* Represents an if statement with branches of code
* and conditions per each
*/
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";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Loop through each `Branch` and recurse on them */
foreach(Branch curBranch; branches)
{
matches ~= curBranch.search(clazzType);
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If not ourself, then check each `Branch` or recurse on them */
else
{
/**
* First check each `Branch` that makes up our
* branches array and see if we can replace that,
* else see if we can recurse on each of the branche
* and apply replacement therein
*/
Statement[] bodyStmts = getStatements();
for(ulong idx = 0; idx < bodyStmts.length; idx++)
{
Statement curBodyStmt = bodyStmts[idx];
/* Should we directly replace the Statement in the body? */
if(curBodyStmt == thiz)
{
// Replace the statement in the body
// FIXME: Apply parenting? Yes we should
branches[idx] = cast(Branch)that;
return true;
}
/* If we cannot, then recurse (try) on it */
else if(cast(MStatementReplaceable)curBodyStmt)
{
MStatementReplaceable curBodyStmtRepl = cast(MStatementReplaceable)curBodyStmt;
if(curBodyStmtRepl.replace(thiz, that))
{
return true;
}
}
}
return false;
}
}
}
/**
* 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";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on the the `Branch` */
if(cast(MStatementSearchable)branch)
{
MStatementSearchable branchCasted = cast(MStatementSearchable)branch;
if(branchCasted)
{
matches ~= branchCasted.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If the `Branch` is to be replaced */
else if(branch == thiz)
{
branch = cast(Branch)that;
return true;
}
/* If not ourself, then recurse on the `Branch` */
else
{
return branch.replace(thiz, that);
}
}
}
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 <code>Statement</code> to run before
* beginning the first iteration
* branch = The <code>Branch</code> 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";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on the pre-loop `Statement` */
if(cast(MStatementSearchable)preLoopStatement)
{
MStatementSearchable preLoopStatementCasted = cast(MStatementSearchable)preLoopStatement;
if(preLoopStatementCasted)
{
matches ~= preLoopStatementCasted.search(clazzType);
}
}
/* Recurse on the the `Branch` */
if(cast(MStatementSearchable)branch)
{
MStatementSearchable branchCasted = cast(MStatementSearchable)branch;
if(branchCasted)
{
matches ~= branchCasted.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If the `Branch` is to be replaced */
else if(branch == thiz)
{
branch = cast(Branch)that;
return true;
}
/* If the pre-loop `Statement` is to be replaced */
else if(preLoopStatement == thiz)
{
preLoopStatement = cast(Statement)that;
return true;
}
/* If not ourself, then recurse on the `Branch` */
else
{
return branch.replace(thiz, that);
}
}
}
/**
* 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;
/**
* 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)
{
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);
}
/**
* Returns the condition of the branch
*
* Returns: The condition as an instance of <code>Expression</code>
*/
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";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on the branch condition `Expression` */
if(cast(MStatementSearchable)branchCondition)
{
MStatementSearchable branchConditionCasted = cast(MStatementSearchable)branchCondition;
if(branchConditionCasted)
{
matches ~= branchConditionCasted.search(clazzType);
}
}
/* Recurse on each `Statement` making up our body */
// NOTE: Using weight-reordered? Is that fine?
foreach(Statement curStmt; getStatements())
{
MStatementSearchable curStmtCasted = cast(MStatementSearchable)curStmt;
if(curStmtCasted)
{
matches ~= curStmtCasted.search(clazzType);
}
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
/* If we (`this`) are `thiz`, then we cannot replace */
if(this == thiz)
{
return false;
}
/* If the branch condition `Expression` is matching */
else if(branchCondition == thiz)
{
branchCondition = cast(Expression)that;
return true;
}
/* If not ourself, then check the body statements */
else
{
/**
* First check each `Statement` that make sup our
* body and see if we can replace that, else see
* if we can recurse on each of the body statements
* and apply replacement therein
*/
// NOTE: Using weight-reordered? Is that fine?
Statement[] bodyStmts = getStatements();
for(ulong idx = 0; idx < bodyStmts.length; idx++)
{
Statement curBodyStmt = bodyStmts[idx];
/* Should we directly replace the Statement in the body? */
if(curBodyStmt == thiz)
{
// Replace the statement in the body
// FIXME: Apply parenting? Yes we should
branchBody[idx] = that;
return true;
}
/* If we cannot, then recurse (try) on it */
else if(cast(MStatementReplaceable)curBodyStmt)
{
MStatementReplaceable curBodyStmtRepl = cast(MStatementReplaceable)curBodyStmt;
if(curBodyStmtRepl.replace(thiz, that))
{
return true;
}
}
}
return false;
}
}
}
import tlang.compiler.symbols.mcro : MStatementSearchable, MStatementReplaceable;
public final class DiscardStatement : Statement, MStatementSearchable, MStatementReplaceable
{
private Expression expression;
this(Expression expression)
{
this.expression = expression;
/* Weighted as 2 */
weight = 2;
}
public Expression getExpression()
{
return expression;
}
public override string toString()
{
return "[DiscardStatement: (Exp: "~expression.toString()~")]";
}
public override Statement[] search(TypeInfo_Class clazzType)
{
/* List of returned matches */
Statement[] matches;
/* Are we (ourselves) of this type? */
if(clazzType.isBaseOf(this.classinfo))
{
matches ~= [this];
}
/* Recurse on our `Expression` (if possible) */
MStatementSearchable innerStmt = cast(MStatementSearchable)expression;
if(innerStmt)
{
matches ~= innerStmt.search(clazzType);
}
return matches;
}
public override bool replace(Statement thiz, Statement that)
{
import std.stdio;
writeln("Replace() enter discard");
/* Check if our `Expression` matches, then replace */
if(expression == thiz)
{
// NOTE: This legit makes no sense and won't do anything, we could remove this
// and honestly should probably make this return false
// FIXME: Make this return `false` (see above)
expression = cast(Expression)that;
return true;
}
/* If not direct match, then recurse and replace (if possible) */
else if(cast(MStatementReplaceable)expression)
{
MStatementReplaceable replStmt = cast(MStatementReplaceable)expression;
return replStmt.replace(thiz, that);
}
/* If not direct match and not replaceable */
else
{
return false;
}
}
}
public final class ExternStmt : Statement
{
// Pseudo entity created
private Entity pseudoEntity;
private SymbolType externType;
this(Entity pseudoEntity, SymbolType externType)
{
// External symbols are either external functions or external variables
assert(externType == SymbolType.EXTERN_EFUNC || externType == SymbolType.EXTERN_EVAR);
this.pseudoEntity = pseudoEntity;
this.externType = externType;
}
public string getExternalName()
{
return pseudoEntity.getName();
}
public SymbolType getExternType()
{
return externType;
}
public Entity getPseudoEntity()
{
return pseudoEntity;
}
public override string toString()
{
return "[ExternStatement: (Symbol name: "~getExternalName()~")]";
}
}