/*************************************************************************** * Copyright (C) 2011 by Fabrizio Montesi <famontesi@gmail.com> * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * For details about the authors of this software, see the AUTHORS file. * ***************************************************************************/ package jolie.lang.parse; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import jolie.lang.Constants; import jolie.lang.Constants.ExecutionMode; import jolie.lang.parse.ast.AddAssignStatement; import jolie.lang.parse.ast.expression.AndConditionNode; import jolie.lang.parse.ast.AssignStatement; import jolie.lang.parse.ast.CompareConditionNode; import jolie.lang.parse.ast.CompensateStatement; import jolie.lang.parse.ast.expression.ConstantIntegerExpression; import jolie.lang.parse.ast.expression.ConstantDoubleExpression; import jolie.lang.parse.ast.expression.ConstantStringExpression; import jolie.lang.parse.ast.CorrelationSetInfo; import jolie.lang.parse.ast.CorrelationSetInfo.CorrelationVariableInfo; import jolie.lang.parse.ast.CurrentHandlerStatement; import jolie.lang.parse.ast.DeepCopyStatement; import jolie.lang.parse.ast.DefinitionCallStatement; import jolie.lang.parse.ast.DefinitionNode; import jolie.lang.parse.ast.DivideAssignStatement; import jolie.lang.parse.ast.DocumentationComment; import jolie.lang.parse.ast.EmbeddedServiceNode; import jolie.lang.parse.ast.ExecutionInfo; import jolie.lang.parse.ast.ExitStatement; import jolie.lang.parse.ast.ForEachStatement; import jolie.lang.parse.ast.ForStatement; import jolie.lang.parse.ast.expression.FreshValueExpressionNode; import jolie.lang.parse.ast.IfStatement; import jolie.lang.parse.ast.InputPortInfo; import jolie.lang.parse.ast.InstallFixedVariableExpressionNode; import jolie.lang.parse.ast.InstallStatement; import jolie.lang.parse.ast.InterfaceDefinition; import jolie.lang.parse.ast.InterfaceExtenderDefinition; import jolie.lang.parse.ast.expression.IsTypeExpressionNode; import jolie.lang.parse.ast.LinkInStatement; import jolie.lang.parse.ast.LinkOutStatement; import jolie.lang.parse.ast.MultiplyAssignStatement; import jolie.lang.parse.ast.NDChoiceStatement; import jolie.lang.parse.ast.expression.NotExpressionNode; import jolie.lang.parse.ast.NotificationOperationStatement; import jolie.lang.parse.ast.NullProcessStatement; import jolie.lang.parse.ast.OLSyntaxNode; import jolie.lang.parse.ast.OneWayOperationDeclaration; import jolie.lang.parse.ast.OneWayOperationStatement; import jolie.lang.parse.ast.expression.OrConditionNode; import jolie.lang.parse.ast.OutputPortInfo; import jolie.lang.parse.ast.ParallelStatement; import jolie.lang.parse.ast.PointerStatement; import jolie.lang.parse.ast.PostDecrementStatement; import jolie.lang.parse.ast.PostIncrementStatement; import jolie.lang.parse.ast.PreDecrementStatement; import jolie.lang.parse.ast.PreIncrementStatement; import jolie.lang.parse.ast.expression.ProductExpressionNode; import jolie.lang.parse.ast.Program; import jolie.lang.parse.ast.RequestResponseOperationDeclaration; import jolie.lang.parse.ast.RequestResponseOperationStatement; import jolie.lang.parse.ast.RunStatement; import jolie.lang.parse.ast.Scope; import jolie.lang.parse.ast.SequenceStatement; import jolie.lang.parse.ast.SolicitResponseOperationStatement; import jolie.lang.parse.ast.SpawnStatement; import jolie.lang.parse.ast.SubtractAssignStatement; import jolie.lang.parse.ast.expression.SumExpressionNode; import jolie.lang.parse.ast.SynchronizedStatement; import jolie.lang.parse.ast.ThrowStatement; import jolie.lang.parse.ast.TypeCastExpressionNode; import jolie.lang.parse.ast.UndefStatement; import jolie.lang.parse.ast.ValueVectorSizeExpressionNode; import jolie.lang.parse.ast.expression.VariableExpressionNode; import jolie.lang.parse.ast.VariablePathNode; import jolie.lang.parse.ast.WhileStatement; import jolie.lang.parse.ast.courier.CourierChoiceStatement; import jolie.lang.parse.ast.courier.CourierDefinitionNode; import jolie.lang.parse.ast.courier.NotificationForwardStatement; import jolie.lang.parse.ast.courier.SolicitResponseForwardStatement; import jolie.lang.parse.ast.expression.ConstantBoolExpression; import jolie.lang.parse.ast.expression.ConstantByteExpression; import jolie.lang.parse.ast.expression.ConstantInteger16Expression; import jolie.lang.parse.ast.expression.ConstantLongExpression; import jolie.lang.parse.ast.expression.ConstantUInteger16Expression; import jolie.lang.parse.ast.expression.ConstantUInteger32Expression; import jolie.lang.parse.ast.expression.ConstantUInteger64Expression; import jolie.lang.parse.ast.expression.InstanceOfExpressionNode; import jolie.lang.parse.ast.types.TypeDefinitionLink; import jolie.lang.parse.ast.types.TypeInlineDefinition; import jolie.lang.parse.context.ParsingContext; import jolie.util.Pair; /** * * @author Fabrizio Montesi */ public class TypeChecker implements OLVisitor { private class FlaggedVariablePathNode extends VariablePathNode { private final boolean isFresh; public FlaggedVariablePathNode( VariablePathNode path, boolean isFresh ) { super( path.context(), path.type() ); this.path().addAll( path.path() ); this.isFresh = isFresh; } public boolean isFresh() { return isFresh; } } private class TypingResult { private final VariablePathSet< VariablePathNode > neededCorrPaths; private final VariablePathSet< FlaggedVariablePathNode > providedCorrPaths; private final VariablePathSet< VariablePathNode > neededVarPaths; private final VariablePathSet< VariablePathNode > providedVarPaths; private final Set< String > sessionOperations; private String startingOperation = null; private final VariablePathSet< VariablePathNode > invalidatedVarPaths; public TypingResult() { neededCorrPaths = new VariablePathSet(); providedCorrPaths = new VariablePathSet(); neededVarPaths = new VariablePathSet(); providedVarPaths = new VariablePathSet(); invalidatedVarPaths = new VariablePathSet(); sessionOperations = new HashSet< String >(); } public void registerOperationInput( String operation, boolean isStartingOperation ) { if ( isStartingOperation ) { startingOperation = operation; } else { sessionOperations.add( operation ); } } public void registerOperations( TypingResult other ) { if ( this.startingOperation == null ) { this.startingOperation = other.startingOperation; } sessionOperations.addAll( other.sessionOperations ); } public void provide( VariablePathNode path, boolean isFresh ) { if ( path.isCSet() ) { providedCorrPaths.add( new FlaggedVariablePathNode( path, isFresh ) ); } else { providedVarPaths.add( path ); } } public void provide( FlaggedVariablePathNode path ) { if ( path.isCSet() ) { providedCorrPaths.add( path ); } else { providedVarPaths.add( path ); } } public void provide( VariablePathNode path ) { if ( path instanceof FlaggedVariablePathNode ) { provide( (FlaggedVariablePathNode) path ); } else { provide( path, false ); } } public void need( VariablePathNode path ) { if ( path.isCSet() ) { neededCorrPaths.add( path ); } else { neededVarPaths.add( path ); } } public void needAll( TypingResult other ) { for( VariablePathNode path : other.neededCorrPaths ) { need( path ); } for( VariablePathNode path : other.neededVarPaths ) { need( path ); } } public void provideAll( TypingResult other ) { for( VariablePathNode path : other.providedCorrPaths ) { provide( path ); } for( VariablePathNode path : other.providedVarPaths ) { provide( path ); } } public void provideAll( VariablePathSet< ? extends VariablePathNode > other ) { for( VariablePathNode path : other ) { provide( path ); } } public void needAll( VariablePathSet< ? extends VariablePathNode > other ) { for( VariablePathNode path : other ) { need( path ); } } public void invalidateAll( TypingResult other ) { for( VariablePathNode path : other.invalidatedVarPaths ) { invalidate( path ); } } public void invalidate( VariablePathNode path ) { invalidatedVarPaths.add( path ); providedVarPaths.remove( path ); } public void removeUnsharedProvided( TypingResult other ) { List< VariablePathNode > toBeRemoved = new LinkedList< VariablePathNode >(); for( VariablePathNode path : providedVarPaths ) { if ( !other.providedVarPaths.contains( path ) ) { toBeRemoved.add( path ); } } for( VariablePathNode path : toBeRemoved ) { providedVarPaths.remove( path ); } } } private final Program program; private boolean insideInit = false; private final CorrelationFunctionInfo correlationFunctionInfo; private final ExecutionMode executionMode; private TypingResult typingResult; private TypingResult entryTyping; private static final Logger logger = Logger.getLogger( "JOLIE" ); private boolean valid = true; private final Map< String, TypingResult > definitionTyping = new HashMap< String, TypingResult >(); private boolean sessionStarter = false; public TypeChecker( Program program, ExecutionMode executionMode, CorrelationFunctionInfo correlationFunctionInfo ) { this.program = program; this.executionMode = executionMode; this.correlationFunctionInfo = correlationFunctionInfo; } private void error( OLSyntaxNode node, String message ) { valid = false; if ( node != null ) { ParsingContext context = node.context(); logger.severe( context.sourceName() + ":" + context.line() + ": " + message ); } else { logger.severe( message ); } } private boolean isDefinedBefore( VariablePathNode path ) { if ( entryTyping.providedVarPaths.contains( path ) || entryTyping.providedCorrPaths.contains( path ) ) { return true; } return false; } public boolean check() { check( program, new TypingResult() ); typingResult = definitionTyping.get( "main" ); if ( typingResult == null ) { error( program, "Can not find the main entry point" ); } else { checkMainTyping(); } return valid; } private void checkMainTyping() { TypingResult initTyping = definitionTyping.get( "init" ); if ( initTyping != null ) { addInitTypingToMain(); } for( VariablePathNode path : typingResult.neededCorrPaths ) { error( path, "Correlation path " + path.toPrettyString() + " is not initialised before usage." ); } for( VariablePathNode path : typingResult.neededVarPaths ) { error( path, "Variable " + path.toPrettyString() + " is not initialised before using it to initialise a correlation variable." ); } VariablePathNode path; boolean isCorrelationSetFresh; for( CorrelationSetInfo cset : correlationFunctionInfo.correlationSets() ) { isCorrelationSetFresh = false; for( CorrelationVariableInfo cvar : cset.variables() ) { path = new VariablePathNode( cvar.correlationVariablePath().context(), VariablePathNode.Type.CSET ); path.path().add( new Pair< OLSyntaxNode, OLSyntaxNode >( new ConstantStringExpression( cset.context(), Constants.CSETS ), new ConstantIntegerExpression( cset.context(), 0 ) ) ); path.path().addAll( cvar.correlationVariablePath().path() ); FlaggedVariablePathNode flaggedPath = typingResult.providedCorrPaths.getContained( path ); if ( flaggedPath == null ) { // The two cases could be merged in a single if-then-else condition, but they are logically different. isCorrelationSetFresh = true; // We can set this because the correlation set is not used at all. break; } else if ( flaggedPath.isFresh() ) { isCorrelationSetFresh = true; break; } } if ( !isCorrelationSetFresh ) { error( cset, "Every correlation set must have at least one fresh value (maybe you are not using new?)." ); } } } private void addInitTypingToMain() { TypingResult right = typingResult; typingResult = definitionTyping.get( "init" ); for( VariablePathNode path : right.providedCorrPaths ) { if ( typingResult.providedCorrPaths.contains( path ) ) { error( path, "Correlation variables can not be defined more than one time." ); } else { typingResult.provide( path ); } } for( VariablePathNode path : right.providedVarPaths ) { typingResult.provide( path ); typingResult.invalidatedVarPaths.remove( path ); } for( VariablePathNode path : right.neededVarPaths ) { if ( !typingResult.providedVarPaths.contains( path ) ) { typingResult.need( path ); } } for( VariablePathNode path : right.neededCorrPaths ) { if ( !typingResult.providedCorrPaths.contains( path ) ) { typingResult.need( path ); } } typingResult.invalidateAll( right ); } private TypingResult check( OLSyntaxNode n, TypingResult entryTyping ) { this.entryTyping = entryTyping; TypingResult backup = typingResult; typingResult = new TypingResult(); n.accept( this ); TypingResult ret = typingResult; typingResult = backup; return ret; } public void visit( Program n ) { for( OLSyntaxNode node : n.children() ) { check( node, new TypingResult() ); } } public void visit( OneWayOperationDeclaration decl ) {} public void visit( RequestResponseOperationDeclaration decl ) {} public void visit( DefinitionNode n ) { insideInit = false; TypingResult entry = null; if ( n.id().equals( "main" ) ) { sessionStarter = true; entry = definitionTyping.get( "init" ); } else if ( n.id().equals( "init" ) ) { insideInit = true; } if ( entry == null ) { entry = new TypingResult(); } definitionTyping.put( n.id(), check( n.body(), entry ) ); if ( n.id().equals( "init" ) ) { for( VariablePathNode path : typingResult.providedCorrPaths ) { error( path, "Correlation variables can not be initialised in the init procedure." ); } } } public void visit( ParallelStatement n ) { if ( n.children().isEmpty() ) { return; } TypingResult entry = entryTyping; typingResult = check( n.children().get( 0 ), entry ); TypingResult right; for( int i = 1; i < n.children().size(); i++ ) { right = check( n.children().get( i ), entry ); for( VariablePathNode path : right.providedCorrPaths ) { if ( typingResult.providedCorrPaths.contains( path ) ) { error( path, "Correlation variables can not be defined more than one time." ); } else { typingResult.provide( path ); } } typingResult.provideAll( right.providedVarPaths ); typingResult.needAll( right ); typingResult.invalidateAll( right ); typingResult.registerOperations( right ); } } public void visit( SequenceStatement n ) { if ( n.children().isEmpty() ) { return; } typingResult.provideAll( entryTyping ); typingResult = check( n.children().get( 0 ), typingResult ); TypingResult right; for( int i = 1; i < n.children().size(); i++ ) { right = check( n.children().get( i ), typingResult ); for( VariablePathNode path : right.providedCorrPaths ) { if ( typingResult.providedCorrPaths.contains( path ) ) { error( path, "Correlation variables can not be defined more than one time." ); } else { typingResult.provide( path ); } } for( VariablePathNode path : right.providedVarPaths ) { typingResult.provide( path ); typingResult.invalidatedVarPaths.remove( path ); } for( VariablePathNode path : right.neededVarPaths ) { if ( !typingResult.providedVarPaths.contains( path ) ) { typingResult.need( path ); } } for( VariablePathNode path : right.neededCorrPaths ) { if ( !typingResult.providedCorrPaths.contains( path ) ) { typingResult.need( path ); } } typingResult.invalidateAll( right ); typingResult.registerOperations( right ); } } public void visit( NDChoiceStatement n ) { if ( n.children().isEmpty() ) { return; } List< TypingResult > branchTypings = new LinkedList< TypingResult >(); boolean origSessionStarter = sessionStarter; TypingResult entry = entryTyping; SequenceStatement seq; seq = new SequenceStatement( n.context() ); seq.addChild( n.children().get( 0 ).key() ); seq.addChild( n.children().get( 0 ).value() ); typingResult = check( seq, entry ); branchTypings.add( typingResult ); TypingResult right; for( int i = 1; i < n.children().size(); i++ ) { sessionStarter = origSessionStarter; seq = new SequenceStatement( n.context() ); seq.addChild( n.children().get( i ).key() ); seq.addChild( n.children().get( i ).value() ); right = check( seq, entry ); branchTypings.add( right ); typingResult.needAll( right ); typingResult.invalidateAll( right ); if ( !origSessionStarter ) { for( VariablePathNode path : typingResult.providedCorrPaths ) { if ( !right.providedCorrPaths.contains( path ) ) { error( path, "Correlation variables must be initialized in every branch." ); } } for( VariablePathNode path : right.providedCorrPaths ) { if ( !typingResult.providedCorrPaths.contains( path ) ) { error( path, "Correlation variables must be initialized in every branch." ); } } typingResult.registerOperations( right ); } typingResult.removeUnsharedProvided( right ); sessionStarter = false; } if ( origSessionStarter ) { for( TypingResult top : branchTypings ) { for( TypingResult branch : branchTypings ) { if ( top != branch && branch.sessionOperations.contains( top.startingOperation ) ) { error( program, "Operation " + top.startingOperation + " can not be used both as a starter and in the body of another session branch." ); } } } } sessionStarter = false; } public void visit( OneWayOperationStatement n ) { if ( executionMode == ExecutionMode.SINGLE ) { return; } typingResult.registerOperationInput( n.id(), sessionStarter ); if ( n.inputVarPath() != null && n.inputVarPath().isCSet() ) { error( n, "Input operations can not receive on a correlation variable" ); } CorrelationSetInfo cset = correlationFunctionInfo.operationCorrelationSetMap().get( n.id() ); if ( !sessionStarter && !insideInit ) { if ( cset == null || cset.variables().isEmpty() ) { error( n, "No correlation set defined for operation " + n.id() ); } } if ( cset != null ) { for( CorrelationSetInfo.CorrelationVariableInfo cvar : cset.variables() ) { VariablePathNode path = new VariablePathNode( cset.context(), VariablePathNode.Type.CSET ); path.path().add( new Pair< OLSyntaxNode, OLSyntaxNode >( new ConstantStringExpression( cset.context(), Constants.CSETS ), new ConstantIntegerExpression( cset.context(), 0 ) ) ); path.path().addAll( cvar.correlationVariablePath().path() ); if ( sessionStarter ) { typingResult.provide( path, true ); } else { typingResult.need( path ); } } } sessionStarter = false; } public void visit( RequestResponseOperationStatement n ) { if ( executionMode == ExecutionMode.SINGLE ) { return; } typingResult.registerOperationInput( n.id(), sessionStarter ); if ( n.inputVarPath() != null && n.inputVarPath().isCSet() ) { error( n, "Input operations can not receive on a correlation variable" ); } CorrelationSetInfo cset = correlationFunctionInfo.operationCorrelationSetMap().get( n.id() ); if ( !sessionStarter && !insideInit ) { if ( cset == null || cset.variables().isEmpty() ) { error( n, "No correlation set defined for operation " + n.id() ); } } if ( cset != null ) { for( CorrelationSetInfo.CorrelationVariableInfo cvar : cset.variables() ) { VariablePathNode path = new VariablePathNode( cset.context(), VariablePathNode.Type.CSET ); path.path().add( new Pair< OLSyntaxNode, OLSyntaxNode >( new ConstantStringExpression( cset.context(), Constants.CSETS ), new ConstantIntegerExpression( cset.context(), 0 ) ) ); path.path().addAll( cvar.correlationVariablePath().path() ); if ( sessionStarter ) { typingResult.provide( path, true ); } else { typingResult.need( path ); } } } sessionStarter = false; TypingResult internalProcessTyping = check( n.process(), entryTyping ); typingResult.needAll( internalProcessTyping ); typingResult.provideAll( internalProcessTyping ); typingResult.registerOperations( internalProcessTyping ); } public void visit( NotificationOperationStatement n ) {} public void visit( SolicitResponseOperationStatement n ) { if ( n.inputVarPath() != null && n.inputVarPath().isCSet() ) { error( n, "Solicit-response statements can not receive on a correlation variable" ); } } public void visit( FreshValueExpressionNode n ) {} public void visit( LinkInStatement n ) {} public void visit( LinkOutStatement n ) {} public void visit( AssignStatement n ) { if ( n.variablePath().isStatic() ) { if ( n.expression() instanceof ConstantIntegerExpression ) { typingResult.provide( n.variablePath() ); } else if ( n.expression() instanceof ConstantDoubleExpression ) { typingResult.provide( n.variablePath() ); } else if ( n.expression() instanceof ConstantBoolExpression ) { typingResult.provide( n.variablePath() ); } else if ( n.expression() instanceof ConstantLongExpression ) { typingResult.provide( n.variablePath() ); } else if ( n.expression() instanceof ConstantStringExpression ) { typingResult.provide( n.variablePath() ); } else if ( n.expression() instanceof PostDecrementStatement ) { typingResult.provide( n.variablePath() ); } else if ( n.expression() instanceof PostIncrementStatement ) { typingResult.provide( n.variablePath() ); } else if ( n.expression() instanceof PreDecrementStatement ) { typingResult.provide( n.variablePath() ); } else if ( n.expression() instanceof PreIncrementStatement ) { typingResult.provide( n.variablePath() ); } else if ( n.expression() instanceof VariableExpressionNode ) { VariablePathNode rightPath = ((VariableExpressionNode)n.expression()).variablePath(); if ( rightPath.isStatic() && isDefinedBefore( rightPath ) ) { typingResult.provide( n.variablePath() ); } else if ( n.variablePath().isCSet() ) { error( n, "Variable " + rightPath.toPrettyString() + " may be undefined before being used for defining correlation variable " + n.variablePath().toPrettyString() ); } } else if ( n.expression() instanceof FreshValueExpressionNode ) { typingResult.provide( n.variablePath(), true ); } else if ( n.variablePath().isCSet() ) { error( n, "Correlation variables must either be initialised with createSecureToken@SecurityUtils, a variable or a constant." ); } } } public void visit( AddAssignStatement n ) {} public void visit( SubtractAssignStatement n ) {} public void visit( MultiplyAssignStatement n ) {} public void visit( DivideAssignStatement n ) {} public void visit( IfStatement n ) { if ( n.children().isEmpty() ) { return; } TypingResult entry = entryTyping; typingResult = check( n.children().get( 0 ).value(), entry ); TypingResult right; for( int i = 1; i < n.children().size(); i++ ) { right = check( n.children().get( i ).value(), entry ); typingResult.needAll( right ); typingResult.registerOperations( right ); typingResult.invalidateAll( right ); for( VariablePathNode path : typingResult.providedCorrPaths ) { if ( !right.providedCorrPaths.contains( path ) ) { error( path, "Correlation variables must be initialized in every if-then-else branch." ); } } for( VariablePathNode path : right.providedCorrPaths ) { if ( !typingResult.providedCorrPaths.contains( path ) ) { error( path, "Correlation variables must be initialized in every if-then-else branch." ); } } typingResult.removeUnsharedProvided( right ); } if ( n.elseProcess() != null ) { right = check( n.elseProcess(), entry ); typingResult.needAll( right ); typingResult.registerOperations( right ); typingResult.invalidateAll( right ); for( VariablePathNode path : typingResult.providedCorrPaths ) { if ( !right.providedCorrPaths.contains( path ) ) { error( path, "Correlation variables must be initialized in every if-then-else branch." ); } } for( VariablePathNode path : right.providedCorrPaths ) { if ( !typingResult.providedCorrPaths.contains( path ) ) { error( path, "Correlation variables must be initialized in every if-then-else branch." ); } } typingResult.removeUnsharedProvided( right ); } } public void visit( InstanceOfExpressionNode n ) {} public void visit( DefinitionCallStatement n ) { typingResult = definitionTyping.get( n.id() ); if ( typingResult == null ) { typingResult = new TypingResult(); error( n, "Can not find definition " + n.id() ); } } public void visit( WhileStatement n ) { typingResult = check( n.body(), entryTyping ); if ( !typingResult.providedCorrPaths.isEmpty() ) { error( n, "Initialising correlation variables in while loops is forbidden." ); } typingResult.providedVarPaths.clear(); } public void visit( OrConditionNode n ) {} public void visit( AndConditionNode n ) {} public void visit( NotExpressionNode n ) {} public void visit( CompareConditionNode n ) {} public void visit( ConstantIntegerExpression n ) {} public void visit( ConstantUInteger32Expression n ) {} public void visit( ConstantUInteger16Expression n ) {} public void visit( ConstantInteger16Expression n ) {} public void visit( ConstantByteExpression n ) {} public void visit( ConstantUInteger64Expression n ) {} public void visit( ConstantLongExpression n ) {} public void visit( ConstantBoolExpression n ) {} public void visit( ConstantDoubleExpression n ) {} public void visit( ConstantStringExpression n ) {} public void visit( ProductExpressionNode n ) {} public void visit( SumExpressionNode n ) {} public void visit( VariableExpressionNode n ) {} public void visit( NullProcessStatement n ) {} public void visit( Scope n ) { typingResult = check( n.body(), entryTyping ); } public void visit( InstallStatement n ) { // TODO check code inside install } public void visit( CompensateStatement n ) {} public void visit( ThrowStatement n ) {} public void visit( ExitStatement n ) {} public void visit( ExecutionInfo n ) {} public void visit( CorrelationSetInfo n ) {} public void visit( InputPortInfo n ) {} public void visit( OutputPortInfo n ) {} public void visit( PointerStatement n ) { typingResult.invalidate( n.rightPath() ); typingResult.invalidate( n.leftPath() ); } public void visit( DeepCopyStatement n ) { typingResult.invalidate( n.rightPath() ); typingResult.invalidate( n.leftPath() ); } public void visit( RunStatement n ) {} public void visit( UndefStatement n ) { typingResult.invalidate( n.variablePath() ); } public void visit( ValueVectorSizeExpressionNode n ) {} public void visit( PreIncrementStatement n ) {} public void visit( PostIncrementStatement n ) {} public void visit( PreDecrementStatement n ) {} public void visit( PostDecrementStatement n ) {} public void visit( ForStatement n ) { typingResult = check( n.body(), entryTyping ); if ( !typingResult.providedCorrPaths.isEmpty() ) { error( n, "Initialising correlation variables in while loops is forbidden." ); } typingResult.providedVarPaths.clear(); } public void visit( ForEachStatement n ) { typingResult = check( n.body(), entryTyping ); if ( !typingResult.providedCorrPaths.isEmpty() ) { error( n, "Initialising correlation variables in while loops is forbidden." ); } typingResult.providedVarPaths.clear(); } public void visit( SpawnStatement n ) {} public void visit( IsTypeExpressionNode n ) {} public void visit( TypeCastExpressionNode n ) {} public void visit( SynchronizedStatement n ) { typingResult = check( n.body(), entryTyping ); } public void visit( CurrentHandlerStatement n ) {} public void visit( EmbeddedServiceNode n ) {} public void visit( InstallFixedVariableExpressionNode n ) {} public void visit( VariablePathNode n ) {} public void visit( TypeInlineDefinition n ) {} public void visit( TypeDefinitionLink n ) {} public void visit( InterfaceDefinition n ) {} public void visit( DocumentationComment n ) {} public void visit( InterfaceExtenderDefinition n ) {} public void visit( CourierDefinitionNode n ) {} public void visit( CourierChoiceStatement n ) {} public void visit( NotificationForwardStatement n ) {} public void visit( SolicitResponseForwardStatement n ) {} }