Index: compile_rules.py
==================================================================
--- compile_rules.py
+++ compile_rules.py
@@ -5,19 +5,19 @@
 import copy
 import json
 from distutils import file_util
 
 
-DEF = {}
-FUNCTIONS = []
-
-RULESET = set()     # set of rule-ids to check if there is several rules with the same id
-
-JSREGEXES = {}
-
-WORDLIMITLEFT  = r"(?<![\w.,–-])"   # r"(?<![-.,—])\b"  seems slower
-WORDLIMITRIGHT = r"(?![\w–-])"      # r"\b(?!-—)"       seems slower
+dDEF = {}
+lFUNCTIONS = []
+
+aRULESET = set()     # set of rule-ids to check if there is several rules with the same id
+
+dJSREGEXES = {}
+
+sWORDLIMITLEFT  = r"(?<![\w.,–-])"   # r"(?<![-.,—])\b"  seems slower
+sWORDLIMITRIGHT = r"(?![\w–-])"      # r"\b(?!-—)"       seems slower
 
 
 def prepareFunction (s):
     s = s.replace("__also__", "bCondMemo")
     s = s.replace("__else__", "not bCondMemo")
@@ -162,11 +162,11 @@
     return 0
 
 
 def createRule (s, nIdLine, sLang, bParagraph, dOptPriority):
     "returns rule as list [option name, regex, bCaseInsensitive, identifier, list of actions]"
-    global JSREGEXES
+    global dJSREGEXES
 
     #### OPTIONS
     sLineId = str(nIdLine) + ("p" if bParagraph else "s")
     sRuleId = sLineId
     sOption = False         # False or [a-z0-9]+ name
@@ -181,14 +181,14 @@
         cCaseMode = m.group('borders_and_case')[1]
         cWordLimitRight = m.group('borders_and_case')[2]
         sOption = m.group('option')[1:]  if m.group('option')  else False
         if m.group('ruleid'):
             sRuleId =  m.group('ruleid')[1:-1]
-            if sRuleId in RULESET:
+            if sRuleId in aRULESET:
                 print("# Error. Several rules have the same id: " + sRuleId)
                 exit()
-            RULESET.add(sRuleId)
+            aRULESET.add(sRuleId)
         nPriority = dOptPriority.get(sOption, 4)
         if m.group('priority'):
             nPriority = int(m.group('priority')[1:])
         s = s[m.end(0):]
     else:
@@ -208,11 +208,11 @@
         tGroups = groupsPositioningCodeToList(sRegex[m.start()+2:])
         sRegex = sRegex[:m.start()].strip()
     # JS regex
     m = re.search("<js>.+</js>i?", sRegex)
     if m:
-        JSREGEXES[sLineId] = m.group(0)
+        dJSREGEXES[sLineId] = m.group(0)
         sRegex = sRegex[:m.start()].strip()
     if "<js>" in sRegex or "</js>" in sRegex:
         print("# Error: JavaScript regex not delimited at line " + sLineId)
         return None
 
@@ -219,11 +219,11 @@
     # quotes ?
     if sRegex.startswith('"') and sRegex.endswith('"'):
         sRegex = sRegex[1:-1]
 
     ## definitions
-    for sDef, sRepl in DEF.items():
+    for sDef, sRepl in dDEF.items():
         sRegex = sRegex.replace(sDef, sRepl)
 
     ## count number of groups (must be done before modifying the regex)
     nGroup = countGroupInRegex(sRegex)
     if nGroup > 0:
@@ -233,13 +233,13 @@
             if nGroup != len(tGroups):
                 print("# Error: groups positioning code irrelevant at line " + sLineId)
 
     ## word limit
     if cWordLimitLeft == '[' and not sRegex.startswith(("^", '’', "'", ",")):
-        sRegex = WORDLIMITLEFT + sRegex
+        sRegex = sWORDLIMITLEFT + sRegex
     if cWordLimitRight == ']' and not sRegex.endswith(("$", '’', "'", ",")):
-        sRegex = sRegex + WORDLIMITRIGHT
+        sRegex = sRegex + sWORDLIMITRIGHT
 
     ## casing mode
     if cCaseMode == "i":
         bCaseInsensitive = True
         if not sRegex.startswith("(?i)"):
@@ -280,11 +280,11 @@
     return [sOption, sRegex, bCaseInsensitive, sLineId, sRuleId, nPriority, lActions, tGroups]
 
 
 def createAction (sIdAction, sAction, nGroup):
     "returns an action to perform as a tuple (condition, action type, action[, iGroup [, message, URL ]])"
-    global FUNCTIONS
+    global lFUNCTIONS
 
     m = re.search(r"([-~=>])(\d*|)>>", sAction)
     if not m:
         print("# No action at line " + sIdAction)
         return None
@@ -291,11 +291,11 @@
 
     #### CONDITION
     sCondition = sAction[:m.start()].strip()
     if sCondition:
         sCondition = prepareFunction(sCondition)
-        FUNCTIONS.append(("c_"+sIdAction, sCondition))
+        lFUNCTIONS.append(("c_"+sIdAction, sCondition))
         for x in re.finditer("[.](?:group|start|end)[(](\d+)[)]", sCondition):
             if int(x.group(1)) > nGroup:
                 print("# Error in groups in condition at line " + sIdAction + " ("+str(nGroup)+" groups only)")
         if ".match" in sCondition:
             print("# Error. JS compatibility. Don't use .match() in condition, use .search()")
@@ -321,11 +321,11 @@
         if mURL:
             sURL = mURL.group(1).strip()
             sMsg = sMsg[:mURL.start(0)].strip()
         if sMsg[0:1] == "=":
             sMsg = prepareFunction(sMsg[1:])
