"""Samples showing the parsing of common programming-language constructs

numbers
    integers
        int
        int_unsigned
        
    hexidecimal integers
        hex
        
    floats (including exponents, requring a '.' in the literal)
        float
            floats, with optional integer-only exponents
        float_floatexp
            floats, with optional integer or float exponents

    imaginary_number
        (float/int),[jJ]

    number
        hex/float/int
    number_full
        binary_number/imaginary_number/hex/float/int

    binary_number
        signed binary number
            1001001b or 1001001B bit-field format,
            optional sign
            can be used with number as (binary_number/number)

Interpreters:

    IntInterpreter
        int, int_unsigned
    HexInterpreter
        hex
    FloatInterpreter
        float
    FloatFloatExpInterpreter
        float_floatexp
    BinaryInterpreter
        binary_number
    ImaginaryInterpreter
        imaginary_number
    
"""
from simpleparse.parser import Parser
from simpleparse import common, objectgenerator
from simpleparse.common import chartypes
from simpleparse.dispatchprocessor import *

c = {}

declaration = r"""
# sample for parsing integer and float numbers
# including hexidecimal numbers in 0xFFF format
sign             := [-+]+

<l_digits>          := digits
<l_hexdigits>       := hexdigits

decimal_fraction    := '.',int_unsigned?

# float which is explicitly a float, cannot be an integer
# because it includes a decimal point
explicit_base       := sign?, ((int_unsigned, decimal_fraction) / decimal_fraction / (int_unsigned,'.'))

exponent            := int
exponent_loose      := explicit_base/int

float               := explicit_base, ([eE],exponent)?
float_floatexp      := explicit_base, ([eE],exponent_loose)?
 
hex                 := sign?, '0', [xX], hexdigits
int_unsigned        := l_digits
int                 := sign?, l_digits
binary_digits       := [01]+
binary_number       := sign?, binary_digits,('b'/'B')

imaginary_number    := (float/int), [jJ]

##number            := binary_number/hex/float/int
number              := hex/float/int
number_full         := binary_number/imaginary_number/hex/float/int
"""

_p = Parser( declaration )
for name in ["int","hex", "int_unsigned", "number", "float", "binary_number", "float_floatexp", "imaginary_number", "number_full"]:
    c[ name ] = objectgenerator.LibraryElement(
        generator = _p._generator,
        production = name,
    )

if __name__ == "__main__":
    test()

common.share( c )

def _toInt( s, base ):
    try:
        return int( s, base)
    except TypeError:
        return int( s, base)
def _toLong( s, base ):
    return int( s, base)

class IntInterpreter(DispatchProcessor):
    """Interpret an integer (or unsigned integer) string as an integer"""
    def __call__( self, info, buffer):
        (tag, left, right, children) = info
        try:
            return _toInt( buffer[left:right], 10)
        except ValueError:
            return _toLong( buffer[left:right], 10)
class HexInterpreter(DispatchProcessor):
    """Interpret a hexidecimal integer string as an integer value"""
    def __call__( self, info, buffer):
        (tag, left, right, children) = info
        try:
            return _toInt( buffer[left:right], 16)
        except ValueError:
            return _toLong( buffer[left:right], 16)
        
class FloatFloatExpInterpreter(DispatchProcessor):
    """Interpret a float string as an integer value
    Note: we're allowing float exponentiation, which
    gives you a nice way to write 2e.5
    """
    def __call__( self, info, buffer):
        (tag, left, right, children) = info
        tag, l, r, _ = children[0]
        base = float( buffer[l:r] )
        if len(children) > 1:
            # figure out the exponent...
            exp = children[1]
            exp = buffer[ exp[1]:exp[2]]
##			import pdb
##			pdb.set_trace()
            exp = float( exp )
            
            base = base * (10** exp)
        return base
class FloatInterpreter(DispatchProcessor):
    """Interpret a standard float value as a float"""
    def __call__( self, info, buffer):
        (tag, left, right, children) = info
        return float( buffer[left:right])

import sys
if hasattr( sys,'version_info') and sys.version_info[:2] > (2,0):
    class BinaryInterpreter(DispatchProcessor):
        def __call__( self, info, buffer):
            """Interpret a bitfield set as an integer"""
            (tag, left, right, children) = info
            return _toInt( buffer[left:right-1], 2)
else:
    class BinaryInterpreter(DispatchProcessor):
        def __call__( self, info, buffer):
            """Interpret a bitfield set as an integer, not sure this algo
            is correct, will see I suppose"""
            (tag, left, right, children) = info
            sign = 1
            if len(children) > 2:
                s = children[0]
                for schar in buffer[s[1]:s[2]]:
                    if schar == '-':
                        sign = sign * -1
                bits = buffer[children[1][1]:children[1][2]]
            else:
                bits = buffer[children[0][1]:children[0][2]]
            value = 0
            for bit in bits:
                value = (value << 1)
                if bit == '1':
                    value = value + 1
            return value
        
class ImaginaryInterpreter( DispatchProcessor ):
    map = {
        "float":FloatInterpreter(),
        "int":IntInterpreter()
    }
    def __call__( self, info, buffer):
        """Interpret a bitfield set as an integer, not sure this algo
        is correct, will see I suppose"""
        (tag, left, right, children) = info
        base = children[0]
        base = self.mapSet[base[0]](base, buffer)
        return base * 1j
    
