# simsubs.py -- A library for setting/unsetting defines and performing substitutions of said defines # @YAHOO@ # # Michael Thomas # Center for Computation & Technology # Louisiana State University # import re import sys import libutil from libutil import dprint class DefineDatabase: def __init__(self, env): self.SimEnvironment = env self.PresetMacros = self.SimEnvironment.OptionsManager.Macros self.Patterns = dict() self.Reset() def Reset(self): self.defines = dict() #load in our preset (command-line defined) macros. for key in self.PresetMacros.keys(): #dprint("loading predefined macro %s with value %s" % (key, self.PresetMacros[key])) self.Set(key, self.PresetMacros[key]) self.CompileReplacements() self.CompileAppends() def Set(self, define, value): # if we attempt to set something that's preset, just ignore it. if self.PresetMacros.has_key(define): return self.defines[define] = value def Unset(self, define): try: del self.defines[define] except KeyError: return def Has(self, define): return self.defines.has_key(define) def Get(self, define): if self.Has(define): return self.defines[define] return None def Sub(self, define, ss): if self.Has(define): macro = "@%s@" % define return self.PerformSub(ss, macro, self.defines[define]) return ss def PerformSub(self, ss, macro, value): if value is not str: value = str(value) return ss.replace(macro, value) def ParseEnvCommands(self, ss): pattern = "@ENV\((.+)\)@\s+" env = [] rx = re.compile(pattern) mm = rx.findall(ss) for m in mm: env.append(m) for m in env: f_m = "@ENV(%s)@" % m ss = self.PerformSub(ss, f_m, '') return (ss, env) def PerformRegexSubstitutions(self, ss): slist = self.SimEnvironment.OptionsManager.Substitutions if self.SimEnvironment.ConfigurationDatabase.HasConfigOption("substitutions"): slist2 = self.SimEnvironment.ConfigurationDatabase.GetConfigOption("substitutions") slist.extend(slist2) if len(slist) == 0: return ss for rx_pair in slist: rx_pair[1] = rx_pair[1].replace("@1@", r"\1") rx = rx.compile(rx_pair[0], re.MULTILINE) ss = rx.replace(rx_pair[1], ss) return ss # Add additional define # @VAR@ = VALUE def AddDefine(self, var, value): if var != var.strip(): dprint("Error: illegal variable name '%s'" % var) sys.exit(1) pattern = r"@%s@" % var if pattern in self.Patterns: dprint("Error: pattern '%s' exists already" % pattern) sys.exit(1) self.Patterns[pattern] = value # Add additional substitution # PATTERN = VALUE def AddSubstitution (self, var, value): pattern = var if pattern in self.Patterns: dprint("Error: pattern '%s' exists already" % pattern) sys.exit(1) dprint("Adding substitution '%s' = '%s'" % (pattern, value)) self.Patterns[pattern] = value.replace("@1@", r"\1") # Add additional replacement # KEY = NEWVALUE def AddReplacement(self, var, value): if var != var.strip(): dprint("Error: illegal variable name '%s'" % var) sys.exit(1) pattern = r"^\s*%s\s*=.*$" % var if pattern in self.Patterns: dprint("Error: pattern '%s' exists already" % pattern) sys.exit(1) self.Patterns[pattern] = "=SIMFACTORY-PROTECTED=%s = %s" % (var, value) # Add additional append # KEY = OLDVALUE NEWVALUE def AddAppend(self, var, value): if var != var.strip(): dprint("Error: illegal variable name '%s'" % var) sys.exit(1) pattern = r'^\s*%s\s*=\s*(.*?)\s*$' % var if pattern in self.Patterns: dprint("Error: pattern '%s' exists already" % pattern) sys.exit(1) self.Patterns[pattern] = r"=SIMFACTORY-PROTECTED=%s = \1 %s" % (var, value) #def CompileDefines #def CompleSubstitutions def CompileReplacements(self): rlist = self.SimEnvironment.OptionsManager.Replacements if self.SimEnvironment.ConfigurationDatabase.HasConfigOption("replacements"): rlist2 = self.SimEnvironment.ConfigurationDatabase.GetConfigOption("replacements") rlist.extend(rlist2) for r in rlist: (var, value) = r.split('=') self.AddReplacement(var, value) def CompileAppends(self): rlist = self.SimEnvironment.OptionsManager.Appends if self.SimEnvironment.ConfigurationDatabase.HasConfigOption("appends"): rlist2 = self.SimEnvironment.ConfigurationDatabase.GetConfigOption("appends") rlist.extend(rlist2) for r in rlist: (var, value) = r.split('=') self.AddAppend(var, value) def SubAll(self, ss): while True: oldss = ss for macro in self.defines.keys(): f_m = "@%s@" % macro ss = self.PerformSub(ss, f_m, self.Get(macro)) pattern = "@\(([^@]+)\)@" rx = re.compile(pattern) mm = rx.findall(ss) for m in mm: locals = dict() locals['ifthen'] = self.ifthen #translate ? into ifthen if m.count("?") >= 1: if m.count("?") > 2: dprint("Error: cannot evaluate complex ternary operation \"%s\", only one ? allowed." % m) sys.exit(1) m_new = self.TransformTernary(m) else: m_new = m output = eval(m_new, locals) f_m = "@(%s)@" % m ss = self.PerformSub(ss, f_m, output) ss = self.PerformRegexSubstitutions(ss) ss = self.PerformPatternSubstitutions(ss) if ss == oldss: ss = ss.replace("=SIMFACTORY-PROTECTED=", "") return ss def PerformPatternSubstitutions(self, m): for pattern in self.Patterns.keys(): #dprint("have replacement pattern: %s, replacement: %s" % (pattern, self.Patterns[pattern])) rx = re.compile(pattern, re.MULTILINE) m = rx.sub(self.Patterns[pattern], m) return m def TransformTernary(self, m): # statement ? value : value #dprint("ternary statement: %s" % m) sp = m.split("?") statement = sp[0].strip() replacements = dict() replacements['ne'] = "!=" replacements['eq'] = "==" replacements['gt'] = ">" replacements['lt'] = "<" replacements['gte'] = ">=" replacements['lte'] = "<=" for key in replacements.keys(): statement = statement.replace(key, replacements[key]) # now, we need to go character by character here to find the first : not in quotes. count = 1 quoteChar = None inQuotes = False for c in sp[1]: if c in ["'", '"']: if inQuotes != False: if quoteChar == c: inQuotes = False quoteChar = None else: quoteChar = c inQuotes = True if c == ":" and inQuotes == False: splitPos = count break count = count + 1 true = sp[1][1:splitPos-1].strip() false = sp[1][splitPos:].strip() cmd = "ifthen(\"%s\", %s, %s)" % (statement, true, false) #dprint("translated ternary to: %s" % cmd) return cmd def ifthen(self, expr, tval, fval): try: if eval(expr): return tval else: return fval except: return fval