🧠 Feature/Meta: Cloneable (round 1) (#21)
* Data - Moved AST manipulation imports to the top - Made `VariableAssignment` cloneable - Made `Variable` cloneable * Data - When trying to `clone()` an `Expression`, do a runtime type check to check if we can (else `null` is used) * Expressions - Moved AST-manipulation related import to the top * Expressions - `BinaryOperatorExpression` now overrides `clone()` from `MCloneable` * Expressions - `IntegerLiteral` now implements `MCloneable` * Expressions - `CastedExpression` now implements `clone()` for `MCloneable` * Containers - Moved all AST maniuplation-related imports to the top * Containers - Made `Struct` support `MCloneable`'s `clone()` method * Data - Only clone the `VariableAssignment` if the `Variable` has one * Containers (unit test) - Added test which tests the `clone()` on a `Struct`
This commit is contained in:
parent
f1aaaf1088
commit
8a11eabd96
|
@ -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
|
||||
|
@ -363,3 +401,51 @@ 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
|
||||
}
|
|
@ -4,6 +4,11 @@ public import tlang.compiler.symbols.check;
|
|||
import std.conv : to;
|
||||
import tlang.compiler.typecheck.dependency.core : Context;
|
||||
|
||||
// For debug printing
|
||||
import gogga;
|
||||
|
||||
// AST manipulation interfaces
|
||||
import tlang.compiler.symbols.mcro : MStatementSearchable, MStatementReplaceable, MCloneable;
|
||||
|
||||
/**
|
||||
* TODO: Implement the blow and use them
|
||||
|
@ -438,7 +443,7 @@ public class Function : TypedEntity, Container
|
|||
}
|
||||
}
|
||||
|
||||
public class Variable : TypedEntity, MStatementSearchable, MStatementReplaceable
|
||||
public class Variable : TypedEntity, MStatementSearchable, MStatementReplaceable, MCloneable
|
||||
{
|
||||
/* TODO: Just make this an Expression */
|
||||
private VariableAssignment assignment;
|
||||
|
@ -509,6 +514,39 @@ public class Variable : TypedEntity, MStatementSearchable, MStatementReplaceable
|
|||
return assignment.replace(thiz, that);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones this variable declaration recursively
|
||||
* including its assigned value (`VariableAssignment`)
|
||||
* if any.
|
||||
*
|
||||
* Returns: the cloned `Statement`
|
||||
*/
|
||||
public override Statement clone()
|
||||
{
|
||||
Variable clonedVarDec;
|
||||
|
||||
// If there's an assignment, then clone it
|
||||
VariableAssignment clonedVarAss = null;
|
||||
if(this.assignment)
|
||||
{
|
||||
// Clone the assignment
|
||||
clonedVarAss = cast(VariableAssignment)this.assignment.clone();
|
||||
}
|
||||
|
||||
|
||||
// Create new variable with same name and identifier
|
||||
clonedVarDec = new Variable(this.type, this.name);
|
||||
|
||||
// Copy all properties across (TODO: Make sure we didn't miss any)
|
||||
clonedVarDec.accessorType = this.accessorType;
|
||||
clonedVarDec.isExternalEntity = this.isExternalEntity;
|
||||
clonedVarDec.assignment = clonedVarAss;
|
||||
clonedVarDec.container = this.container;
|
||||
|
||||
|
||||
return clonedVarDec;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -521,7 +559,7 @@ public import tlang.compiler.symbols.expressions;
|
|||
/**
|
||||
* TODO: Rename to `VariableDeclarationAssignment`
|
||||
*/
|
||||
public class VariableAssignment : Statement, MStatementSearchable, MStatementReplaceable
|
||||
public class VariableAssignment : Statement, MStatementSearchable, MStatementReplaceable, MCloneable
|
||||
{
|
||||
private Expression expression;
|
||||
private Variable variable;
|
||||
|
@ -600,6 +638,35 @@ public class VariableAssignment : Statement, MStatementSearchable, MStatementRep
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones this variable assignment by recursively cloning
|
||||
* the fields within (TODO: finish description)
|
||||
*
|
||||
* Returns: the cloned `Statement`
|
||||
*/
|
||||
public override Statement clone()
|
||||
{
|
||||
// FIXME: Investigate if `Variable`? Must be cloned
|
||||
// ... would cuase infinite recursion and it isn't
|
||||
// ... reaslly a part of the AST (just a helper)
|
||||
// ... hence I do not believe it needs to be cloned
|
||||
// (If for some reason the association eneds to be)
|
||||
// ... updted then `Variable`'s `clone()' can call
|
||||
/// ... `setvariable(clonedVarDec)` (with itself)
|
||||
|
||||
// Clone the expression (if supported, TODO: throw an error if not)
|
||||
Expression clonedExpression = null;
|
||||
if(cast(MCloneable)this.expression)
|
||||
{
|
||||
MCloneable cloneableExpression = cast(MCloneable)this.expression;
|
||||
clonedExpression = cast(Expression)cloneableExpression.clone();
|
||||
}
|
||||
|
||||
VariableAssignment clonedVarAss = new VariableAssignment(clonedExpression);
|
||||
|
||||
return clonedVarAss;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1508,8 +1575,6 @@ public final class Branch : Entity, Container
|
|||
}
|
||||
}
|
||||
|
||||
import tlang.compiler.symbols.mcro : MStatementSearchable, MStatementReplaceable;
|
||||
|
||||
public final class DiscardStatement : Statement, MStatementSearchable, MStatementReplaceable
|
||||
{
|
||||
private Expression expression;
|
||||
|
|
|
@ -3,6 +3,9 @@ module tlang.compiler.symbols.expressions;
|
|||
import tlang.compiler.symbols.data;
|
||||
import std.conv : to;
|
||||
|
||||
// AST manipulation interfaces
|
||||
import tlang.compiler.symbols.mcro : MStatementSearchable, MStatementReplaceable, MCloneable;
|
||||
|
||||
/* TODO: Look into arrays later */
|
||||
public class StringExpression : Expression
|
||||
{
|
||||
|
@ -56,9 +59,7 @@ public class UnaryOperatorExpression : OperatorExpression
|
|||
}
|
||||
}
|
||||
|
||||
import tlang.compiler.symbols.mcro : MStatementSearchable, MStatementReplaceable;
|
||||
|
||||
public class BinaryOperatorExpression : OperatorExpression, MStatementSearchable, MStatementReplaceable
|
||||
public class BinaryOperatorExpression : OperatorExpression, MStatementSearchable, MStatementReplaceable, MCloneable
|
||||
{
|
||||
private Expression lhs, rhs;
|
||||
|
||||
|
@ -151,6 +152,39 @@ public class BinaryOperatorExpression : OperatorExpression, MStatementSearchable
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones this binery operator expression recursively
|
||||
* returning a fresh new copy of itself and its
|
||||
* left and right operands
|
||||
*
|
||||
* Returns: the cloned `Statement`
|
||||
*/
|
||||
public override Statement clone()
|
||||
{
|
||||
BinaryOperatorExpression clonedBinaryOp;
|
||||
|
||||
// Clone the left-hand operand expression (if supported, TODO: throw an error if not)
|
||||
Expression clonedLeftOperandExpression = null;
|
||||
if(cast(MCloneable)this.lhs)
|
||||
{
|
||||
MCloneable cloneableExpression = cast(MCloneable)this.lhs;
|
||||
clonedLeftOperandExpression = cast(Expression)cloneableExpression.clone();
|
||||
}
|
||||
|
||||
// Clone the left-hand operand expression (if supported, TODO: throw an error if not)
|
||||
Expression clonedRightOperandExpression = null;
|
||||
if(cast(MCloneable)this.rhs)
|
||||
{
|
||||
MCloneable cloneableExpression = cast(MCloneable)this.rhs;
|
||||
clonedRightOperandExpression = cast(Expression)cloneableExpression.clone();
|
||||
}
|
||||
|
||||
// Clone ourselves
|
||||
clonedBinaryOp = new BinaryOperatorExpression(this.operator, clonedLeftOperandExpression, clonedRightOperandExpression);
|
||||
|
||||
return clonedBinaryOp;
|
||||
}
|
||||
}
|
||||
|
||||
public enum IntegerLiteralEncoding
|
||||
|
@ -161,7 +195,7 @@ public enum IntegerLiteralEncoding
|
|||
UNSIGNED_LONG
|
||||
}
|
||||
|
||||
public class IntegerLiteral : NumberLiteral
|
||||
public class IntegerLiteral : NumberLiteral, MCloneable
|
||||
{
|
||||
private IntegerLiteralEncoding encoding;
|
||||
|
||||
|
@ -180,6 +214,20 @@ public class IntegerLiteral : NumberLiteral
|
|||
{
|
||||
return "[integerLiteral: "~numberLiteral~" ("~to!(string)(encoding)~")]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones this integer literal
|
||||
*
|
||||
* Returns: the cloned `Statement`
|
||||
*/
|
||||
public override Statement clone()
|
||||
{
|
||||
IntegerLiteral clonedIntegerLiteral;
|
||||
|
||||
clonedIntegerLiteral = new IntegerLiteral(this.numberLiteral, this.encoding);
|
||||
|
||||
return clonedIntegerLiteral;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Work on floating point literal encodings
|
||||
|
@ -238,7 +286,7 @@ public final class NewExpression : Expression
|
|||
}
|
||||
}
|
||||
|
||||
public final class CastedExpression : Expression
|
||||
public final class CastedExpression : Expression, MCloneable
|
||||
{
|
||||
private Expression uncastedExpression;
|
||||
private string toType;
|
||||
|
@ -258,6 +306,29 @@ public final class CastedExpression : Expression
|
|||
{
|
||||
return uncastedExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones this casted expression recursively
|
||||
* and returns a fresh copy of it
|
||||
*
|
||||
* Returns: the cloned `Statement`
|
||||
*/
|
||||
public override Statement clone()
|
||||
{
|
||||
CastedExpression clonedCastedExpression;
|
||||
|
||||
// Clone the uncasted expression (if supported, TODO: throw an error if not)
|
||||
Expression clonedUncastedExpression = null;
|
||||
if(cast(MCloneable)this.uncastedExpression)
|
||||
{
|
||||
MCloneable cloneableExpression = cast(MCloneable)this.uncastedExpression;
|
||||
clonedUncastedExpression = cast(Expression)cloneableExpression.clone();
|
||||
}
|
||||
|
||||
clonedCastedExpression = new CastedExpression(this.toType, clonedUncastedExpression);
|
||||
|
||||
return clonedCastedExpression;
|
||||
}
|
||||
}
|
||||
|
||||
public final class ArrayIndex : Expression
|
||||
|
|
Loading…
Reference in New Issue