Commit b12a5766 authored by Miklos Magyari's avatar Miklos Magyari
Browse files

OOP: implemented variable level property modifiers (issue #427)


Signed-off-by: Miklos Magyari's avatarMiklos Magyari <miklos.magyari@sigmatechnology.se>
parent 340277e2
......@@ -410,8 +410,12 @@ type class PropertyClass {
// invalid: bad combination of modifiers
var float @property prop_modifiers {
@final @abstract @get {
return 0.1;
@final @abstract @get;
}
var @abstract integer @property prop_modifiers2 {
@get {
return 1;
}
}
}
......
......@@ -46,22 +46,24 @@ 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";
private static final String GETMISSINGRETURN = "Statement block of a property getter should have a `return' statement";
private static final String MODIFIERFINALABSTRACT = "Property {0} cannot be both abstract and final";
private static final String ABSTRACTWITHBODY = "Abstract {0} should not have a body";
/** type of the property */
private Type myType;
/** statement block of the property getter, if defined */
private StatementBlock getStatementBlock;
private StatementBlock getterStatementBlock;
/** statement block of the property setter, if defined */
private StatementBlock setStatementBlock;
private StatementBlock setterStatementBlock;
/** template definition of the property getter, if defined */
private TTCN3Template getTemplate;
private TTCN3Template getterTemplate;
/** template definition of the property setter, if defined */
private TTCN3Template setTemplate;
private TTCN3Template setterTemplate;
/** a template containing the initial value for the property */
private TTCN3Template initValTemplate;
......@@ -78,6 +80,10 @@ public final class Property_Type extends Type {
private boolean isAutoProperty;
/** Modifiers */
private boolean isAbstract;
private boolean isFinal;
private boolean isDeterministic;
private boolean isInternal;
private boolean isGetterAbstract;
private boolean isSetterAbstract;
private boolean isGetterFinal;
......@@ -91,13 +97,17 @@ public final class Property_Type extends Type {
private Location getterModifierLocation;
private Location setterModifierLocation;
public Property_Type(Type type) {
public Property_Type(Type type, boolean isAbstract, boolean isFinal, boolean isDeterministic, boolean isInternal) {
this.myType = type;
this.isAbstract = isAbstract;
this.isFinal = isFinal;
this.isDeterministic = isDeterministic;
this.isInternal = isInternal;
this.setStatementBlock = null;
this.getStatementBlock = null;
this.setTemplate = null;
this.getTemplate = null;
this.setterStatementBlock = null;
this.getterStatementBlock = null;
this.setterTemplate = null;
this.getterTemplate = null;
this.initValTemplate = null;
this.isAutoProperty = true;
this.hasSetter = false;
......@@ -113,7 +123,7 @@ public final class Property_Type extends Type {
boolean isAbstract, boolean isFinal, boolean isDeterministic,
Location visibilityLocation, Location modifierLocation) {
hasGetter = true;
getStatementBlock = sb;
getterStatementBlock = sb;
getterModifier = modifier;
isGetterAbstract = isAbstract;
isGetterFinal = isFinal;
......@@ -121,12 +131,12 @@ public final class Property_Type extends Type {
getterVisibilityLocation = visibilityLocation;
getterModifierLocation = modifierLocation;
if (getStatementBlock != null) {
getStatementBlock.setIsGetter();
getStatementBlock.setOwnerIsProperty();
getStatementBlock.setFullNameParent(this);
if (getterStatementBlock != null) {
getterStatementBlock.setIsGetter();
getterStatementBlock.setOwnerIsProperty();
getterStatementBlock.setFullNameParent(this);
}
getTemplate = template;
getterTemplate = template;
}
/**
......@@ -137,19 +147,19 @@ public final class Property_Type extends Type {
boolean isAbstract, boolean isFinal, boolean isDeterministic,
Location visibilityLocation, Location modifierLocation) {
hasSetter = true;
setStatementBlock = sb;
setterStatementBlock = sb;
isSetterAbstract = isAbstract;
isSetterFinal = isFinal;
isSetterDeterministic = isDeterministic;
setterVisibilityLocation = visibilityLocation;
setterModifierLocation = modifierLocation;
if (setStatementBlock != null) {
setStatementBlock.setIsSetter();
setStatementBlock.setOwnerIsProperty();
setStatementBlock.setFullNameParent(this);
if (setterStatementBlock != null) {
setterStatementBlock.setIsSetter();
setterStatementBlock.setOwnerIsProperty();
setterStatementBlock.setFullNameParent(this);
}
setTemplate = template;
setterTemplate = template;
}
@Override
......@@ -172,15 +182,15 @@ public final class Property_Type extends Type {
checkModifiers();
if (getStatementBlock != null) {
getStatementBlock.check(timestamp);
if (getStatementBlock.hasReturn(timestamp) == ReturnStatus_type.RS_NO) {
getStatementBlock.getLocation().reportSemanticError(GETMISSINGRETURN);
if (getterStatementBlock != null) {
getterStatementBlock.check(timestamp);
if (getterStatementBlock.hasReturn(timestamp) == ReturnStatus_type.RS_NO) {
getterStatementBlock.getLocation().reportSemanticError(GETMISSINGRETURN);
}
}
if (setStatementBlock != null) {
setStatementBlock.setValueParamList(fpList);
setStatementBlock.check(timestamp);
if (setterStatementBlock != null) {
setterStatementBlock.setValueParamList(fpList);
setterStatementBlock.check(timestamp);
}
if (initValTemplate != null && hasSetter() == false) {
initValTemplate.getLocation().reportSemanticError(INITIALVALUEWITHOUTSETTER);
......@@ -192,13 +202,32 @@ public final class Property_Type extends Type {
* Semantic check of property getter/setter modifiers
*/
public void checkModifiers() {
if (isGetterAbstract && isGetterFinal) {
getterModifierLocation.reportSemanticError(MessageFormat.format(
MODIFIERFINALABSTRACT, "getter"));
if (isAbstract) {
isGetterAbstract = true;
isSetterAbstract = true;
}
if (isSetterAbstract && isSetterFinal) {
setterModifierLocation.reportSemanticError(MessageFormat.format(
MODIFIERFINALABSTRACT, "setter"));
if (isGetterAbstract) {
if (isGetterFinal) {
getterModifierLocation.reportSemanticError(MessageFormat.format(
MODIFIERFINALABSTRACT, "getter"));
}
if (getterStatementBlock != null || getterTemplate != null) {
final Location getterLoc = getterStatementBlock == null ? getterTemplate.getLocation() : getterStatementBlock.getLocation();
getterLoc.reportSemanticError(MessageFormat.format(
ABSTRACTWITHBODY, "getter"));
}
}
if (isSetterAbstract) {
if (isSetterFinal) {
setterModifierLocation.reportSemanticError(MessageFormat.format(
MODIFIERFINALABSTRACT, "setter"));
}
if (setterStatementBlock != null || setterTemplate != null) {
final Location setterLoc = setterStatementBlock == null ? setterTemplate.getLocation() : setterStatementBlock.getLocation();
setterLoc.reportSemanticError(MessageFormat.format(
ABSTRACTWITHBODY, "setter"));
}
}
}
......@@ -221,12 +250,11 @@ public final class Property_Type extends Type {
/** {@inheritDoc} */
public void setMyScope(final Scope scope) {
super.setMyScope(scope);
if (getStatementBlock != null) {
Scope s = getMyScope();
getStatementBlock.setMyScope(scope);
if (getterStatementBlock != null) {
getterStatementBlock.setMyScope(scope);
}
if (setStatementBlock != null) {
setStatementBlock.setMyScope(scope);
if (setterStatementBlock != null) {
setterStatementBlock.setMyScope(scope);
}
}
......
......@@ -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", "@control", "@final", "@property", "@trait"
"@abstract", "@control", "@final", "@internal", "@property", "@trait"
};
public static final String[] TEMPLATE_MATCH = new String[] { "complement", "decmatch", "ifpresent", "subset", "superset", "permutation",
......
......@@ -51,7 +51,7 @@ public final class TTCN3Keywords {
public static final String[] OOP_ALL_AVAILABLE = new String[] {
/* OOP extension keywords */
"class", "@abstract", "@control", "@final", "@trait", "@property", "this", "super", "finally"
"@abstract", "@control", "@final", "@internal", "@property", "@trait", "class", "this", "super", "finally"
};
public static final String[] FORMAL_PARAMETER_SCOPE = new String[] { "in", "inout", "out", "template" };
......
......@@ -562,6 +562,7 @@ TRAITKEYWORD: '@trait' { isOopEnabled }? ;
PROPERTYKEYWORD: '@property' { isOopEnabled }? ;
SETKEYWORD: '@set' { isOopEnabled }? ;
GETKEYWORD: '@get' { isOopEnabled }? ;
INTERNALKEYWORD: '@internal' { isOopEnabled }? ;
fragment DIGIT: [0-9];
......
......@@ -4478,13 +4478,17 @@ pr_ControlStatement returns[Statement statement]
$statement.setLocation(getLocation( $start, getLastVisibleToken())); }
);
pr_VarInstance returns[List<Definition> definitions, Type type]
pr_VarInstance returns[List<Definition> definitions, Type type, boolean isAbstract, boolean isFinal, boolean isDeterministic, boolean isInternal]
@init {
$definitions = new ArrayList<Definition>();
List<Identifier> identifiers = null;
TemplateRestriction.Restriction_type templateRestriction = TemplateRestriction.Restriction_type.TR_NONE;
parameterEvaluationType eval = parameterEvaluationType.NORMAL_EVAL;
$type = null;
$isAbstract = false;
$isFinal = false;
$isDeterministic = false;
$isInternal = false;
}:
( col = pr_VarKeyword
( tr = pr_TemplateOptRestricted { templateRestriction = $tr.templateRestriction; }
......@@ -4493,8 +4497,14 @@ pr_VarInstance returns[List<Definition> definitions, Type type]
pr_TempVarList[ $definitions, $t.type, templateRestriction ]
|
lf = pr_OptLazyOrFuzzyModifier { eval = $lf.eval; }
( pmod = pr_PropertyGlobalModifier {
$isAbstract = $pmod.isAbstract;
$isFinal = $pmod.isFinal;
$isDeterministic = $pmod.isDeterministic;
$isInternal = $pmod.isInternal;
})
t2 = pr_Type { $type = $t2.type; }
pr_VarList[ $definitions, $t2.type, eval ]
pr_VarList[ $definitions, $t2.type, eval, $isAbstract, $isFinal, $isDeterministic, $isInternal ]
)
)
{
......@@ -4550,14 +4560,14 @@ pr_SingleTempVarInstance [List<Definition> definitions, Type type, TemplateRestr
};
pr_VarList[List<Definition> definitions, Type type, parameterEvaluationType eval]:
( d = pr_SingleVarInstance[type, eval] { if($d.definition != null) { $definitions.add($d.definition); } }
pr_VarList[List<Definition> definitions, Type type, parameterEvaluationType eval, boolean isAbstract, boolean isFinal, boolean isDeterministic, boolean isInternal]:
( d = pr_SingleVarInstance[type, eval, isAbstract, isFinal, isDeterministic, isInternal] { if($d.definition != null) { $definitions.add($d.definition); } }
( pr_Comma
d = pr_SingleVarInstance[type, eval] { if($d.definition != null) { $definitions.add($d.definition); } }
d = pr_SingleVarInstance[type, eval, isAbstract, isFinal, isDeterministic, isInternal] { if($d.definition != null) { $definitions.add($d.definition); } }
)*
);
pr_SingleVarInstance[Type type, parameterEvaluationType eval] returns[Def_Var definition]
pr_SingleVarInstance[Type type, parameterEvaluationType eval, boolean isAbstract, boolean isFinal, boolean isDeterministic, boolean isInternal] returns[Def_Var definition]
@init {
$definition = null;
Value value = null;
......@@ -4582,7 +4592,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, isAbstract, isFinal, isDeterministic, isInternal] { prop = $body.prop; }
)
)
{
......@@ -4598,7 +4608,7 @@ pr_SingleVarInstance[Type type, parameterEvaluationType eval] returns[Def_Var de
if (prop != null) {
prop.setInitValTemplate(initValTemplate);
}
type2 = prop == null ? new Property_Type(type) : prop;
type2 = prop == null ? new Property_Type(type, $isAbstract, $isFinal, $isDeterministic, $isInternal) : prop;
type2.setLocation(getLocation( $prop.start, getLastVisibleToken()));
}
$definition = new Def_Var( $i.identifier, type2, value, $eval );
......@@ -9178,7 +9188,7 @@ pr_ClassMember returns[List<Definition> definitions]
}:
(
( vis = pr_OopVisibility { visibility = $vis.visibility; } )?
( var = pr_VarInstance { $definitions = $var.definitions; }
( var = pr_VarInstance { $definitions = $var.definitions; }
| timer = pr_TimerInstance { $definitions = $timer.definitions; }
| con = pr_ConstDef { $definitions = $con.array; }
| { boolean isTemplateVar = false; }
......@@ -9454,9 +9464,9 @@ pr_SelectClassCase:
SEMICOLON?
);
pr_PropertyBody[Type type] returns[Property_Type prop]
pr_PropertyBody[Type type, boolean isAbstract, boolean isFinal, boolean isDeterministic, boolean isInternal] returns[Property_Type prop]
@init {
$prop = new Property_Type(type);
$prop = new Property_Type(type, $isAbstract, $isFinal, $isDeterministic, $isInternal);
}:
(
(
......@@ -9574,6 +9584,21 @@ pr_PropertyVisibility returns[VisibilityModifier visibility]
)?
;
pr_PropertyGlobalModifier returns[boolean isAbstract, boolean isFinal, boolean isDeterministic, boolean isInternal]
@init {
$isAbstract = false;
$isFinal = false;
$isDeterministic = false;
$isInternal = false;
}:
(
pr_AbstractModifier { $isAbstract = true; }
| pr_FinalModifier { $isFinal = true;}
| DETERMINISTICKEYWORD { $isDeterministic = true; }
| INTERNALKEYWORD { $isInternal = true; }
)*
;
pr_PropertyModifier returns[boolean isAbstract, boolean isFinal, boolean isDeterministic]
@init {
$isAbstract = false;
......
......@@ -164,7 +164,7 @@ public class OOP_Semantic_tests {
private ArrayList<MarkerToCheck> oopNegative_ttcn_initializer() {
//oopNegativeSemanticTest.ttcn
ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(90);
ArrayList<MarkerToCheck> markersToCheck = new ArrayList<MarkerToCheck>(91);
int lineNum = 33;
markersToCheck.add(new MarkerToCheck("class type expected", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 10;
......@@ -307,6 +307,8 @@ public class OOP_Semantic_tests {
markersToCheck.add(new MarkerToCheck("Statement block of a property getter should have a `return' statement", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 7;
markersToCheck.add(new MarkerToCheck("Property getter cannot be both abstract and final", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 4;
markersToCheck.add(new MarkerToCheck("Abstract getter should not have a body", lineNum, IMarker.SEVERITY_ERROR));
lineNum += 13;
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));
......
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