# -*- coding: UTF-8 -*-
#    This file is part of arena.
#   
#    arena is free software: you can redistribute it and/or modify it
#    under the terms of the GNU General Public License as published by the
#    Free Software Foundation; either version 3 of the License or, at your
#    option, any later version.
#
#    arena is distributed in the hope that it will be useful, but
#    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABLITY
#    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
#    License for more details.
#
#    You should have received a copy of the GNU General Public License along
#    with arena.  If not, see <http://www.gnu.org/licenses/>. 

## @file
#  This file defines classes that are used by a parser to tokenize a source
#  stream.

from Library.Base.Classwork import AnObject
from Library.String.Utilities import IsPrintable
from Library.Parse.Scan.Tokens import AToken
from Library.Parse.Lex.Languages import TokenType

## A scanner that tokenizes a source stream.
class AScanner(AnObject, IsPrintable):
    ## Construct a scanner that will tokenize the specified stream.
    def __init__(Self, ThisStream):
        AnObject.__init__(Self)
        
        Self._Source = ThisStream
    
    ## Initializer    
    def init(Self):
        result = AnObject.init(Self)
        
        if result:
            # Establish private attributes
            # The source stream used by the scanner
            Self._Source = None
            # The line number within the source
            Self._line = 1
            
        return result
    
    ## Peek at the next token from the source stream
    def PeekToken(Self):
        Result = None
        
        if Self._Source is not None:
            # Fetch the token
            Result = AToken.fromSource(Self._Source, None)
            
            # Put back the token
            if Result is not None:
                Result.rewind(Self._Source)
                
        return Result
    
    ## Retrieve the next token from the source stream.
    def NextToken(Self):
        Result = None
        
        if Self._Source is not None:
            Result = AToken.fromSource(Self._Source, None)
            
            if Result.code == TokenType.endOfLine:
                Self._line += 1
            
        return Result
    
    ## Move to a new position within the source stream.
    def moveTo(Self, newPosition):
        if Self._Source is not None:
            return Self._Source.moveTo(newPosition)
            
        return 0
        
    # IsPrintable implementation -----------------------------------------------
    ## Return a string representation of the scanner.
    #    
    #  This representation is the name of the stream, if available; otherwise,
    #  it is the display name of the class.
    def toString(Self):
        if Self._Source is not None:
            return Self._Source.name()
            
        return Self.displayName()
        
    # Properties ---------------------------------------------------------------
    ## Retrieve the source stream used by the scanner.
    def Source(Self):
        return Self._Source
        
    ## Retrieve the current line number within the source or set the
    #  line number within the source. 
    #    
    #  Not all implementations of AScanner will allow the line number to
    #  be set by using this method.  The base implementation of the method
    #  ignores the new line number specified and always returns the current
    #  line number.
    def line(Self, newLineNumber=0):
        return Self._line
     
    ## Retrieve the scanner's current position within the source stream.
    def position(Self):        
        if Self._Source is not None:
            return Self._Source.position()
            
        return 0
        
    ## Return an iterator that retrieves tokens from the scanner.
    #    
    #  This method is provided for convenience, so that the scanner can
    #  be used as part of a <tt>for...in</tt> loop.
    def __iter__(Self):        
        return iter(Self.NextToken, None)
