Commit 18b8ae96 authored by Miklos Magyari's avatar Miklos Magyari
Browse files

OOP: handling empty property bodies (issue #427)


Signed-off-by: Miklos Magyari's avatarMiklos Magyari <miklos.magyari@sigmatechnology.se>
parent 10194304
......@@ -29,6 +29,7 @@ type union MyUnion {
type class CorrectClass1 { }
// invalid: a class can only extend other classes
type class BadInheritance extends MyUnion {
}
......@@ -273,8 +274,9 @@ type class FuncClass extends BaseFunctionClass {
private function f_test_super() {
// type mismatches
var integer vl_int := f_get_one();
var charstring vl_cs:= super.f_get_one();
var integer vl_int := f_get_one(); // mismatch
var charstring vl_ok := f_get_one(); // correct
var charstring vl_cs := super.f_get_one(); // mismatch
}
public function f_dummy(in integer pl_int) return float {
......@@ -359,7 +361,7 @@ type class BadClauses {
}
}
// 'value' can only be used in properties (and in some cases of advanced matching)
// invalid: 'value' can only be used in properties (and in some cases of advanced matching)
function f_invalid_value() {
var integer vl_x := value;
}
......@@ -372,7 +374,7 @@ type class PropertyClass {
@get => size_;
@set {
size_ := value;
sizename_ := value;
sizename_ := value; // type mismatch
}
}
......@@ -380,11 +382,17 @@ type class PropertyClass {
@get => size;
}
// invalid: a property without a setter cannot be initialized
var charstring @property nosetter_init := "abc" {
@get {
sizename_ := "xyz";
}
}
// invalid: an empty property body is not allowed
var float @property emptybody {
}
}
testcase tc_basicSyntax() runs on CT {
......@@ -417,6 +425,8 @@ testcase tc_basicSyntax() runs on CT {
var integer vl_subint := vl_sub.m_const;
var PropertyClass vl_prop := PropertyClass.create;
// invalid: cannot assign a value to a property that has no setter
vl_prop.nosetter := 10;
}
......
......@@ -318,8 +318,12 @@ type class ClassWithPrivateExt extends ClassWithPrivate {
// class properties
type class CorrectWithProperty {
private var integer heightVal;
private var integer @property width;
private var integer heightVal;
// auto property
private var integer @property width;
// non-auto property
var integer @property height {
@get => heightVal;
@set {
......@@ -328,6 +332,12 @@ type class CorrectWithProperty {
}
}
}
// getter-only property
private const float piVal := 3.1415;
var float @property getPi {
@get => piVal;
}
}
testcase tc_basicSyntax() runs on CT {
......
......@@ -40,6 +40,8 @@ import org.eclipse.titan.designer.parsers.CompilationTimeStamp;
public final class Property_Type extends Type {
private static final String INITIALVALUEWITHOUTSETTER = "A property without a setter cannot have an initial value";
private static final String EMPTYBODY = "An empty property body is not allowed";
/** type of the property */
private Type myType;
......@@ -61,9 +63,13 @@ public final class Property_Type extends Type {
/** a fake formal param list with one member to support the 'value' keyword */
private FormalParameterList fpList;
private boolean hasGetter;
private boolean hasSetter;
/** Indicates if the property's body is empty. */
private boolean hasBody;
private boolean isAutoProperty;
public Property_Type(Type type) {
......@@ -77,6 +83,7 @@ public final class Property_Type extends Type {
this.isAutoProperty = true;
this.hasSetter = false;
this.hasGetter = false;
this.hasBody = false;
}
/**
......@@ -91,8 +98,6 @@ public final class Property_Type extends Type {
getStatementBlock.setFullNameParent(this);
}
getTemplate = template;
isAutoProperty = false;
}
/**
......@@ -108,8 +113,6 @@ public final class Property_Type extends Type {
setStatementBlock.setFullNameParent(this);
}
setTemplate = template;
isAutoProperty = false;
}
@Override
......@@ -120,7 +123,11 @@ public final class Property_Type extends Type {
}
lastTimeChecked = timestamp;
if (hasBody == true && hasGetter() == false && hasSetter() == false) {
getLocation().reportSemanticError(EMPTYBODY);
}
FormalParameter valueParam = new FormalParameter(null, Assignment_type.A_PAR_VAL_IN, myType, new Identifier(Identifier_type.ID_TTCN, "value"), null, null);
List<FormalParameter> paramList = new ArrayList<FormalParameter>();
paramList.add(valueParam);
......@@ -192,6 +199,14 @@ public final class Property_Type extends Type {
initValTemplate = template;
}
public void setHasBody() {
hasBody = true;
}
public void setIsAutoProperty(boolean isAutoProperty) {
this.isAutoProperty = isAutoProperty;
}
@Override
public String getOutlineIcon() {
// TODO Auto-generated method stub
......
......@@ -53,7 +53,7 @@ public final class CodeScanner extends RuleBasedScanner {
public static final String[] OOP_TITANSPECIFICKEYWORDS = new String[] {
/* Because some OOP keywords start with @, they are added here temporarily
* as TITANSPECIFICKEYWORDS have special handling of the @ character */
"@abstract", "@final", "@trait"
"@abstract", "@final", "@trait", "@property"
};
public static final String[] TEMPLATE_MATCH = new String[] { "complement", "decmatch", "ifpresent", "subset", "superset", "permutation" };
......
......@@ -18,6 +18,7 @@ import org.eclipse.titan.designer.productUtilities.ProductConstants;
* according to where and how they can be used.
*
* @author Kristof Szabados
* @author Miklos Magyari
* */
public final class TTCN3Keywords {
public static final String KEYWORD = "keyword";
......@@ -50,7 +51,7 @@ public final class TTCN3Keywords {
public static final String[] OOP_ALL_AVAILABLE = new String[] {
/* OOP extension keywords */
"class", "@abstract", "@final", "@trait", "this", "super", "finally"
"class", "@abstract", "@final", "@trait", "@property", "this", "super", "finally"
};
public static final String[] FORMAL_PARAMETER_SCOPE = new String[] { "in", "inout", "out", "template" };
......
......@@ -4563,7 +4563,7 @@ pr_SingleVarInstance[Type type, parameterEvaluationType eval] returns[Def_Var de
initValTemplate.setLocation(getLocation( $templ.start, $templ.stop ));
}
)?
( body = pr_PropertyBody[type] { prop = $body.prop; } )?
body = pr_PropertyBody[type] { prop = $body.prop; }
)
)
{
......@@ -9438,13 +9438,20 @@ pr_PropertyBody[Type type] returns[Property_Type prop]
$prop = new Property_Type(type);
}:
(
pr_BeginChar
( sbg1 = pr_PropertyGetter { $prop.setStatementBlockGetter( $sbg1.statementblock, $sbg1.template ); }
( sbs1 = pr_PropertySetter { $prop.setStatementBlockSetter( $sbs1.statementblock, $sbs1.template ); } )?
| sbs2 = pr_PropertySetter { $prop.setStatementBlockSetter( $sbs2.statementblock, $sbs2.template ); }
(sbg2 = pr_PropertyGetter { $prop.setStatementBlockGetter( $sbg2.statementblock, $sbg2.template ); } )?
)
pr_EndChar
(
pr_BeginChar
(
sbg1 = pr_PropertyGetter { $prop.setStatementBlockGetter( $sbg1.statementblock, $sbg1.template ); }
( sbs1 = pr_PropertySetter { $prop.setStatementBlockSetter( $sbs1.statementblock, $sbs1.template ); } )?
| sbs2 = pr_PropertySetter { $prop.setStatementBlockSetter( $sbs2.statementblock, $sbs2.template ); }
(sbg2 = pr_PropertyGetter { $prop.setStatementBlockGetter( $sbg2.statementblock, $sbg2.template ); } )?
)?
pr_EndChar
{
$prop.setHasBody();
$prop.setIsAutoProperty(false);
}
)?
);
pr_PropertyGetter returns[StatementBlock statementblock, TTCN3Template template]:
......
......@@ -164,8 +164,8 @@ public class OOP_Semantic_tests {
private ArrayList<MarkerToCheck> oopNegative_ttcn_initializer() {
//oopNegativeSemanticTest.ttcn
ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(86);
int lineNum = 32;
ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(87);
int lineNum = 33;
markersToCheck.add(new MarkerToCheck("class type expected", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 10;
int i = 0;
......@@ -265,7 +265,8 @@ public class OOP_Semantic_tests {
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));
markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `charstring' was expected instead of `integer'", ++lineNum, IMarker.SEVERITY_ERROR));
lineNum += 2;
markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `charstring' was expected instead of `integer'", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 19;
markersToCheck.add(new MarkerToCheck("Definition is overridden with different formal parameters", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 19;
......@@ -296,9 +297,11 @@ public class OOP_Semantic_tests {
markersToCheck.add(new MarkerToCheck("Invalid `value` reference", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 11;
markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `charstring' was expected instead of `integer'", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 8;
lineNum += 9;
markersToCheck.add(new MarkerToCheck("A property without a setter cannot have an initial value", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 14;
lineNum += 7;
markersToCheck.add(new MarkerToCheck("An empty property body is not allowed", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 12;
markersToCheck.add(new MarkerToCheck("Unknown field reference", lineNum, IMarker.SEVERITY_ERROR));
markersToCheck.add(new MarkerToCheck("Type mismatch: a value of type `charstring' was expected instead of `integer'", ++lineNum, IMarker.SEVERITY_ERROR));
lineNum += 8;
......@@ -310,7 +313,7 @@ public class OOP_Semantic_tests {
markersToCheck.add(new MarkerToCheck("An abstract class cannot be instantiated", ++lineNum, IMarker.SEVERITY_ERROR));
lineNum += 3;
markersToCheck.add(new MarkerToCheck("Private member is inaccessible due to its protection level", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 3;
lineNum += 5;
markersToCheck.add(new MarkerToCheck("Cannot assign a value to a property without a setter", lineNum, IMarker.SEVERITY_ERROR));
return markersToCheck;
......
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