text: # EMACS settings: -*-	tab-width: 2; indent-tabs-mode: t; python-indent-offset: 2 -*-
  # vim: tabstop=2:shiftwidth=2:noexpandtab
  # kate: tab-width 2; replace-tabs off; indent-width 2;
  # ==============================================================================
  # Authors:            Patrick Lehmann
  #
  # Python functions:   A streaming VHDL parser
  #
  # Description:
  # ------------------------------------
  #		TODO:
  #
  # License:
  # ==============================================================================
  # Copyright 2007-2017 Patrick Lehmann - Dresden, Germany
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #   http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  # ==============================================================================
  #
  # load dependencies
  from pyVHDLParser.Token               import LinebreakToken, CommentToken, MultiLineCommentToken, IndentationToken, SingleLineCommentToken, ExtendedIdentifier, CharacterToken, SpaceToken
  from pyVHDLParser.Token.Keywords      import InKeyword, ForKeyword, LoopKeyword, BoundaryToken, IdentifierToken, StringToken
  from pyVHDLParser.Blocks              import TokenParserException, Block, CommentBlock, ParserState
  from pyVHDLParser.Blocks.Common       import LinebreakBlock, WhitespaceBlock
  from pyVHDLParser.Blocks.Generic      import SequentialBeginBlock
  from pyVHDLParser.Blocks.Generic1     import EndBlock as EndBlockBase
  from pyVHDLParser.Blocks.Expression   import ExpressionBlockEndedByKeywordORClosingRoundBracket, ExpressionBlockEndedByKeywordOrToOrDownto
  
  
  class IteratorBlock(Block):
  	@classmethod
  	def stateForKeyword(cls, parserState: ParserState):
  		token = parserState.Token
  		if isinstance(token, SpaceToken):
  			parserState.NewToken =    BoundaryToken(token)
  			parserState.NextState =   cls.stateWhitespace1
  			return
  		elif isinstance(token, (LinebreakToken, CommentToken)):
  			block =                   LinebreakBlock if isinstance(token, LinebreakToken) else CommentBlock
  			parserState.NewBlock =    cls(parserState.LastBlock, parserState.TokenMarker, endToken=token.PreviousToken, multiPart=True)
  			_ =                       block(parserState.NewBlock, token)
  			parserState.TokenMarker = None
  			parserState.NextState =   cls.stateWhitespace1
  			return
  
  		raise TokenParserException("Expected whitespace after keyword FOR.", token)
  
  	@classmethod
  	def stateWhitespace1(cls, parserState: ParserState):
  		token = parserState.Token
  		if isinstance(token, StringToken):
  			parserState.NewToken =      IdentifierToken(token)
  			parserState.NextState =     cls.stateIteratorName
  			return
  		elif isinstance(token, ExtendedIdentifier):
  			parserState.NextState =     cls.stateIteratorName
  			return
  		elif isinstance(token, LinebreakToken):
  			if (not (isinstance(parserState.LastBlock, CommentBlock) and isinstance(parserState.LastBlock.StartToken, MultiLineCommentToken))):
  				parserState.NewBlock =    cls(parserState.LastBlock, parserState.TokenMarker, endToken=token.PreviousToken, multiPart=True)
  				_ =                       LinebreakBlock(parserState.NewBlock, token)
  			else:
  				parserState.NewBlock =    LinebreakBlock(parserState.LastBlock, token)
  			parserState.TokenMarker =   None
  			return
  		elif isinstance(token, CommentToken):
  			parserState.NewBlock =      cls(parserState.LastBlock, parserState.TokenMarker, endToken=token.PreviousToken, multiPart=True)
  			_ =                         CommentBlock(parserState.NewBlock, token)
  			parserState.TokenMarker =   None
  			return
  		elif (isinstance(token, IndentationToken) and isinstance(token.PreviousToken, (LinebreakToken, SingleLineCommentToken))):
  			return
  		elif (isinstance(token, SpaceToken) and (isinstance(parserState.LastBlock, CommentBlock) and isinstance(parserState.LastBlock.StartToken, MultiLineCommentToken))):
  			parserState.NewToken =      BoundaryToken(token)
  			parserState.NewBlock =      WhitespaceBlock(parserState.LastBlock, parserState.NewToken)
  			parserState.TokenMarker =   None
  			return
  
  		raise TokenParserException("Expected iterator name (identifier).", token)
  
  	@classmethod
  	def stateIteratorName(cls, parserState: ParserState):
  		token = parserState.Token
  		if isinstance(token, SpaceToken):
  			parserState.NewToken =    BoundaryToken(token)
  			parserState.NextState =   cls.stateWhitespace2
  			return
  		elif isinstance(token, (LinebreakToken, CommentToken)):
  			block =                   LinebreakBlock if isinstance(token, LinebreakToken) else CommentBlock
  			parserState.NewBlock =    cls(parserState.LastBlock, parserState.TokenMarker, endToken=token.PreviousToken, multiPart=True)
  			_ =                       block(parserState.NewBlock, token)
  			parserState.TokenMarker = None
  			parserState.NextState =   cls.stateWhitespace2
  			return
  
  		raise TokenParserException("Expected whitespace after iterator name.", token)
  
  	@classmethod
  	def stateWhitespace2(cls, parserState: ParserState):
  		token = parserState.Token
  		if (isinstance(token, StringToken) and (token <= "in")):
  			parserState.NewToken =      InKeyword(token)
  			# parserState.NewBlock =      cls(parserState.LastBlock, parserState.TokenMarker, endToken=parserState.NewToken)
  			# parserState.TokenMarker =   None
  			parserState.NextState =     cls.stateInKeyword
  			return
  		elif isinstance(token, LinebreakToken):
  			if (not (isinstance(parserState.LastBlock, CommentBlock) and isinstance(parserState.LastBlock.StartToken, MultiLineCommentToken))):
  				parserState.NewBlock =    cls(parserState.LastBlock, parserState.TokenMarker, endToken=token.PreviousToken, multiPart=True)
  				_ =                       LinebreakBlock(parserState.NewBlock, token)
  			else:
  				parserState.NewBlock =    LinebreakBlock(parserState.LastBlock, token)
  			parserState.TokenMarker =   None
  			return
  		elif isinstance(token, CommentToken):
  			parserState.NewBlock =      cls(parserState.LastBlock, parserState.TokenMarker, endToken=token.PreviousToken, multiPart=True)
  			_ =                         CommentBlock(parserState.NewBlock, token)
  			parserState.TokenMarker =   None
  			return
  		elif (isinstance(token, IndentationToken) and isinstance(token.PreviousToken, (LinebreakToken, SingleLineCommentToken))):
  			return
  		elif (isinstance(token, SpaceToken) and (isinstance(parserState.LastBlock, CommentBlock) and isinstance(parserState.LastBlock.StartToken, MultiLineCommentToken))):
  			parserState.NewToken =      BoundaryToken(token)
  			parserState.NewBlock =      WhitespaceBlock(parserState.LastBlock, parserState.NewToken)
  			parserState.TokenMarker =   None
  			return
  
  		raise TokenParserException("Expected keyword IN after iterator name.", token)
  
  	@classmethod
  	def stateInKeyword(cls, parserState: ParserState):
  		token = parserState.Token
  		if (isinstance(token, CharacterToken) and (token == "(")):
  			parserState.NewToken =    BoundaryToken(token)
  			parserState.NewBlock =    cls(parserState.LastBlock, parserState.TokenMarker, endToken=parserState.NewToken.PreviousToken)
  			parserState.TokenMarker = parserState.NewToken
  			parserState.NextState =   LoopBlock.stateSequentialRegion
  			parserState.PushState =   ExpressionBlockEndedByLoopORToORDownto.stateExpression
  			return
  		elif isinstance(token, SpaceToken):
  			parserState.NewToken =    BoundaryToken(token)
  			parserState.NextState =   cls.stateWhitespace3
  			return
  		elif isinstance(token, (LinebreakToken, CommentToken)):
  			block =                   LinebreakBlock if isinstance(token, LinebreakToken) else CommentBlock
  			parserState.NewBlock =    cls(parserState.LastBlock, parserState.TokenMarker, endToken=token.PreviousToken, multiPart=True)
  			_ =                       block(parserState.NewBlock, token)
  			parserState.TokenMarker = None
  			parserState.NextState =   cls.stateWhitespace3
  			return
  
  		raise TokenParserException("Expected '(' or whitespace after keyword IN.", token)
  
  	@classmethod
  	def stateWhitespace3(cls, parserState: ParserState):
  		token = parserState.Token
  		if isinstance(token, LinebreakToken):
  			if (not (isinstance(parserState.LastBlock, CommentBlock) and isinstance(parserState.LastBlock.StartToken, MultiLineCommentToken))):
  				parserState.NewBlock =    cls(parserState.LastBlock, parserState.TokenMarker, endToken=token.PreviousToken, multiPart=True)
  				_ =                       LinebreakBlock(parserState.NewBlock, token)
  			else:
  				parserState.NewBlock =    LinebreakBlock(parserState.LastBlock, token)
  			parserState.TokenMarker =   None
  			return
  		elif isinstance(token, CommentToken):
  			parserState.NewBlock =      cls(parserState.LastBlock, parserState.TokenMarker, endToken=token.PreviousToken, multiPart=True)
  			_ =                         CommentBlock(parserState.NewBlock, token)
  			parserState.TokenMarker =   None
  			return
  		elif (isinstance(token, IndentationToken) and isinstance(token.PreviousToken, (LinebreakToken, SingleLineCommentToken))):
  			return
  		elif (isinstance(token, SpaceToken) and (isinstance(parserState.LastBlock, CommentBlock) and isinstance(parserState.LastBlock.StartToken, MultiLineCommentToken))):
  			parserState.NewToken =      BoundaryToken(token)
  			parserState.NewBlock =      WhitespaceBlock(parserState.LastBlock, parserState.NewToken)
  			parserState.TokenMarker =   None
  			return
  		else:
  			parserState.NewBlock =      cls(parserState.LastBlock, parserState.TokenMarker, endToken=token.PreviousToken)
  			parserState.NextState =     LoopBlock.stateLoopKeyword
  			parserState.PushState =     ExpressionBlockEndedByLoop.stateExpression
  			parserState.PushState =     ExpressionBlockEndedByLoopORToORDownto.stateExpression
  			parserState.TokenMarker =   parserState.Token
  			parserState.NextState(parserState)
  			return
  
  
  class EndBlock(EndBlockBase):
  	KEYWORD =             ForKeyword
  	KEYWORD_IS_OPTIONAL = False
  	EXPECTED_NAME =       KEYWORD.__KEYWORD__
  
  
  class LoopBlock(SequentialBeginBlock):
  	END_BLOCK = EndBlock
  
  	@classmethod
  	def stateLoopKeyword(cls, parserState: ParserState):
  		parserState.NextState = cls.stateSequentialRegion
  		parserState.NextState(parserState)
  
  
  class ExpressionBlockEndedByLoopORToORDownto(ExpressionBlockEndedByKeywordOrToOrDownto):
  	EXIT_KEYWORD =  LoopKeyword
  	EXIT_BLOCK =    LoopBlock
  
  
  class ExpressionBlockEndedByLoop(ExpressionBlockEndedByKeywordORClosingRoundBracket):
  	EXIT_KEYWORD = LoopKeyword
  	EXIT_BLOCK =   LoopBlock
  
  
  class LoopIterationDirectionBlock(Block):
  	pass
  