Commit 74abde7f authored by Daniel Honsel's avatar Daniel Honsel
Browse files

more scoping and validation

- added name clash validation for test cases
- added scope for test case fields
parent 36163b97
Loading
Loading
Loading
Loading
+10 −13
Original line number Diff line number Diff line
@@ -174,14 +174,11 @@ AltstepLocalDef:
	VarInstance | TimerInstance | ConstDef | TemplateDef;

TestcaseDef:
	TESTCASEKEYWORD name=IDENTIFIER LPAREN params=TemplateOrValueFormalParList? RPAREN speck=ConfigSpec
	TESTCASEKEYWORD name=IDENTIFIER LPAREN parList=TemplateOrValueFormalParList? RPAREN spec=ConfigSpec
	statement=StatementBlock;

TestcaseRef:
	name=[TestcaseDef|IDENTIFIER];

TemplateOrValueFormalParList:
	par+=TemplateOrValueFormalPar (COMMA par+=TemplateOrValueFormalPar);
	params+=TemplateOrValueFormalPar (COMMA params+=TemplateOrValueFormalPar)*;

TemplateOrValueFormalPar:
	value=FormalValuePar | template=FormalTemplatePar;
@@ -433,8 +430,8 @@ ComponentOrDefaultReference:
	variable=VariableRef | function=FunctionInstance;

TestcaseInstance:
	EXECUTEKEYWORD LPAREN TestcaseRef LPAREN tcParams=TestcaseActualParList? RPAREN (COMMA (expr=Expression | MINUS)
	(COMMA sexpr=SingleExpression)?)? RPAREN;
	EXECUTEKEYWORD LPAREN ref=[TestcaseDef|IDENTIFIER] LPAREN tcParams=TestcaseActualParList? RPAREN (COMMA
	(expr=Expression | MINUS) (COMMA sexpr=SingleExpression)?)? RPAREN;

TestcaseActualParList:
	(templParam+=TemplateInstanceActualPar (COMMA templParam+=TemplateInstanceActualPar)*) |
@@ -653,7 +650,7 @@ StructuredTypeDef:
RecordDef:
	RECORDKEYWORD ADDRESSKEYWORD StructDefBody | RecordDefNamed;

RecordDefNamed returns RecordDef:
RecordDefNamed:
	RECORDKEYWORD name=IDENTIFIER body=StructDefBody;

RecordOfDef:
@@ -720,7 +717,6 @@ ProcedureAttribs:
	PROCEDUREKEYWORD LBRACKET ((addresses+=AddressDecl | procs+=ProcedureList | configs+=ConfigParamDef) SEMICOLON?)+
	RBRACKET;

	// TODO: restrict extends type scope (do not allow self referencing)
ComponentDef:
	COMPONENTKEYWORD name=IDENTIFIER (EXTENDSKEYWORD extends+=[ComponentDef|IDENTIFIER] (COMMA
	extends+=[ComponentDef|IDENTIFIER])*)? LBRACKET defs+=ComponentDefList* RBRACKET;
@@ -835,7 +831,7 @@ PatternParticle:
	{PatternParticle} CSTRING | ReferencedValue;

TemplateDef:
	TEMPLATEKEYWORD res=TemplateRestriction? base=BaseTemplate derived=DerivedDef? ac=ASSIGNMENTCHAR body=TemplateBody;
	TEMPLATEKEYWORD res=TemplateRestriction? base=BaseTemplate derived=DerivedDef? ASSIGNMENTCHAR body=TemplateBody;

DerivedDef:
	MODIFIESKEYWORD name=ExtendedIdentifier;
@@ -868,7 +864,7 @@ FieldSpecList:
	LBRACKET spec+=FieldSpec (COMMA spec+=FieldSpec)* RBRACKET;

FieldSpec:
	ref=FieldReference ASSIGNMENTCHAR (body=TemplateBody | MINUS);
	ref=[StructFieldDef|IDENTIFIER] ASSIGNMENTCHAR (body=TemplateBody | MINUS);

SimpleSpec:
	expr=SingleExpression (STRINGOP spec=SimpleTemplateSpec)? | spec=SimpleTemplateSpec;
@@ -877,7 +873,7 @@ SimpleTemplateSpec:
	expr=SingleTemplateExpression (STRINGOP spec=SimpleSpec)?;

SingleTemplateExpression:
	symbol=MatchingSymbol | list=TemplateRefWithParList ref+=ExtendedFieldReference*;
	symbol=MatchingSymbol | list=TemplateRefWithParList ref+=ExtendedFieldReference;

TemplateRefWithParList:
	name=ExtendedIdentifier list=TemplateActualParList?;
@@ -1045,7 +1041,8 @@ ReferencedValue:
	ref=[RefValue|IDENTIFIER] ext+=ExtendedFieldReference*;

RefValue:
	SingleConstDef | ModuleParameter | SingleVarInstance | RecordOfDefNamed | SetOfDefNamed | FormalValuePar;
	SingleConstDef | ModuleParameter | SingleVarInstance | RecordOfDefNamed | SetOfDefNamed | FormalValuePar |
	FormalTemplatePar;

	// IDENTIFIER omitted
PredefinedValue:
+15 −0
Original line number Diff line number Diff line
@@ -11,6 +11,9 @@ import de.ugoe.cs.swe.tTCN3.ComponentDef
import de.ugoe.cs.swe.tTCN3.ModuleDefinitionsList
import de.ugoe.cs.swe.tTCN3.TypeDef
import de.ugoe.cs.swe.tTCN3.ModuleDefinition
import de.ugoe.cs.swe.tTCN3.FieldSpec
import de.ugoe.cs.swe.tTCN3.TemplateDef
import de.ugoe.cs.swe.tTCN3.RecordDefNamed

