Commit 28979b4d authored by Adam Knapp's avatar Adam Knapp
Browse files

Implemented conjunction, implication and dynamic templates, part 1

issues #413, #414 and #415

Signed-off-by: Adam Knapp's avatarAdam Knapp <adam.knapp@ericsson.com>
parent 2d8135f2
......@@ -467,6 +467,7 @@ public class Identifier implements ILocateableNode, IVisitableNode {
{"check__", "check", "check_"},
{"clear__", "clear", "clear_"},
{"complement__", "complement", "complement_"},
{"conjunct__", "conjunct", "conjunct_"},
{"connect__", "connect", "connect_"},
{"control__", "control", "control_"},
{"create__", "create", "create_"},
......@@ -494,6 +495,7 @@ public class Identifier implements ILocateableNode, IVisitableNode {
{"halt__", "halt", "halt_"},
{"hexstring__", "hexstring", "hexstring_"},
{"ifpresent__", "ifpresent", "ifpresent_"},
{"implies__", "implies", "implies_"},
{"import__", "import", "import_"},
{"in__", "in", "in_"},
{"inconc__", "inconc", "inconc_"},
......
......@@ -80,9 +80,13 @@ public class Reference extends ASTNode implements ILocateableNode, IIncrementall
private static final String VALUENOTSETTER = "A property getter cannot have a `value` reference";
public enum Ref_Type {
/** basic reference (not related to a class scope or a dynamic template) */
REF_BASIC,
/** reference to the current class object */
REF_THIS,
/** reference to the superclass */
REF_SUPER,
/** reference to the value being matched in a dynamic template or to be used in an OOP property */
REF_VALUE
}
......
......@@ -51,6 +51,7 @@ public final class Return_Statement extends Statement {
private static final String USAGEINCONTROLPART = "Return statement cannot be used in the control part. It is allowed only in functions and altsteps";
private static final String RETURNINDESTRUCTOR = "Return statement cannot be used in a class destructor";
private static final String INVALIDSETTERRETURN = "Return statement cannot be used in a property setter";
private static final String RETURNINDYNAMICTEMPLATE = "The dynamic template's statement block should return a boolean value";
private static final String FULLNAMEPART = ".returnexpression";
private static final String STATEMENT_NAME = "return";
private static final String RETURNTYPEEXPECTED = "Return type `{0}'' expected";
......@@ -171,6 +172,11 @@ public final class Return_Statement extends Statement {
location.reportSemanticError(MessageFormat.format(MISSINGVALUE, returnType.getTypename()));
break;
}
if (myStatementBlock.isInDynamicTemplate()
&& !returnType.getTypetype().equals(Type_type.TYPE_BOOL)) {
template.getLocation().reportSemanticError(RETURNINDYNAMICTEMPLATE);
break;
}
if (!template.isValue(timestamp)) {
template.getLocation().reportSemanticError(SPECIFICVALUEEXPECTED);
break;
......
......@@ -44,6 +44,8 @@ import org.eclipse.titan.designer.AST.TTCN3.definitions.Def_Testcase;
import org.eclipse.titan.designer.AST.TTCN3.definitions.Definition;
import org.eclipse.titan.designer.AST.TTCN3.definitions.FormalParameterList;
import org.eclipse.titan.designer.AST.TTCN3.statements.Statement.Statement_type;
import org.eclipse.titan.designer.AST.TTCN3.templates.DynamicMatch_template;
import org.eclipse.titan.designer.AST.TTCN3.templates.TTCN3Template;
import org.eclipse.titan.designer.AST.TTCN3.types.ClassTypeBody;
import org.eclipse.titan.designer.AST.TTCN3.types.Component_Type;
import org.eclipse.titan.designer.compiler.JavaGenData;
......@@ -109,6 +111,9 @@ public final class StatementBlock extends TTCN3Scope implements ILocateableNode,
/** the definition containing this statement block. */
private Definition myDefinition;
/** the dynamic template, if this is the statement block of a dynamic template */
private DynamicMatch_template dynamicTemplate;
/** the time when this statement block was check the last time. */
private CompilationTimeStamp lastTimeChecked;
......@@ -135,6 +140,7 @@ public final class StatementBlock extends TTCN3Scope implements ILocateableNode,
/** Formal parameter list with only one member.
* It is used to support the special 'value' keyword in class properties
* and in dynamic templates
*/
private FormalParameterList valueParamList;
......@@ -1132,7 +1138,7 @@ public final class StatementBlock extends TTCN3Scope implements ILocateableNode,
}
}
/**
* Sets a formal parameter list for this statement block.
* It is used by class properties for the special keyword 'value'.
......@@ -1141,7 +1147,7 @@ public final class StatementBlock extends TTCN3Scope implements ILocateableNode,
public void setValueParamList(FormalParameterList fpl) {
this.valueParamList = fpl;
}
/**
* Gets a formal parameter list for this statement block.
* It is used by class properties for the special keyword 'value'.
......@@ -1154,7 +1160,7 @@ public final class StatementBlock extends TTCN3Scope implements ILocateableNode,
public boolean ownerIsProperty() {
return this.ownerIsProperty;
}
/**
* Checks wheter a statement block belongs to a property setter
* @return
......@@ -1166,7 +1172,7 @@ public final class StatementBlock extends TTCN3Scope implements ILocateableNode,
return false;
}
/**
* Checks wheter a statement block belongs to a property getter
* @return
......@@ -1178,18 +1184,68 @@ public final class StatementBlock extends TTCN3Scope implements ILocateableNode,
return false;
}
/**
* Sets the flag to indicate it is a statement block of a property getter
*/
public void setIsGetter() {
this.isPropertyGetter = true;
}
/**
* Sets the flag to indicate it is a statement block of a property setter
*/
public void setIsSetter() {
this.isPropertySetter = true;
}
/**
* Returns whether this statement block has a formal parameter list.
* It is used by class properties and by dynamic matching for the special keyword 'value'.
* @return {@code true} if a formal parameter list is set, otherwise {@code false}
*/
public boolean hasValueParamList() {
return valueParamList != null;
}
/**
* Returns the dynamic template of this statement block
* @return {@code null}, if this is not the statement block of a dynamic template
*/
public DynamicMatch_template getDynamicTemplate() {
if (dynamicTemplate != null) {
return dynamicTemplate;
}
if (myStatementBlock != null) {
return myStatementBlock.getDynamicTemplate();
}
ErrorReporter.INTERNAL_ERROR();
return null;
}
/**
* Sets the dynamic template for this statement block
* @param template
*/
public void setDynamicTemplate(final TTCN3Template template) {
if (template instanceof DynamicMatch_template) {
dynamicTemplate = (DynamicMatch_template)template;
} else {
ErrorReporter.INTERNAL_ERROR("TTCN3Template is not type of DynamicMatch_template");
}
}
/**
* Returns whether this statement block is in a dynamic template
* @return {@code true} if this statement block is in a dynamic template, otherwise {@code false}
*/
public boolean isInDynamicTemplate() {
if (dynamicTemplate != null) {
return true;
}
if (myStatementBlock != null) {
return myStatementBlock.isInDynamicTemplate();
}
return false;
}
}
/******************************************************************************
* Copyright (c) 2000-2021 Ericsson Telecom AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
******************************************************************************/
package org.eclipse.titan.designer.AST.TTCN3.templates;
import java.text.MessageFormat;
import java.util.ArrayList;
import org.eclipse.titan.common.logging.ErrorReporter;
import org.eclipse.titan.designer.AST.Assignment;
import org.eclipse.titan.designer.AST.IType;
import org.eclipse.titan.designer.AST.Location;
import org.eclipse.titan.designer.AST.Module;
import org.eclipse.titan.designer.AST.NULL_Location;
import org.eclipse.titan.designer.AST.Reference;
import org.eclipse.titan.designer.AST.IType.Type_type;
import org.eclipse.titan.designer.AST.TTCN3.Expected_Value_type;
import org.eclipse.titan.designer.AST.TTCN3.TemplateRestriction;
import org.eclipse.titan.designer.AST.TTCN3.values.expressions.ExpressionStruct;
import org.eclipse.titan.designer.compiler.JavaGenData;
import org.eclipse.titan.designer.parsers.CompilationTimeStamp;
/**
* Represents a template for conjunction matching.
*
* @author Adam Knapp
* */
public class ConjunctionMatch_template extends CompositeTemplate {
public ConjunctionMatch_template(final ListOfTemplates templates) {
super(templates);
}
@Override
/** {@inheritDoc} */
public boolean checkExpressionSelfReferenceTemplate(final CompilationTimeStamp timestamp, final Assignment lhs) {
for (int i = 0, size = templates.getNofTemplates(); i < size; i++) {
if(templates.getTemplateByIndex(i).checkExpressionSelfReferenceTemplate(timestamp, lhs)) {
return true;
}
}
return false;
}
@Override
/** {@inheritDoc} */
public boolean checkPresentRestriction(final CompilationTimeStamp timestamp, final String definitionName, final Location usageLocation) {
checkRestrictionCommon(timestamp, definitionName, TemplateRestriction.Restriction_type.TR_PRESENT, usageLocation);
boolean needsRuntimeCheck = false;
for (int i = 0, size = templates.getNofTemplates(); i < size; i++) {
final ITTCN3Template component = templates.getTemplateByIndex(i);
if (component.checkPresentRestriction(timestamp, definitionName, usageLocation)) {
needsRuntimeCheck = true;
}
}
return needsRuntimeCheck;
}
@Override
/** {@inheritDoc} */
public void checkSpecificValue(final CompilationTimeStamp timestamp, final boolean allowOmit) {
getLocation().reportSemanticError("A specific value expected instead of a conjunction match");
}
@Override
/** {@inheritDoc} */
public boolean checkThisTemplateGeneric(final CompilationTimeStamp timestamp, final IType type, final boolean isModified,
final boolean allowOmit, final boolean allowAnyOrOmit, final boolean subCheck, final boolean implicitOmit, final Assignment lhs) {
if (type == null) {
return false;
}
boolean selfReference = false;
for (int i = 0, size = templates.getNofTemplates(); i < size; i++) {
final TTCN3Template component = templates.getTemplateByIndex(i);
component.setMyGovernor(type);
final ITTCN3Template temporalComponent = type.checkThisTemplateRef(timestamp, component);
selfReference |= temporalComponent.checkThisTemplateGeneric(timestamp, type, false, false, true, subCheck, implicitOmit, lhs);
}
checkLengthRestriction(timestamp, type);
if (!allowOmit && isIfpresent) {
if (location != null && !(location instanceof NULL_Location)) {
location.reportSemanticError("`ifpresent' is not allowed here");
}
}
if (subCheck) {
type.checkThisTemplateSubtype(timestamp, this);
}
return selfReference;
}
@Override
/** {@inheritDoc} */
public void generateCodeInit(final JavaGenData aData, final StringBuilder source, final String name) {
if (lastTimeBuilt != null && !lastTimeBuilt.isLess(aData.getBuildTimstamp())) {
return;
}
lastTimeBuilt = aData.getBuildTimstamp();
aData.addBuiltinTypeImport( "Base_Template.template_sel" );
final ArrayList<Integer> variables = new ArrayList<Integer>();
long fixedPart = 0;
for (int i = 0; i < templates.getNofTemplates(); i++) {
final TTCN3Template templateListItem = templates.getTemplateByIndex(i);
if (templateListItem.getTemplatetype() == Template_type.ALL_FROM) {
variables.add(i);
} else {
fixedPart++;
}
}
final String typeName = myGovernor.getGenNameTemplate(aData, source);
if (variables.size() > 0) {
final StringBuilder preamble = new StringBuilder();
final StringBuilder setType = new StringBuilder();
final StringBuilder variableReferences[] = new StringBuilder[templates.getNofTemplates()];
setType.append(MessageFormat.format("{0}.set_type(template_sel.VALUE_LIST, {1}", name, fixedPart));
for (int v = 0; v < variables.size(); v++) {
TTCN3Template template = templates.getTemplateByIndex(variables.get(v));
// the template must be all from
if ( template instanceof All_From_Template ) {
template = ((All_From_Template)template).getAllFrom();
}
final Reference reference = ((SpecificValue_Template) template).getReference();
final Assignment assignment = reference.getRefdAssignment(CompilationTimeStamp.getBaseTimestamp(), false);
setType.append(" + ");
final ExpressionStruct expression = new ExpressionStruct();
reference.generateConstRef(aData, expression);
if (expression.preamble.length() > 0) {
preamble.append(expression.preamble);
}
switch (assignment.getAssignmentType()) {
case A_CONST:
case A_EXT_CONST:
case A_MODULEPAR:
case A_VAR:
case A_PAR_VAL:
case A_PAR_VAL_IN:
case A_PAR_VAL_OUT:
case A_PAR_VAL_INOUT:
case A_FUNCTION_RVAL:
case A_EXT_FUNCTION_RVAL:
if (assignment.getType(CompilationTimeStamp.getBaseTimestamp()).fieldIsOptional(reference.getSubreferences())) {
expression.expression.append(".constGet()");
}
break;
default:
break;
}
variableReferences[variables.get(v)] = expression.expression;
setType.append(expression.expression);
setType.append(".n_elem()");
}
source.append(preamble);
source.append(setType);
source.append(");\n");
final StringBuilder shifty = new StringBuilder();
for (int i = 0; i < templates.getNofTemplates(); i++) {
final TTCN3Template template = templates.getTemplateByIndex(i);
switch (template.getTemplatetype()) {
case ALL_FROM: {
// the template must be all from
final StringBuilder storedExpression = variableReferences[i];
source.append(MessageFormat.format("for (int i_i = 0, i_lim = {0}.n_elem(); i_i < i_lim; ++i_i ) '{'\n", storedExpression));
final String embeddedName = MessageFormat.format("{0}.list_item({1}{2} + i_i)", name, i, shifty);
((All_From_Template) template).generateCodeInitAllFrom(aData, source, embeddedName, storedExpression);
source.append("}\n");
shifty.append(MessageFormat.format("-1 + {0}.n_elem()", storedExpression));
break;
}
default:
if (template.needsTemporaryReference()) {
final String tempId = aData.getTemporaryVariableName();
source.append("{\n");
source.append(MessageFormat.format("final {0} {1} = {2}.list_item({3}{4});\n", typeName, tempId, name, i, shifty));
template.generateCodeInit(aData, source, tempId);
source.append("}\n");
} else {
final String embeddedName = MessageFormat.format("{0}.list_item({1}{2})", name, i, shifty);
template.generateCodeInit(aData, source, embeddedName);
}
break;
}
}
} else {
source.append(MessageFormat.format("{0}.set_type(template_sel.VALUE_LIST, {1});\n", name, templates.getNofTemplates()));
for (int i = 0; i < templates.getNofTemplates(); i++) {
final TTCN3Template template = templates.getTemplateByIndex(i);
if (template.needsTemporaryReference()) {
final String tempId = aData.getTemporaryVariableName();
source.append("{\n");
source.append(MessageFormat.format("final {0} {1} = {2}.list_item({3});\n", typeName, tempId, name, i));
template.generateCodeInit(aData, source, tempId);
source.append("}\n");
} else {
final String embeddedName = MessageFormat.format("{0}.list_item({1})", name, i);
template.generateCodeInit(aData, source, embeddedName);
}
}
}
if (lengthRestriction != null) {
if(getCodeSection() == CodeSectionType.CS_POST_INIT) {
lengthRestriction.reArrangeInitCode(aData, source, myScope.getModuleScopeGen());
}
lengthRestriction.generateCodeInit(aData, source, name);
}
if (isIfpresent) {
source.append(name);
source.append(".set_ifPresent();\n");
}
}
@Override
/** {@inheritDoc} */
public IType getExpressionGovernor(final CompilationTimeStamp timestamp, final Expected_Value_type expectedValue) {
if (myGovernor != null) {
return myGovernor;
}
for (int i = 0, size = templates.getNofTemplates(); i < size; i++) {
final IType type = templates.getTemplateByIndex(i).getExpressionGovernor(timestamp, expectedValue);
if (type != null) {
return type;
}
}
return null;
}
@Override
/** {@inheritDoc} */
public Type_type getExpressionReturntype(final CompilationTimeStamp timestamp, final Expected_Value_type expectedValue) {
if (getIsErroneous(timestamp)) {
return Type_type.TYPE_UNDEFINED;
}
for (int i = 0, size = templates.getNofTemplates(); i < size; i++) {
final Type_type type = templates.getTemplateByIndex(i).getExpressionReturntype(timestamp, expectedValue);
if (!Type_type.TYPE_UNDEFINED.equals(type)) {
return type;
}
}
return Type_type.TYPE_UNDEFINED;
}
@Override
protected String getNameForStringRep() {
return "conjunct";
}
@Override
/** {@inheritDoc} */
public StringBuilder getSingleExpression(final JavaGenData aData, final boolean castIsNeeded) {
final StringBuilder result = new StringBuilder();
ErrorReporter.INTERNAL_ERROR("FATAL ERROR while processing conjunction match `" + getFullName() + "''");
return result;
}
@Override
/** {@inheritDoc} */
public Template_type getTemplatetype() {
return Template_type.CONJUNCTION_MATCH;
}
@Override
/** {@inheritDoc} */
public String getTemplateTypeName() {
if (isErroneous) {
return "erroneous conjunction match";
}
return "conjunction match";
}
@Override
/** {@inheritDoc} */
public boolean hasSingleExpression() {
return false;
}
@Override
/** {@inheritDoc} */
public boolean needsTemporaryReference() {
return true;
}
@Override
/** {@inheritDoc} */
public void reArrangeInitCode(final JavaGenData aData, final StringBuilder source, final Module usageModule) {
for (int i = 0; i < templates.getNofTemplates(); i++) {
templates.getTemplateByIndex(i).reArrangeInitCode(aData, source, usageModule);
}
if (lengthRestriction != null) {
lengthRestriction.reArrangeInitCode(aData, source, usageModule);
}
}
}
/******************************************************************************
* Copyright (c) 2000-2021 Ericsson Telecom AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
******************************************************************************/
package org.eclipse.titan.designer.AST.TTCN3.templates;
import org.eclipse.titan.common.logging.ErrorReporter;
import org.eclipse.titan.designer.AST.Assignment;
import org.eclipse.titan.designer.AST.IReferenceChain;
import org.eclipse.titan.designer.AST.Reference;
import org.eclipse.titan.designer.AST.Scope;
import org.eclipse.titan.designer.AST.TTCN3.definitions.FormalParameter;
import org.eclipse.titan.designer.AST.TTCN3.definitions.FormalParameterList;
import org.eclipse.titan.designer.AST.TTCN3.statements.Return_Statement;
import org.eclipse.titan.designer.AST.TTCN3.statements.StatementBlock;
import org.eclipse.titan.designer.compiler.JavaGenData;
import org.eclipse.titan.designer.parsers.CompilationTimeStamp;
/**
* Represents a template for implication matching.
*
* @author Adam Knapp
* */
public class DynamicMatch_template extends TTCN3Template {
/** function reference used in defining the dynamic template, not owned */
private Reference reference;
/** statement block of the dynamic template
* (if the template is defined using a function reference instead of a statement block,
* then a new statement block is generated with a return statement containing the function reference) */
private StatementBlock statementBlock;
/** Pointer to the formal parameter list if this template is part of
* a parameterized template. It is {@code null} otherwise. */
private FormalParameterList formalParameterList;
public DynamicMatch_template(final Reference reference) {
// '@dynamic F' is equivalent to '@dynamic { return F(value); }'
// the parser has already added the function parameter 'value',
// the rest of the statement block is constructed here
this.reference = reference;
statementBlock = new StatementBlock();
statementBlock.setDynamicTemplate(this);
statementBlock.addStatement(new Return_Statement(new Referenced_Template(reference)));
if (reference != null) {
reference.setFullNameParent(this);