@ -4,6 +4,9 @@ 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
@ -30,7 +33,7 @@ public Statement[] weightReorder(Statement[] statements)
}
// TODO: Honestly all contains should be a kind-of `MStatementSearchable` and `MStatementReplaceable`
import tlang.compiler.symbols.mcro : MStatementSearchable , MStatementReplaceable ;
// AND MCloneable
public interface Container : MStatementSearchable , MStatementReplaceable
{
public void addStatement ( Statement statement ) ;
@ -147,7 +150,7 @@ public class Module : Entity, Container
* that are Variables ( TODO : Enforce in parser )
* TODO : Possibly enforce here too
* /
public class Struct : Type , Container
public class Struct : Type , Container , MCloneable
{
private Statement [ ] statements ;
@ -243,6 +246,41 @@ public class Struct : Type, Container
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
@ -362,4 +400,52 @@ public class Clazz : Type, Container
}
}
}
/ * *
* 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
}