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); } 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 Branch that makes up this while * loop * isDoWhile = If true then interpret this as a * do-while loop, however if false * 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 Statement to run before * beginning the first iteration * branch = The Branch that makes up this for * loop */ this(Branch branch, Statement preLoopStatement = null, bool hasPostIterate = false) { forStmtContainerRollingNameCounter++; super("forStmt_"~to!(string)(forStmtContainerRollingNameCounter)); this.preLoopStatement = preLoopStatement; this.branch = branch; this.hasPostIterate = hasPostIterate; weight = 2; } public bool hasPostIterateStatement() { return hasPostIterate; } public bool hasPreRunStatement() { return !(preLoopStatement is null); } public Branch getBranch() { return branch; } public Statement getPreRunStatement() { return preLoopStatement; } public override void addStatement(Statement statement) { // You should only be adding one branch to a for loop assert(branch is null); branch = cast(Branch)statement; } public override void addStatements(Statement[] statements) { // Only one Branch in the given input list assert(statements.length == 1); // You should only be adding one branch to a for loop assert(branch is null); branch = (cast(Branch[])statements)[0]; } public override Statement[] getStatements() { // If there is a pre-run statement then prepend it if(hasPreRunStatement()) { return cast(Statement[])[preLoopStatement, branch]; } // If not, then just the Branch container else { return cast(Statement[])[branch]; } } public override string toString() { return "ForLoop"; } 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 Expression and a body * of Statement(s) apart of it * * Params: * condition = The condition as an Expression * branch = The body of Statement(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: true if so, false * otherwise */ public bool hasCondition() { return !(branchCondition is null); } /** * Returns the condition of the branch * * Returns: The condition as an instance of Expression */ 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()~")]"; } }