#!/usr/bin/python
# -*- coding: utf-8 -*-
# vim: ts=4:sw=4:et:

''' Class for a Table of Defines.
Each identifier has a dictionary entry.
'''
import sys
import re

from id_ import ID
from exceptions import PreprocError
from output import warning
from output import CURRENT_FILE

RE_ID = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*')


class DefinesTable(object):
    ''' A class which will store
    define labels, and its values.
    It will also susbtitute the current value
    of a label for the given value.
    '''
    def __init__(self):
        ''' Initializes table
        '''
        self.table = {}

    def define(self, id_, lineno, value='', fname=None, args=None):
        ''' Defines the value of a macro.
        Issues a warning if the macro is already defined.
        '''
        if fname is None:
            if CURRENT_FILE:
                fname = CURRENT_FILE[-1]
            else:  # If no files opened yet, use owns program fname
                fname = sys.argv[0]

        if self.defined(id_):
            i = self.table[id_]
            warning(lineno, '"%s" redefined (previous definition at %s:%i)' %
                    (i.name, i.fname, i.lineno))
        self.set(id_, lineno, value, fname, args)

    def set(self, id_, lineno, value='', fname=None, args=None):
        ''' Like the above, but issues no warning on duplicate macro
            definitions.
        '''
        if fname is None:
            if CURRENT_FILE:
                fname = CURRENT_FILE[-1]
            else:  # If no files opened yet, use owns program fname
                fname = sys.argv[0]
        self.table[id_] = ID(id_, args, value, lineno, fname)

    def undef(self, id_):
        if self.defined(id_):
            del self.table[id_]

    def defined(self, id_):
        ''' Returns if the given ID
        is defined
        '''
        return id_.strip() in self.table.keys()

    def __getitem__(self, key):
        ''' Returns the ID instance given it's
        _id. If it does not exist, return the _id
        itself.
        '''
        return self.table.get(key.strip(), key)

    def __setitem__(self, key, value):
        ''' Assigns the value to the given table entry
        '''
        k = key.strip()
        if not RE_ID.match(k):
            raise PreprocError('"%s" must be an identifier' % key, None)
        self.table[key] = value
