diff --git a/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn b/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn index c9f35dc9715ac8b70831b855d63a7ddd649a047f..1edb7bd700d20fad8d01e8f22807a329e88fc3dd 100755 --- a/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn +++ b/Semantic_Analizer_Tests/src/Basic_tests/OopNegativeSemanticTest.ttcn @@ -54,8 +54,9 @@ type class @trait BadTraitClass { var float vl_float := 1.0; } - private function f_valid(integer pl_int); - private function f_invalid(integer pl_int) { + private function @abstract f_valid(integer pl_int); + public function f_invalid_non_abstract(in charstring pl_cstr); + private function @abstract f_invalid(integer pl_int) { // this should not be here } diff --git a/Semantic_Analizer_Tests/src/Basic_tests/OopPositiveBasicSyntax.ttcn b/Semantic_Analizer_Tests/src/Basic_tests/OopPositiveBasicSyntax.ttcn index 838e7a156a899db2669ebc90dfab18700c739f8b..b3b6ea58ef12d2fcbfac85c69c707e4b0f89265f 100644 --- a/Semantic_Analizer_Tests/src/Basic_tests/OopPositiveBasicSyntax.ttcn +++ b/Semantic_Analizer_Tests/src/Basic_tests/OopPositiveBasicSyntax.ttcn @@ -83,6 +83,10 @@ type class MembersClass { } } +type class TraitClass { + public function @abstract f_func(in integer pl_in); +} + type union MyUnion { integer choice1, charstring choice2 diff --git a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/definitions/Def_Function.java b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/definitions/Def_Function.java index bae90f530dbb28ef6999c41ff044a2bd6ef8c220..bc3b0faabed02038d087030379b1aefe0228985a 100644 --- a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/definitions/Def_Function.java +++ b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/definitions/Def_Function.java @@ -135,7 +135,10 @@ public final class Def_Function extends Definition implements IParameterisedAssi private EncodingPrototype_type prototype; private Type inputType; private Type outputType; + private final boolean isClassFunction; + private final boolean isAbstract; + private final boolean isFinal; // stores whether this function can be started or not private boolean isStartable; @@ -144,7 +147,8 @@ public final class Def_Function extends Definition implements IParameterisedAssi public Def_Function(final Identifier identifier, final FormalParameterList formalParameters, final Reference runsOnRef, final Reference mtcReference, final Reference systemReference, final Reference portReference, final Type returnType, final boolean returnsTemplate, final TemplateRestriction.Restriction_type templateRestriction, - final StatementBlock block, boolean isClassFunction) { + final StatementBlock block, + boolean isClassFunction, boolean isAbstract, boolean isFinal) { super(identifier); assignmentType = (returnType == null) ? Assignment_type.A_FUNCTION : (returnsTemplate ? Assignment_type.A_FUNCTION_RTEMP : Assignment_type.A_FUNCTION_RVAL); @@ -162,6 +166,8 @@ public final class Def_Function extends Definition implements IParameterisedAssi this.templateRestriction = templateRestriction; this.block = block; this.isClassFunction = isClassFunction; + this.isAbstract = isAbstract; + this.isFinal = isFinal; this.prototype = EncodingPrototype_type.NONE; inputType = null; @@ -194,7 +200,7 @@ public final class Def_Function extends Definition implements IParameterisedAssi final Type returnType, final boolean returnsTemplate, final TemplateRestriction.Restriction_type templateRestriction, final StatementBlock block) { this(identifier, formalParameters, runsOnRef, mtcReference, systemReference, portReference, returnType, - returnsTemplate, templateRestriction, block, false); + returnsTemplate, templateRestriction, block, false, false, false); } /** @@ -373,6 +379,14 @@ public final class Def_Function extends Definition implements IParameterisedAssi return portType; } + + public boolean isAbstract() { + return isAbstract; + } + + public boolean isFinal() { + return isFinal; + } @Override /** {@inheritDoc} */ diff --git a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeBody.java b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeBody.java index 3629b5a9152dfb018f31b25b0050394c9dfe8580..fb45fcf231ad897154cba97c800d73f2141e74db 100755 --- a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeBody.java +++ b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/AST/TTCN3/types/ClassTypeBody.java @@ -59,6 +59,7 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl 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"; + public static final String TRAITMETHODABSTRACT = "Trait classes can only declare abstract methods"; private final Identifier identifier; /** The class's own definitions */ @@ -361,9 +362,14 @@ public final class ClassTypeBody extends TTCN3Scope implements IReferenceChainEl def.getLocation().reportSingularSemanticError(TRAITCONSTRUCTOR); myType.setIsErroneous(true); } - else if (funcDef.hasBody()) { - def.getLocation().reportSingularSemanticError(TRAITMETHODHASBODY); - myType.setIsErroneous(true); + else { + if (! funcDef.isAbstract()) { + def.getLocation().reportSingularSemanticError(TRAITMETHODABSTRACT); + } + if (funcDef.hasBody()) { + def.getLocation().reportSingularSemanticError(TRAITMETHODHASBODY); + myType.setIsErroneous(true); + } } } else { def.getLocation().reportSingularSemanticError(TRAITMETHODSONLY); diff --git a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/parsers/ttcn3parser/Ttcn3Parser.g4 b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/parsers/ttcn3parser/Ttcn3Parser.g4 index 12ae9c2ed3f686961131dc82593394640e2a82ff..0c70bda1d1cf0b1747ec6683ed0d3068772fe23f 100644 --- a/org.eclipse.titan.designer/src/org/eclipse/titan/designer/parsers/ttcn3parser/Ttcn3Parser.g4 +++ b/org.eclipse.titan.designer/src/org/eclipse/titan/designer/parsers/ttcn3parser/Ttcn3Parser.g4 @@ -9196,7 +9196,8 @@ pr_ClassFunctionDef returns[Def_Function def_func] ( pr_ExtKeyword? col = pr_FunctionKeyword - mod = pr_Modifier[isAbstract, isFinal, isTrait] + ( fm = pr_FinalModifier { isFinal = $fm.isFinal; } )? + ( am = pr_AbstractModifier { isAbstract = $am.isAbstract; } )? pr_DeterministicModifier? id = pr_Identifier start1 = pr_LParen @@ -9222,7 +9223,7 @@ pr_ClassFunctionDef returns[Def_Function def_func] if($id.identifier != null) { if(parameters == null) { parameters = new FormalParameterList(new ArrayList()); } parameters.setLocation(getLocation( $start1.start, $end.stop)); - $def_func = new Def_Function($id.identifier, parameters, runsonHelper.runsonReference, runsonHelper.mtcReference, runsonHelper.systemReference, portReference, returnType, returnsTemplate, templateRestriction, statementBlock, true); + $def_func = new Def_Function($id.identifier, parameters, runsonHelper.runsonReference, runsonHelper.mtcReference, runsonHelper.systemReference, portReference, returnType, returnsTemplate, templateRestriction, statementBlock, true, isAbstract, isFinal); $def_func.setLocation(getLocation( $col.start, $sb.stop)); $def_func.setCommentLocation( getLastCommentLocation( $start ) ); } @@ -9260,7 +9261,7 @@ pr_ClassConstructorDef returns[Def_Function def_func] if(parameters == null) { parameters = new FormalParameterList(new ArrayList()); } parameters.setLocation(getLocation( $pstart.start, $pstop.stop)); 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, true); + $def_func = new Def_Function(id, parameters, null, null, null, null, null, false, null, statementBlock, true, false, false); $def_func.setLocation(getLocation( $id.start, $sb.stop)); $def_func.setCommentLocation( getLastCommentLocation( $start ) ); }; diff --git a/org.eclipse.titan.regressiontests/src/org/eclipse/titan/regressiontests/designer/statictests/Basic_tests/OOP_Semantic_tests.java b/org.eclipse.titan.regressiontests/src/org/eclipse/titan/regressiontests/designer/statictests/Basic_tests/OOP_Semantic_tests.java index 218588be958d8131acfc90ffacbb3324e7ede609..174d4580992c43ad8018252a2aa4eba876df86c3 100755 --- a/org.eclipse.titan.regressiontests/src/org/eclipse/titan/regressiontests/designer/statictests/Basic_tests/OOP_Semantic_tests.java +++ b/org.eclipse.titan.regressiontests/src/org/eclipse/titan/regressiontests/designer/statictests/Basic_tests/OOP_Semantic_tests.java @@ -45,7 +45,7 @@ public class OOP_Semantic_tests { private ArrayList oopNegative_ttcn_initializer() { //oopNegativeSemanticTest.ttcn - ArrayList markersToCheck = new ArrayList(39); + ArrayList markersToCheck = new ArrayList(41); int lineNum = 28; markersToCheck.add(new MarkerToCheck("class type expected", lineNum, IMarker.SEVERITY_ERROR)); lineNum += 9; @@ -64,7 +64,8 @@ public class OOP_Semantic_tests { } markersToCheck.add(new MarkerToCheck("Trait classes cannot have a constructor", ++lineNum, IMarker.SEVERITY_ERROR)); lineNum += 5; - markersToCheck.add(new MarkerToCheck("Trait method cannot have a function body", lineNum, IMarker.SEVERITY_ERROR)); + markersToCheck.add(new MarkerToCheck("Trait classes can only declare abstract methods", lineNum, IMarker.SEVERITY_ERROR)); + markersToCheck.add(new MarkerToCheck("Trait method cannot have a function body", ++lineNum, IMarker.SEVERITY_ERROR)); lineNum += 17; markersToCheck.add(new MarkerToCheck("Reference to non-existent field `nonexist' in union template for type `@classesNegativeSemantic.MyUnion'", lineNum, IMarker.SEVERITY_ERROR)); lineNum += 4; @@ -75,8 +76,9 @@ public class OOP_Semantic_tests { markersToCheck.add(new MarkerToCheck("integer value was expected", lineNum, IMarker.SEVERITY_ERROR)); lineNum += 4; markersToCheck.add(new MarkerToCheck("Constant must be initialized", lineNum, IMarker.SEVERITY_ERROR)); - lineNum += 20; - markersToCheck.add(new MarkerToCheck("A trait class should not define a finally block", lineNum, IMarker.SEVERITY_ERROR)); + lineNum += 19; + markersToCheck.add(new MarkerToCheck("Trait classes can only declare abstract methods", lineNum, IMarker.SEVERITY_ERROR)); + markersToCheck.add(new MarkerToCheck("A trait class should not define a finally block", ++lineNum, IMarker.SEVERITY_ERROR)); lineNum += 5; markersToCheck.add(new MarkerToCheck("An absract class cannot be final", lineNum, IMarker.SEVERITY_ERROR)); markersToCheck.add(new MarkerToCheck("A trait class cannot be final", ++lineNum, IMarker.SEVERITY_ERROR));