/** * Copyright (c) 2014 committers of YAKINDU and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * Contributors: * committers of YAKINDU - initial API and implementation * */ package org.yakindu.sct.model.stext.inferrer; import static org.yakindu.base.types.typesystem.ITypeSystem.BOOLEAN; import static org.yakindu.base.types.typesystem.ITypeSystem.INTEGER; import static org.yakindu.base.types.typesystem.ITypeSystem.VOID; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.yakindu.base.expressions.expressions.ElementReferenceExpression; import org.yakindu.base.expressions.expressions.Expression; import org.yakindu.base.expressions.expressions.FeatureCall; import org.yakindu.base.expressions.inferrer.ExpressionsTypeInferrer; import org.yakindu.base.types.AnnotationType; import org.yakindu.base.types.Event; import org.yakindu.base.types.Property; import org.yakindu.sct.model.sgraph.Scope; import org.yakindu.sct.model.stext.stext.ActiveStateReferenceExpression; import org.yakindu.sct.model.stext.stext.ArgumentedAnnotation; import org.yakindu.sct.model.stext.stext.EventRaisingExpression; import org.yakindu.sct.model.stext.stext.EventValueReferenceExpression; import org.yakindu.sct.model.stext.stext.Guard; import org.yakindu.sct.model.stext.stext.TimeEventSpec; import org.yakindu.sct.model.stext.stext.VariableDefinition; /** * @author andreas muelder - Initial contribution and API * */ public class STextTypeInferrer extends ExpressionsTypeInferrer { public static final String VARIABLE_DEFINITION = "Cannot assign a value of type %s to a variable of type %s."; public static final String EVENT_DEFINITION = "Cannot assign a value of type %s to an event of type %s."; public static final String GUARD = "The evaluation result of a guard expression must be of type boolean."; public static final String TIME_SPEC = "The evaluation result of a time expression must be of type integer."; public static final String MISSING_VALUE = "Need to assign a value to an event of type %s."; public InferenceResult doInfer(VariableDefinition e) { InferenceResult result = inferTypeDispatch(e.getTypeSpecifier()); assertNotType(result, VARIABLE_VOID_TYPE, getResultFor(VOID)); if (e.getInitialValue() == null) return result; InferenceResult result2 = inferTypeDispatch(e.getInitialValue()); assertAssignable(result, result2, String.format(VARIABLE_DEFINITION, result2, result)); return result; } public InferenceResult doInfer(Event e) { // if an event is used within an expression, the type is boolean and the // value indicates if the event is raised or not return getResultFor(BOOLEAN); } public InferenceResult doInfer(Guard e) { InferenceResult result = inferTypeDispatch(e.getExpression()); assertIsSubType(result, getResultFor(BOOLEAN), GUARD); return result; } public InferenceResult doInfer(TimeEventSpec e) { InferenceResult result = inferTypeDispatch(e.getValue()); assertIsSubType(result, getResultFor(INTEGER), TIME_SPEC); return inferTypeDispatch(result.getType()); } public InferenceResult doInfer(Scope scope) { return getResultFor(VOID); } public InferenceResult doInfer(EventValueReferenceExpression e) { Event definition = deresolve(e.getValue()); if (definition != null) return definition.getTypeSpecifier() == null ? getResultFor(VOID) : inferTypeDispatch(definition.getTypeSpecifier()); return inferTypeDispatch(e.getValue()); } public InferenceResult doInfer(EventRaisingExpression e) { Event event = deresolve(e.getEvent()); InferenceResult eventType = null; if (event != null) eventType = inferTypeDispatch(event.getTypeSpecifier()); eventType = eventType != null ? eventType : getResultFor(VOID); if (e.getValue() == null) { assertSame(eventType, getResultFor(VOID), String.format(MISSING_VALUE, eventType)); return getResultFor(VOID); } InferenceResult valueType = inferTypeDispatch(e.getValue()); assertAssignable(eventType, valueType, String.format(EVENT_DEFINITION, valueType, eventType)); return valueType; } protected Event deresolve(Expression e) { // TODO This is ugly -> reuse the TypeTrace to determine the context in // infer(Event) if (e instanceof ElementReferenceExpression) { EObject reference = ((ElementReferenceExpression) e).getReference(); if (reference instanceof Event) { return (Event) reference; } } if (e instanceof FeatureCall) { EObject reference = ((FeatureCall) e).getFeature(); if (reference instanceof Event) { return (Event) reference; } } return null; } public InferenceResult doInfer(ActiveStateReferenceExpression e) { return getResultFor(BOOLEAN); } public InferenceResult doInfer(ArgumentedAnnotation ad) { EList<Expression> arguments = ad.getArgs(); inferAnnotationProperty(ad.getType(), arguments); return getResultFor(VOID); } protected void inferAnnotationProperty(AnnotationType type, EList<Expression> arguments) { EList<Property> properties = type.getProperties(); if (properties.size() == arguments.size()) { for (int i = 0; i < properties.size(); i++) { InferenceResult type1 = inferTypeDispatch(properties.get(i)); InferenceResult type2 = inferTypeDispatch(arguments.get(i)); assertCompatible(type1, type2, String.format(INCOMPATIBLE_TYPES, type1, type2)); } } } }