tlang/source/tlang/compiler/symbols/containers.d

451 lines
13 KiB
D

module tlang.compiler.symbols.containers;
import tlang.compiler.symbols.data;
import std.conv : to;
import tlang.compiler.symbols.typing.core;
// AST manipulation interfaces
import tlang.compiler.symbols.mcro : MStatementSearchable, MStatementReplaceable, MCloneable;
/**
* Used so often that we may as well
* declare it once
*
* TODO: Check if we could do it with interfaces?
*/
public Statement[] weightReorder(Statement[] statements)
{
import std.algorithm.sorting : sort;
import std.algorithm.mutation : SwapStrategy;
/* Re-ordered by lowest wieght first */
Statement[] stmntsRed;
/* Comparator for Statement objects */
bool wCmp(Statement lhs, Statement rhs)
{
return lhs.weight < rhs.weight;
}
stmntsRed = sort!(wCmp, SwapStrategy.stable)(statements).release;
return stmntsRed;
}
// TODO: Honestly all contains should be a kind-of `MStatementSearchable` and `MStatementReplaceable`
// AND MCloneable
public interface Container : MStatementSearchable, MStatementReplaceable
{
public void addStatement(Statement statement);
public void addStatements(Statement[] statements);
public Statement[] getStatements();
}
public class Module : Entity, Container
{
this(string moduleName)
{
super(moduleName);
}
private Statement[] statements;
public void addStatement(Statement statement)
{
this.statements ~= statement;
}
public void addStatements(Statement[] statements)
{
this.statements ~= statements;
}
public Statement[] getStatements()
{
return weightReorder(statements);
}
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
statements[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;
}
}
}
/**
* Struct
*
* A Struct can only contain Entity's
* that are Variables (TODO: Enforce in parser)
* TODO: Possibly enforce here too
*/
public class Struct : Type, Container, MCloneable
{
private Statement[] statements;
public void addStatement(Statement statement)
{
this.statements ~= statement;
}
public void addStatements(Statement[] statements)
{
this.statements ~= statements;
}
public Statement[] getStatements()
{
return weightReorder(statements);
}
this(string name)
{
super(name);
}
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
statements[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;
}
}
/**
* Clones this struct recursively returning a
* fresh copy of all its members and the struct
* itself.
*
* Returns: the cloned `Statement`
*/
public override Statement clone()
{
Struct clonedStruct = new Struct(this.name);
/**
* Clone all the statements and re-parent them
* to the clone
*/
Statement[] clonedStatements;
foreach(Statement curStmt; this.getStatements())
{
Statement clonedStmt;
if(cast(MCloneable)curStmt)
{
MCloneable cloneableCurStmt = cast(MCloneable)curStmt;
clonedStmt = cloneableCurStmt.clone();
}
// Re-parent to the cloned struct
clonedStmt.parentTo(clonedStruct);
// Add it to the cloned struct's body
clonedStruct.addStatement(clonedStmt);
}
return clonedStruct;
}
}
public class Clazz : Type, Container
{
private Statement[] statements;
private string[] interfacesClasses;
this(string name)
{
super(name);
/* Weighted as 0 */
weight = 0;
}
public void addInherit(string[] l)
{
interfacesClasses ~= l;
}
public string[] getInherit()
{
return interfacesClasses;
}
public override string toString()
{
return "Class (Name: "~name~", Parents (Class/Interfaces): "~to!(string)(interfacesClasses)~")";
}
public void addStatement(Statement statement)
{
this.statements ~= statement;
}
public void addStatements(Statement[] statements)
{
this.statements ~= statements;
}
public Statement[] getStatements()
{
return weightReorder(statements);
}
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
statements[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;
}
}
}
/**
* Test the `MCloneable`-ity support of `Struct`
* which has two `Variable` members (therefore
* also testing the `clone()` on `Variable`)
*/
unittest
{
Struct original = new Struct("User");
Variable originalVar_Name = new Variable("byte*", "name");
Variable originalVar_Age = new Variable("int", "age");
originalVar_Name.parentTo(original);
originalVar_Age.parentTo(original);
original.addStatement(originalVar_Name);
original.addStatement(originalVar_Age);
// Now clone it
Struct cloned = cast(Struct)original.clone();
// Cloned version should differ
assert(cloned !is original);
// Cloned statements versus original statements
Statement[] clonedStmts = cloned.getStatements();
Statement[] originalStmts = original.getStatements();
assert(clonedStmts[0] !is originalStmts[0]);
assert(clonedStmts[1] !is originalStmts[1]);
// Compare the variables (members) of both
Variable origStruct_MemberOne = cast(Variable)originalStmts[0];
Variable origStruct_MemberTwo = cast(Variable)originalStmts[1];
Variable clonedStruct_MemberOne = cast(Variable)clonedStmts[0];
Variable clonedStruct_MemberTwo = cast(Variable)clonedStmts[1];
assert(origStruct_MemberOne !is clonedStruct_MemberOne);
assert(origStruct_MemberTwo !is clonedStruct_MemberTwo);
assert(originalVar_Name.getName() == clonedStruct_MemberOne.getName()); // Names should match
assert(origStruct_MemberTwo.getName() == clonedStruct_MemberTwo.getName()); // Names should match
// Ensure re-parenting is correct
assert(origStruct_MemberOne.parentOf() == original);
assert(origStruct_MemberTwo.parentOf() == original);
assert(clonedStruct_MemberOne.parentOf() == cloned);
assert(clonedStruct_MemberTwo.parentOf() == cloned);
// TODO: Make this more deeper this test as a few
// ... more things were left out that can be checked
}