class TTCN3ScopeProvider extends AbstractDeclarativeScopeProvider {

@@ -34,4 +37,16 @@ class TTCN3ScopeProvider extends AbstractDeclarativeScopeProvider {
		scopeFor(inner)
	}


	def IScope scope_FieldSpec_ref(FieldSpec spec, EReference ref) {
		val template = spec.findDesiredParent(typeof(TemplateDef)) as TemplateDef
		val type = template.base.type
		val inner = newArrayList
		
		if (type != null && type.ref != null && typeof(RecordDefNamed).isAssignableFrom(type.ref.class)) {
			inner.addAll((type.ref as RecordDefNamed).body.defs)
		}
		scopeFor(inner)
	}

}
+47 −11
Original line number Diff line number Diff line
@@ -24,6 +24,10 @@ import de.ugoe.cs.swe.tTCN3.ModuleControlPart
import de.ugoe.cs.swe.tTCN3.ControlStatementOrDefList
import de.ugoe.cs.swe.tTCN3.ComponentDef
import de.ugoe.cs.swe.tTCN3.ComponentDefList
import de.ugoe.cs.swe.tTCN3.TemplateOrValueFormalParList
import de.ugoe.cs.swe.tTCN3.TemplateOrValueFormalPar
import de.ugoe.cs.swe.tTCN3.TestcaseDef
import org.eclipse.emf.ecore.EStructuralFeature

class TTCN3Validator extends AbstractTTCN3Validator {

@@ -60,48 +64,67 @@ class TTCN3Validator extends AbstractTTCN3Validator {

	def private isNameClashInHierarchy(RefValue variable) {
		var parent = variable.eContainer
		var EStructuralFeature feature = null;
		
//		if (variable instanceof SingleConstDef)
//			feature = null
//		else if (variable instanceof SingleVarInstance)
//			feature = null
//		else if (variable instanceof FormalValuePar)
//			feature = TTCN3Package.eINSTANCE.

		while (parent != null) {

			if (parent instanceof TTCN3Module) {
				if (parent.defs != null && parent.defs.checkNameClashModuleDefinitionsList(variable)) {

					// TODO: TTCN3Package$Literals::SINGLE_CONST_DEF__NAME
					error('Name clash with another variable definition in this scope!', null, -1);
					error('Name clash with another variable definition in this scope!',  feature);
					return;
				}
			} else if (parent instanceof StatementBlock) {
				if (parent.checkNameClasStatementBlock(variable)) {
					error('Name clash with another variable definition in this scope!', null, -1);
					error('Name clash with another variable definition in this scope!', feature);
					return;
				}
			} else if (parent instanceof Initial) {
				if (parent.checkNameClashInitial(variable)) {
					error('Name clash with another variable definition in this scope!', null, -1);
					error('Name clash with another variable definition in this scope!', feature);
					return;
				}
			} else if (parent instanceof ForStatement) {
				if (parent.init.checkNameClashInitial(variable)) {
					error('Name clash with another variable definition in this scope!', null, -1);
					error('Name clash with another variable definition in this scope!', feature);
					return;
				}
			} else if (parent instanceof FunctionDef) {
				if (parent.parameterList != null && parent.parameterList.checkNameClashFunctionParameterValue(variable)) {
					error('Name clash with another variable definition in this scope!', null, -1);
					error('Name clash with another variable definition in this scope!', feature);
					return;
				}
			} else if (parent instanceof FunctionFormalParList) {
				if (parent.checkNameClashFunctionParameterValue(variable)) {
					error('Name clash with another variable definition in this scope!', null, -1);
					error('Name clash with another variable definition in this scope!', feature);
					return;
				}
			} else if (parent instanceof ModuleControlPart) {
				if (parent.checkNameClashModuleControlPart(variable)) {
					error('Name clash with another variable definition in this scope!', null, -1);
					error('Name clash with another variable definition in this scope!', feature);
					return;
				}
			} else if (parent instanceof ComponentDef) {
				if (!parent.checkNameClashComponentDefHierarchy(variable)) {
					error('Name clash with another variable definition in this scope!', null, -1);
					error('Name clash with another variable definition in this scope!', feature);
					return;
				}
			} else if (parent instanceof TestcaseDef) {
				if (parent.parList.checkNameClashTemplateOrValueFormalParList(variable)) {
					error('Name clash with another variable definition in this scope!', feature);
					return;
				}
			} else if (parent instanceof TemplateOrValueFormalParList) {
				if (parent.checkNameClashTemplateOrValueFormalParList(variable)) {
					error('Name clash with another variable definition in this scope!', feature);
					return;
				}
			}
@@ -225,14 +248,27 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		return res;
	}
		
	def private boolean checkNameClashTemplateOrValueFormalParList(TemplateOrValueFormalParList list, RefValue variable) {
		var RefValue value;
		
		for (TemplateOrValueFormalPar p: list.params) {
			if (p.value != null)
				value = p.value as RefValue
			else if (p.template != null)
				value = p.template as RefValue;
				
			if (value != null && value != variable && value.name == variable.name)
				return true;
		}			
		return false;
	}	

	@Check
	def checkModuleStartsWithM(TTCN3Module module) {
		val char pattern = 'M';

		if (module.name.charAt(0) != pattern) {

			//TODO: TTCN3Package$Literals::TTCN3_MODULE__NAME or get EStructuralFeature from somewhere else
			warning('Module names should start with M!', null, TTCN3Package.TTCN3_MODULE__NAME);
			warning('Module names should start with M!', TTCN3Package.eINSTANCE.TTCN3Module_Name);
		}
	}