Commit 6738c731 authored by Miklos Magyari's avatar Miklos Magyari
Browse files

OOP: semantic check - implemented trait class rules (issue #427)


Signed-off-by: Miklos Magyari's avatarMiklos Magyari <miklos.magyari@sigmatechnology.se>
parent d91c519f
......@@ -46,6 +46,20 @@ type class BadExtends3 extends MinimalFinalClass {
}
type class @trait BadTraitClass {
public var integer m_int := 0;
public timer Timer;
private function f_valid(integer pl_int);
private function f_invalid(integer pl_int) {
// this should not be here
}
create (charstring pl_str) {
var float vl_float := 1.0;
}
}
type class SuperClass {
var integer vl_a;
template MyUnion t_union := { a := 10 }
......@@ -122,7 +136,7 @@ type class @abstract FinallyClass {
// a trait class cannot have a finally block
type class @trait FinallyClass2 {
public const integer m_const := 0;
public function f_pub();
} finally {
log(this.m_const);
}
......@@ -135,7 +149,7 @@ type class @abstract @trait BadClass2 { }
// class with this
type class ClassWithThis {
public var integer vl_a;
const float vl_b;
public var integer vl_b;
public function pl_dummy(in integer pl_int) return integer {
return 1;
......@@ -145,9 +159,9 @@ type class ClassWithThis {
var charstring vl_int := this.pl_dummy(1);
}
create (integer a, float b) {
this.a := vl_a;
this.b := vl_b;
create (integer pl_a, float pl_b) {
this.vl_a := pl_a;
this.vl_b := pl_b;
}
}
......
......@@ -77,9 +77,9 @@ type class MembersClass {
return pl_times * m_int_prot;
}
create (integer p1, integer p2) {
m_int_priv := p1;
m_int_prot := p2;
create (integer pl_p1, integer pl_p2) {
m_int_priv := pl_p1;
m_int_prot := pl_p2;
}
}
......@@ -95,9 +95,8 @@ type class VariousMembers {
public template MyUnion t_union := { choice1 := 12 }
template MyUnion t_union2;
create (charstring p1, charstring p2) {
m_var1 := p2;
t_union := { choice2 := "abc" };
create (charstring pl_p1, charstring pl_p2) {
m_var1 := pl_p2;
}
}
......@@ -151,9 +150,8 @@ type class ClassWithThis {
var integer vl_int := this.pl_dummy(1);
}
create (integer a, float b) {
this.a := vl_a;
this.b := vl_b;
create (integer pl_a, float pl_b) {
this.vl_a := pl_a;
}
}
......
......@@ -70,6 +70,7 @@ import org.eclipse.titan.designer.preferences.PreferenceConstants;
* The Def_Function class represents TTCN3 function definitions.
*
* @author Kristof Szabados
* @author Miklos Magyari
* */
public final class Def_Function extends Definition implements IParameterisedAssignment {
/**
......@@ -782,6 +783,14 @@ public final class Def_Function extends Definition implements IParameterisedAssi
}
}
/**
* Checks if the function has a body
* @return
*/
public boolean hasBody() {
return block != null;
}
@Override
/** {@inheritDoc} */
public String getOutlineText() {
......
......@@ -56,6 +56,10 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl
public static final String FORMALPARAMSDIFFER = "Formal parameter list differs from previous definition";
public static final String OVERRIDDENFORMALPARAM = "Definition is overridden with different formal parameters";
public static final String TRAITMETHODSONLY = "Trait classes can only declare methods";
public static final String TRAITMETHODHASBODY = "Trait method cannot have a function body";
public static final String TRAITCONSTRUCTOR = "Trait classes cannot have a constructor";
private final Identifier identifier;
/** The class's own definitions */
private final DefinitionContainer definitions = new DefinitionContainer();
......@@ -343,6 +347,25 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl
checkUniqueness(timestamp);
definitions.checkAll(timestamp);
if (myType.isTrait()) {
for (Definition def : definitions) {
if (def instanceof Def_Function) {
final Def_Function funcDef = (Def_Function)def;
if (funcDef.getIdentifier().getName().equals("create")) {
def.getLocation().reportSingularSemanticError(TRAITCONSTRUCTOR);
myType.setIsErroneous(true);
}
else if (funcDef.hasBody()) {
def.getLocation().reportSingularSemanticError(TRAITMETHODHASBODY);
myType.setIsErroneous(true);
}
} else {
def.getLocation().reportSingularSemanticError(TRAITMETHODSONLY);
myType.setIsErroneous(true);
}
}
}
}
public Identifier getIdentifier() {
......
......@@ -3062,7 +3062,6 @@ pr_FunctionInstance returns[Reference temporalReference]
Reference ref = null;
FieldSubReference fieldSubReference = null;
Reference superRef = null;
List<ISubReference> extReferences = null;
}:
( ((id = pr_Identifier {
fieldSubReference = new FieldSubReference($id.identifier);
......@@ -3072,7 +3071,6 @@ pr_FunctionInstance returns[Reference temporalReference]
a = pr_LParen
( p = pr_FunctionActualParList { parameters = $p.parsedParameters; } )?
endcol = pr_RParen
(ext = pr_ExtendedFieldReference { extReferences = $ext.subReferences; } )?
)
{
if($temporalReference != null) {
......@@ -3090,12 +3088,8 @@ pr_FunctionInstance returns[Reference temporalReference]
$temporalReference.addSubReference(fieldSubReference);
}
$temporalReference.addSubReference(subReference);
if (extReferences != null) {
for(ISubReference extReference: extReferences) {
$temporalReference.addSubReference(extReference);
}
}
$temporalReference.setLocation(getLocation( $start, $endcol.stop));
}
};
......@@ -9034,13 +9028,11 @@ pr_ClassTypeDef returns[Def_Type def_type]
if (body == null) {
body = new ClassTypeBody($i.identifier, refs);
}
Type type = new Class_Type(body, isAbstract, isFinal, isTrait, getLocation($kw.stop, $i.start), finallyBlock);
if (refs != null) {
refs.setParentClass((Class_Type)type);
}
Class_Type type = new Class_Type(body, isAbstract, isFinal, isTrait, getLocation($kw.stop, $i.start), finallyBlock);
type.setLocation(getLocation($start, getLastVisibleToken()));
$def_type = new Def_Type($i.identifier, type);
$def_type.setLocation(getLocation($kw.start, $i.stop));
refs.setParentClass(type);
}
};
......@@ -9142,7 +9134,12 @@ pr_ClassMember returns[List<Definition> definitions]
$definitions.add($func.def_func);
}
}
| c = pr_ClassConstructorDef
| c = pr_ClassConstructorDef {
if ($c.def_func != null) {
$definitions = new ArrayList<Definition>();
$definitions.add($c.def_func);
}
}
| cl = pr_ClassTypeDef {
if ($cl.def_type != null) {
$definitions = new ArrayList<Definition>();
......@@ -9224,11 +9221,17 @@ pr_ClassFunctionDef returns[Def_Function def_func]
}
};
pr_ClassConstructorDef
:
pr_ClassConstructorDef returns[Def_Function def_func]
@init {
FormalParameterList parameters = null;
StatementBlock statementBlock = null;
}:
( id = pr_CreateKeyword
LPAREN
( pl = pr_FunctionFormalParList )?
( pl = pr_FunctionFormalParList {
parameters = $pl.parList;
parameters.setLocation(getLocation( $pl.start, $pl.stop));
})?
RPAREN
(
pr_ExtKeyword LPAREN
......@@ -9245,9 +9248,14 @@ pr_ClassConstructorDef
}
)?
( sb=pr_StatementBlock )?
( sb=pr_StatementBlock { statementBlock = $sb.statementblock; } )?
)
;
{
Identifier id = new Identifier( Identifier_type.ID_TTCN, "create", getLocation($id.start, $id.stop ) );
$def_func = new Def_Function(id, parameters, null, null, null, null, null, false, null, statementBlock);
$def_func.setLocation(getLocation( $id.start, $sb.stop));
$def_func.setCommentLocation( getLastCommentLocation( $start ) );
};
pr_SingleClassConstDef[Type type] returns[Def_Const def_const]
@init {
......
......@@ -45,7 +45,7 @@ public class OOP_Semantic_tests {
private ArrayList<MarkerToCheck> oopNegative_ttcn_initializer() {
//oopNegativeSemanticTest.ttcn
ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(24);
ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(29);
int lineNum = 28;
markersToCheck.add(new MarkerToCheck("class type expected", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 9;
......@@ -58,7 +58,15 @@ public class OOP_Semantic_tests {
markersToCheck.add(new MarkerToCheck("A trait class can only extend trait classes", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 4;
markersToCheck.add(new MarkerToCheck("A final class cannot be extended", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 15;
lineNum += 5;
for (i = 0; i < 2; i++) {
markersToCheck.add(new MarkerToCheck("Trait classes can only declare methods", lineNum++, IMarker.SEVERITY_ERROR));
}
lineNum += 2;
markersToCheck.add(new MarkerToCheck("Trait method cannot have a function body", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 4;
markersToCheck.add(new MarkerToCheck("Trait classes cannot have a constructor", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 16;
markersToCheck.add(new MarkerToCheck("Reference to non-existent field `nonexist' in union template for type `@classesNegativeSemantic.MyUnion'", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 4;
markersToCheck.add(new MarkerToCheck("Local Definiton `vl_b' collides with definition inherited from class type `@classesNegativeSemantic.SubClass'", lineNum, IMarker.SEVERITY_ERROR));
......@@ -76,7 +84,9 @@ public class OOP_Semantic_tests {
markersToCheck.add(new MarkerToCheck("A class cannot be both abstract and trait", ++lineNum, IMarker.SEVERITY_ERROR));
lineNum += 12;
markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `charstring' was expected instead of `integer'", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 15;
lineNum += 5;
markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `integer' was expected instead of `float'", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 10;
markersToCheck.add(new MarkerToCheck("`super' reference is only valid inside class bodies", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 10;
markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `integer' was expected instead of `charstring'", lineNum, IMarker.SEVERITY_ERROR));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment