# *************************************************************
#  
#  Licensed to the Apache Software Foundation (ASF) under one
#  or more contributor license agreements.  See the NOTICE file
#  distributed with this work for additional information
#  regarding copyright ownership.  The ASF licenses this file
#  to you 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.
#  
# *************************************************************


import sys
from globals import *
import srclexer

class MacroParser(object):

    def __init__ (self, buf):
        self.buffer = buf
        self.macro = None
        self.debug = False

    def parse (self):
        """
A macro with arguments must have its open paren immediately following
its name without any whitespace.
"""
        if self.debug:
            print("-"*68)
            print("parsing '%s'"%self.buffer)

        i = 0
        bufSize = len(self.buffer)
        name, buf = '', ''
        while i < bufSize:
            c = self.buffer[i]
            if c in [' ', "\t"] and len(name) == 0:
                # This is a simple macro with no arguments.
                name = buf
                vars = []
                content = self.buffer[i:]
                self.setMacro(name, vars, content)
                return
            elif c == '(' and len(name) == 0:
                # This one has arguments.
                name = buf
                buf = self.buffer[i:]
                vars, content = self.parseArgs(buf)
                self.setMacro(name, vars, content)
                return
            else:
                buf += c
                i += 1

    def parseArgs (self, buffer):
        """Parse arguments.

The buffer is expected to be formatted like '(a, b, c)' where the first
character is the open paren.
"""
        scope = 0
        buf = ''
        vars = []
        content = ''
        bufSize = len(buffer)
        i = 0
        while i < bufSize:
            c = buffer[i]
            if c == '(':
                scope += 1
            elif c == ')':
                scope -= 1
                if len(buf) > 0:
                    vars.append(buf)
                if scope == 0:
                    break
            elif c == ',':
                if len(buf) == 0:
                    raise globals.ParseError ('')
                vars.append(buf)
                buf = ''
            elif c in " \t" and scope > 0:
                pass
            else:
                buf += c

            i += 1

        if scope > 0:
            raise globals.ParseError ('')

        return vars, buffer[i+1:]


    def setMacro (self, name, vars, content):
        if self.debug:
            print("-"*68)
            print("name: %s"%name)
            for var in vars:
                print("var: %s"%var)
            if len(vars) == 0:
                print("no vars")
            print("content: '%s'"%content)

        if len(content) > 0:
            self.macro = Macro(name)
            for i in range(0, len(vars)):
                self.macro.vars[vars[i]] = i

            # tokinize it using lexer.
            mclexer = srclexer.SrcLexer(content)
            mclexer.expandHeaders = False
            mclexer.inMacroDefine = True
            mclexer.tokenize()
            self.macro.tokens = mclexer.getTokens()
            if self.debug:
                print(self.macro.tokens)

            if not self.isValidMacro(self.macro):
                self.macro = None

        if self.debug:
            if self.macro != None:
                print("macro registered!")
            else:
                print("macro not registered")

    def isValidMacro (self, macro):

        n = len(macro.tokens)
        if n == 0:
            return False
        elif len(macro.name) > 4 and macro.name[1:4] == 'ID_':
            # We don't want to expand macros like HID_, SID_, WID_, etc.
            return False
        return True


    def getMacro (self):
        return self.macro