#!/usr/bin/env python
"""A simple EPICS macLib implementation. We support the minimum syntax needed for expanding fileNames/paths etc
"""

import os
import sys
from plex import *
import random
import StringIO

# Here's where we define the lexicon for the parser.
openMacro1 = Str('$(')  
openMacro2 = Str('${')  
closeMacro1 =  Str(')')
closeMacro2 =  Str('}')
defaultValueKickOff = Str('=')
macroKickOff = Rep1(openMacro1 | openMacro2)
macroDone = Rep1(closeMacro1 | closeMacro2)

letter = Range("AZaz")
digit = Range("09")
hspace = Any(" \t")
spchars = Any(".-_:+/*<>")
comma = Str(",")
quote = Str('"')
name = Rep1(letter | digit | spchars)
space = Any(" \t\n")

class MyScanner(Scanner):
    '''We need to override some methods to be able to print the macro is the name does not exist in the env'''
    def processMacroName(self, text):
        self.macroName = text
    def processMacroValue(self, text):
        self.macroValue = text
    def processMacroDone(self, text):
        if self.macroName in self.env:
            self.produce('expandedmacro', self.env[self.macroName])
        elif self.macroValue:
            self.produce('expandedmacro', self.macroValue)
        else:
            self.produce('expandedmacro', '${' + self.macroName + '}')
        self.macroName = None
        self.macroValue = None
        self.begin('')
    macroLexicon = Lexicon([
                            (name, 'text'),
                            (macroKickOff, Begin("Macro")),
                            State('Macro', [
                                            (name, processMacroName),
                                            (quote, IGNORE),
                                            (defaultValueKickOff, Begin('DefaultValue')),
                                            (macroDone, processMacroDone)
                                            ]),
                            State('DefaultValue', [
                                                   (name, processMacroValue),
                                                   (quote, IGNORE),
                                                   (macroDone, processMacroDone)
                                                   ]),
                            (space, IGNORE)
                            ])
    def __init__(self, file, env):
        Scanner.__init__(self, self.macroLexicon, file, None)
        self.env = env
        self.macroName = None
        self.macroValue = None



def substMacro(val, env):
    ''' Expands a macro using EPICS maclib syntax. The four forms we support are
    $(macroname)
    $(macroname=default-value)
    ${macroname}
    ${macroname=default-value}
    '''
    try:
        ret = ''    
        scanner = MyScanner(StringIO.StringIO(val), env)
        while 1:
            token = scanner.read()
            if token[0] is None:
                break
            if token[0] == 'text':
                ret = ret + token[1]
            elif token[0] == 'expandedmacro':
                    ret = ret + token[1]
            else:
                sys.stderr.write("Unknown token" + token)
        return ret
    except Exception:
        print "Exception when expanding macro ", val
        raise



if __name__ == "__main__":
     print substMacro("${TOP}", {'TOP': 'ABC123'})
     print substMacro("$(TOP)", {'TOP': 'ABC123'})
     print substMacro("${TOP=DEF546}", {'TOP': 'ABC123'})
     print substMacro("${TOP1=DEF546}", {'TOP': 'ABC123'})
     print substMacro("$(TOP=DEF546)", {'TOP': 'ABC123'})
     print substMacro("$(TOP1=DEF546)", {'TOP': 'ABC123'})
     
     print substMacro("${TOP}/123/${BOTTOM}", {'TOP': 'ABC123', 'BOTTOM' : 'DEF456'})
     print substMacro("${TOP}/123/${BOTTOM1}", {'TOP': 'ABC123', 'BOTTOM' : 'DEF456'})
     print substMacro("${TOP}/123/${BOTTOM1=GHI789}", {'TOP': 'ABC123', 'BOTTOM' : 'DEF456'})
     