-            FUNCTIONS.append(("m_"+sIdAction, sMsg))
+            lFUNCTIONS.append(("m_"+sIdAction, sMsg))
             for x in re.finditer("group[(](\d+)[)]", sMsg):
                 if int(x.group(1)) > nGroup:
                     print("# Error in groups in message at line " + sIdAction + " ("+str(nGroup)+" groups only)")
             sMsg = "=m_"+sIdAction
         else:
@@ -353,11 +353,11 @@
     if cAction == "-":
         ## error detected --> suggestion
         if not sAction:
             print("# Error in action at line " + sIdAction + ":  This action is empty.")
         if sAction[0:1] == "=":
-            FUNCTIONS.append(("s_"+sIdAction, sAction[1:]))
+            lFUNCTIONS.append(("s_"+sIdAction, sAction[1:]))
             sAction = "=s_"+sIdAction
         elif sAction.startswith('"') and sAction.endswith('"'):
             sAction = sAction[1:-1]
         if not sMsg:
             print("# Error in action at line " + sIdAction + ":  the message is empty.")
@@ -365,11 +365,11 @@
     elif cAction == "~":
         ## text processor
         if not sAction:
             print("# Error in action at line " + sIdAction + ":  This action is empty.")
         if sAction[0:1] == "=":
-            FUNCTIONS.append(("p_"+sIdAction, sAction[1:]))
+            lFUNCTIONS.append(("p_"+sIdAction, sAction[1:]))
             sAction = "=p_"+sIdAction
         elif sAction.startswith('"') and sAction.endswith('"'):
             sAction = sAction[1:-1]
         return [sCondition, cAction, sAction, iGroup]
     elif cAction == "=":
@@ -376,11 +376,11 @@
         ## disambiguator
         if sAction[0:1] == "=":
             sAction = sAction[1:]
         if not sAction:
             print("# Error in action at line " + sIdAction + ":  This action is empty.")
-        FUNCTIONS.append(("d_"+sIdAction, sAction))
+        lFUNCTIONS.append(("d_"+sIdAction, sAction))
         sAction = "d_"+sIdAction
         return [sCondition, cAction, sAction]
     elif cAction == ">":
         ## no action, break loop if condition is False
         return [sCondition, cAction, ""]
@@ -404,12 +404,12 @@
     bCaseInsensitive = False
     if "(?i)" in sRegex:
         sRegex = sRegex.replace("(?i)", "")
         bCaseInsensitive = True
     lNegLookBeforeRegex = []
-    if WORDLIMITLEFT in sRegex:
-        sRegex = sRegex.replace(WORDLIMITLEFT, "")
+    if sWORDLIMITLEFT in sRegex:
+        sRegex = sRegex.replace(sWORDLIMITLEFT, "")
         lNegLookBeforeRegex = ["[a-zA-Zà-öÀ-Ö0-9_ø-ÿØ-ßĀ-ʯ.,–-]$"]
     sRegex = sRegex.replace("[\\w", "[a-zA-Zà-öÀ-Ö0-9_ø-ÿØ-ßĀ-ʯ")
     sRegex = sRegex.replace("\\w", "[a-zA-Zà-öÀ-Ö0-9_ø-ÿØ-ßĀ-ʯ]")
     sRegex = sRegex.replace("[.]", r"\.")
     if not sRegex.startswith("<js>"):
@@ -438,11 +438,11 @@
     # error messages
     for aAction in lRuleJS[6]:
         if aAction[1] == "-":
             aAction[4] = aAction[4].replace("« ", "«&nbsp;").replace(" »", "&nbsp;»")
     # js regexes
-    lRuleJS[1], lNegLookBehindRegex = regex2js( JSREGEXES.get(lRuleJS[3], lRuleJS[1]) )
+    lRuleJS[1], lNegLookBehindRegex = regex2js( dJSREGEXES.get(lRuleJS[3], lRuleJS[1]) )
     lRuleJS.append(lNegLookBehindRegex)
     return lRuleJS
 
 
 def writeRulesToJSArray (lRules):
@@ -544,11 +544,11 @@
     "compile rules, returns a dictionary of values"
     # for clarity purpose, don’t create any file here
 
     # removing comments, zeroing empty lines, creating definitions, storing tests, merging rule lines
     print("  parsing rules...")
-    global DEF
+    global dDEF
     lLine = []
     lRuleLine = []
     lTest = []
     lOpt = []
     for i, sLine in enumerate(lRules, 1):
@@ -557,11 +557,11 @@
         elif sLine.startswith("#"):
             pass
         elif sLine.startswith("DEF:"):
             m = re.match("DEF: +([a-zA-Z_][a-zA-Z_0-9]*) +(.+)$", sLine.strip())
             if m:
-                DEF["{"+m.group(1)+"}"] = m.group(2)
+                dDEF["{"+m.group(1)+"}"] = m.group(2)
             else:
                 print("Error in definition: ", end="")
                 print(sLine.strip())
         elif sLine.startswith("TEST:"):
             lTest.append("{:<8}".format(i) + "  " + sLine[5:].strip())
@@ -613,11 +613,11 @@
 
     # creating file with all functions callable by rules
     print("  creating callables...")
     sPyCallables = "# generated code, do not edit\n"
     sJSCallables = "// generated code, do not edit\nconst oEvalFunc = {\n"
-    for sFuncName, sReturn in FUNCTIONS:
+    for sFuncName, sReturn in lFUNCTIONS:
         cType = sFuncName[0:1]
         if cType == "c": # condition
             sParams = "s, sx, m, dDA, sCountry, bCondMemo"
         elif cType == "m": # message
             sParams = "s, m"