Grammalecte  Hex Artifact Content

Artifact 0ff606069cbf1540a2caa0747a3696e582b72734eb9ded8e7c7aa03a044a966b:


0000: 22 22 22 0a 47 72 61 6d 6d 61 6c 65 63 74 65 3a  """.Grammalecte:
0010: 20 63 6f 6d 70 69 6c 65 20 72 75 6c 65 73 0a 22   compile rules."
0020: 22 22 0a 0a 69 6d 70 6f 72 74 20 72 65 0a 69 6d  ""..import re.im
0030: 70 6f 72 74 20 6f 73 0a 69 6d 70 6f 72 74 20 74  port os.import t
0040: 72 61 63 65 62 61 63 6b 0a 69 6d 70 6f 72 74 20  raceback.import 
0050: 6a 73 6f 6e 0a 69 6d 70 6f 72 74 20 63 6f 6c 6f  json.import colo
0060: 72 73 79 73 0a 69 6d 70 6f 72 74 20 74 69 6d 65  rsys.import time
0070: 0a 69 6d 70 6f 72 74 20 68 61 73 68 6c 69 62 0a  .import hashlib.
0080: 0a 69 6d 70 6f 72 74 20 63 6f 6d 70 69 6c 65 5f  .import compile_
0090: 72 75 6c 65 73 5f 6a 73 5f 63 6f 6e 76 65 72 74  rules_js_convert
00a0: 20 61 73 20 6a 73 63 6f 6e 76 0a 69 6d 70 6f 72   as jsconv.impor
00b0: 74 20 63 6f 6d 70 69 6c 65 5f 72 75 6c 65 73 5f  t compile_rules_
00c0: 67 72 61 70 68 20 61 73 20 63 72 67 0a 0a 0a 64  graph as crg...d
00d0: 44 45 46 49 4e 49 54 49 4f 4e 53 20 3d 20 7b 7d  DEFINITIONS = {}
00e0: 0a 64 44 45 43 4c 45 4e 53 49 4f 4e 53 20 3d 20  .dDECLENSIONS = 
00f0: 7b 7d 0a 6c 46 55 4e 43 54 49 4f 4e 53 20 3d 20  {}.lFUNCTIONS = 
0100: 5b 5d 0a 0a 61 52 55 4c 45 53 45 54 20 3d 20 73  []..aRULESET = s
0110: 65 74 28 29 20 20 20 20 20 23 20 73 65 74 20 6f  et()     # set o
0120: 66 20 72 75 6c 65 2d 69 64 73 20 74 6f 20 63 68  f rule-ids to ch
0130: 65 63 6b 20 69 66 20 74 68 65 72 65 20 69 73 20  eck if there is 
0140: 73 65 76 65 72 61 6c 20 72 75 6c 65 73 20 77 69  several rules wi
0150: 74 68 20 74 68 65 20 73 61 6d 65 20 69 64 0a 0a  th the same id..
0160: 64 4a 53 52 45 47 45 58 45 53 20 3d 20 7b 7d 0a  dJSREGEXES = {}.
0170: 0a 73 57 4f 52 44 4c 49 4d 49 54 4c 45 46 54 20  .sWORDLIMITLEFT 
0180: 20 3d 20 72 22 28 3f 3c 21 5b 5c 77 2e 2c e2 80   = r"(?<![\w.,..
0190: 93 2d 5d 29 22 20 20 20 23 20 72 22 28 3f 3c 21  .-])"   # r"(?<!
01a0: 5b 2d 2e 2c e2 80 94 5d 29 5c 62 22 20 20 73 65  [-.,...])\b"  se
01b0: 65 6d 73 20 73 6c 6f 77 65 72 0a 73 57 4f 52 44  ems slower.sWORD
01c0: 4c 49 4d 49 54 52 49 47 48 54 20 3d 20 72 22 28  LIMITRIGHT = r"(
01d0: 3f 21 5b 5c 77 e2 80 93 2d 5d 29 22 20 20 20 20  ?![\w...-])"    
01e0: 20 20 23 20 72 22 5c 62 28 3f 21 2d e2 80 94 29    # r"\b(?!-...)
01f0: 22 20 20 20 20 20 20 20 73 65 65 6d 73 20 73 6c  "       seems sl
0200: 6f 77 65 72 0a 0a 0a 64 65 66 20 63 6f 6e 76 65  ower...def conve
0210: 72 74 52 47 42 54 6f 49 6e 74 65 67 65 72 20 28  rtRGBToInteger (
0220: 72 2c 20 67 2c 20 62 29 3a 0a 20 20 20 20 22 72  r, g, b):.    "r
0230: 62 67 20 28 69 6e 74 2c 20 69 6e 74 2c 20 69 6e  bg (int, int, in
0240: 74 29 20 2d 3e 20 69 6e 74 22 0a 20 20 20 20 72  t) -> int".    r
0250: 65 74 75 72 6e 20 28 72 20 26 20 32 35 35 29 20  eturn (r & 255) 
0260: 3c 3c 20 31 36 20 7c 20 28 67 20 26 20 32 35 35  << 16 | (g & 255
0270: 29 20 3c 3c 20 38 20 7c 20 28 62 20 26 20 32 35  ) << 8 | (b & 25
0280: 35 29 0a 0a 0a 64 65 66 20 63 6f 6e 76 65 72 74  5)...def convert
0290: 48 53 4c 54 6f 52 42 47 20 28 68 2c 20 73 2c 20  HSLToRBG (h, s, 
02a0: 6c 29 3a 0a 20 20 20 20 22 68 73 6c 20 28 69 6e  l):.    "hsl (in
02b0: 74 2c 20 69 6e 74 2c 20 69 6e 74 29 20 2d 3e 20  t, int, int) -> 
02c0: 5b 69 6e 74 2c 20 69 6e 74 2c 20 69 6e 74 5d 22  [int, int, int]"
02d0: 0a 20 20 20 20 72 2c 20 67 2c 20 62 20 3d 20 63  .    r, g, b = c
02e0: 6f 6c 6f 72 73 79 73 2e 68 6c 73 5f 74 6f 5f 72  olorsys.hls_to_r
02f0: 67 62 28 68 2f 33 36 30 2c 20 6c 2f 31 30 30 2c  gb(h/360, l/100,
0300: 20 73 2f 31 30 30 29 0a 20 20 20 20 72 65 74 75   s/100).    retu
0310: 72 6e 20 5b 72 6f 75 6e 64 28 72 2a 32 35 35 29  rn [round(r*255)
0320: 2c 20 72 6f 75 6e 64 28 67 2a 32 35 35 29 2c 20  , round(g*255), 
0330: 72 6f 75 6e 64 28 62 2a 32 35 35 29 5d 0a 0a 0a  round(b*255)]...
0340: 64 65 66 20 63 72 65 61 74 65 43 6f 6c 6f 72 73  def createColors
0350: 20 28 64 43 6f 6c 6f 72 29 3a 0a 20 20 20 20 22   (dColor):.    "
0360: 64 69 63 74 69 6f 6e 61 72 79 20 6f 66 20 63 6f  dictionary of co
0370: 6c 6f 72 73 20 7b 63 6f 6c 6f 72 5f 6e 61 6d 65  lors {color_name
0380: 3a 20 5b 68 2c 20 73 2c 20 6c 5d 7d 20 2d 3e 20  : [h, s, l]} -> 
0390: 72 65 74 75 72 6e 73 20 64 69 63 74 69 6f 6e 61  returns dictiona
03a0: 72 79 20 6f 66 20 63 6f 6c 6f 72 73 20 61 73 20  ry of colors as 
03b0: 64 69 63 74 69 6f 6e 61 72 69 65 73 20 6f 66 20  dictionaries of 
03c0: 63 6f 6c 6f 72 20 74 79 70 65 73 22 0a 20 20 20  color types".   
03d0: 20 64 43 6f 6c 6f 72 54 79 70 65 20 3d 20 7b 0a   dColorType = {.
03e0: 20 20 20 20 20 20 20 20 22 61 48 53 4c 22 3a 20          "aHSL": 
03f0: 7b 7d 2c 20 20 20 20 20 23 20 64 69 63 74 69 6f  {},     # dictio
0400: 6e 61 72 79 20 6f 66 20 63 6f 6c 6f 72 73 20 61  nary of colors a
0410: 73 20 48 53 4c 20 6c 69 73 74 0a 20 20 20 20 20  s HSL list.     
0420: 20 20 20 22 73 43 53 53 22 3a 20 7b 7d 2c 20 20     "sCSS": {},  
0430: 20 20 20 23 20 64 69 63 74 69 6f 6e 61 72 79 20     # dictionary 
0440: 6f 66 20 63 6f 6c 6f 72 73 20 61 73 20 73 74 72  of colors as str
0450: 69 6e 67 73 20 66 6f 72 20 48 54 4d 4c 2f 43 53  ings for HTML/CS
0460: 53 20 28 65 78 61 6d 70 6c 65 3a 20 68 73 6c 28  S (example: hsl(
0470: 30 2c 20 35 30 25 2c 20 35 30 25 29 29 0a 20 20  0, 50%, 50%)).  
0480: 20 20 20 20 20 20 22 61 52 47 42 22 3a 20 7b 7d        "aRGB": {}
0490: 2c 20 20 20 20 20 23 20 64 69 63 74 69 6f 6e 61  ,     # dictiona
04a0: 72 79 20 6f 66 20 63 6f 6c 6f 72 73 20 61 73 20  ry of colors as 
04b0: 52 47 42 20 6c 69 73 74 0a 20 20 20 20 20 20 20  RGB list.       
04c0: 20 22 6e 49 6e 74 22 3a 20 7b 7d 20 20 20 20 20   "nInt": {}     
04d0: 20 23 20 64 69 63 74 69 6f 6e 61 72 79 20 6f 66   # dictionary of
04e0: 20 63 6f 6c 6f 72 73 20 61 73 20 69 6e 74 65 67   colors as integ
04f0: 65 72 20 76 61 6c 75 65 73 20 28 66 6f 72 20 57  er values (for W
0500: 72 69 74 65 72 29 0a 20 20 20 20 7d 0a 20 20 20  riter).    }.   
0510: 20 66 6f 72 20 73 4b 65 79 2c 20 61 48 53 4c 20   for sKey, aHSL 
0520: 69 6e 20 64 43 6f 6c 6f 72 2e 69 74 65 6d 73 28  in dColor.items(
0530: 29 3a 0a 20 20 20 20 20 20 20 20 64 43 6f 6c 6f  ):.        dColo
0540: 72 54 79 70 65 5b 22 61 48 53 4c 22 5d 5b 73 4b  rType["aHSL"][sK
0550: 65 79 5d 20 3d 20 61 48 53 4c 0a 20 20 20 20 20  ey] = aHSL.     
0560: 20 20 20 64 43 6f 6c 6f 72 54 79 70 65 5b 22 73     dColorType["s
0570: 43 53 53 22 5d 5b 73 4b 65 79 5d 20 3d 20 22 68  CSS"][sKey] = "h
0580: 73 6c 28 7b 7d 2c 20 7b 7d 25 2c 20 7b 7d 25 29  sl({}, {}%, {}%)
0590: 22 2e 66 6f 72 6d 61 74 28 2a 61 48 53 4c 29 0a  ".format(*aHSL).
05a0: 20 20 20 20 20 20 20 20 64 43 6f 6c 6f 72 54 79          dColorTy
05b0: 70 65 5b 22 61 52 47 42 22 5d 5b 73 4b 65 79 5d  pe["aRGB"][sKey]
05c0: 20 3d 20 63 6f 6e 76 65 72 74 48 53 4c 54 6f 52   = convertHSLToR
05d0: 42 47 28 2a 61 48 53 4c 29 0a 20 20 20 20 20 20  BG(*aHSL).      
05e0: 20 20 64 43 6f 6c 6f 72 54 79 70 65 5b 22 6e 49    dColorType["nI
05f0: 6e 74 22 5d 5b 73 4b 65 79 5d 20 3d 20 63 6f 6e  nt"][sKey] = con
0600: 76 65 72 74 52 47 42 54 6f 49 6e 74 65 67 65 72  vertRGBToInteger
0610: 28 2a 64 43 6f 6c 6f 72 54 79 70 65 5b 22 61 52  (*dColorType["aR
0620: 47 42 22 5d 5b 73 4b 65 79 5d 29 0a 20 20 20 20  GB"][sKey]).    
0630: 72 65 74 75 72 6e 20 64 43 6f 6c 6f 72 54 79 70  return dColorTyp
0640: 65 0a 0a 0a 64 65 66 20 70 72 65 70 61 72 65 46  e...def prepareF
0650: 75 6e 63 74 69 6f 6e 20 28 73 29 3a 0a 20 20 20  unction (s):.   
0660: 20 22 63 6f 6e 76 65 72 74 20 73 69 6d 70 6c 65   "convert simple
0670: 20 72 75 6c 65 20 73 79 6e 74 61 78 20 74 6f 20   rule syntax to 
0680: 61 20 73 74 72 69 6e 67 20 6f 66 20 50 79 74 68  a string of Pyth
0690: 6f 6e 20 63 6f 64 65 22 0a 20 20 20 20 73 20 3d  on code".    s =
06a0: 20 73 2e 72 65 70 6c 61 63 65 28 22 5f 5f 61 6c   s.replace("__al
06b0: 73 6f 5f 5f 22 2c 20 22 62 43 6f 6e 64 4d 65 6d  so__", "bCondMem
06c0: 6f 22 29 0a 20 20 20 20 73 20 3d 20 73 2e 72 65  o").    s = s.re
06d0: 70 6c 61 63 65 28 22 5f 5f 65 6c 73 65 5f 5f 22  place("__else__"
06e0: 2c 20 22 6e 6f 74 20 62 43 6f 6e 64 4d 65 6d 6f  , "not bCondMemo
06f0: 22 29 0a 20 20 20 20 73 20 3d 20 73 2e 72 65 70  ").    s = s.rep
0700: 6c 61 63 65 28 22 73 43 6f 6e 74 65 78 74 22 2c  lace("sContext",
0710: 20 22 5f 73 41 70 70 43 6f 6e 74 65 78 74 22 29   "_sAppContext")
0720: 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62 28  .    s = re.sub(
0730: 72 22 5c 62 73 74 61 72 74 5c 28 5c 29 22 2c 20  r"\bstart\(\)", 
0740: 27 62 65 66 6f 72 65 28 22 5e 20 2a 24 7c 2c 20  'before("^ *$|, 
0750: 2a 24 22 29 27 2c 20 73 29 0a 20 20 20 20 73 20  *$")', s).    s 
0760: 3d 20 72 65 2e 73 75 62 28 72 22 5c 62 72 65 61  = re.sub(r"\brea
0770: 6c 73 74 61 72 74 5c 28 5c 29 22 2c 20 27 62 65  lstart\(\)", 'be
0780: 66 6f 72 65 28 22 5e 20 2a 24 22 29 27 2c 20 73  fore("^ *$")', s
0790: 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62  ).    s = re.sub
07a0: 28 72 22 5c 62 73 74 61 72 74 30 5c 28 5c 29 22  (r"\bstart0\(\)"
07b0: 2c 20 27 62 65 66 6f 72 65 30 28 22 5e 20 2a 24  , 'before0("^ *$
07c0: 7c 2c 20 2a 24 22 29 27 2c 20 73 29 0a 20 20 20  |, *$")', s).   
07d0: 20 73 20 3d 20 72 65 2e 73 75 62 28 72 22 5c 62   s = re.sub(r"\b
07e0: 72 65 61 6c 73 74 61 72 74 30 5c 28 5c 29 22 2c  realstart0\(\)",
07f0: 20 27 62 65 66 6f 72 65 30 28 22 5e 20 2a 24 22   'before0("^ *$"
0800: 29 27 2c 20 73 29 0a 20 20 20 20 73 20 3d 20 72  )', s).    s = r
0810: 65 2e 73 75 62 28 72 22 5c 62 65 6e 64 5c 28 5c  e.sub(r"\bend\(\
0820: 29 22 2c 20 27 61 66 74 65 72 28 22 5e 20 2a 24  )", 'after("^ *$
0830: 7c 5e 2c 22 29 27 2c 20 73 29 0a 20 20 20 20 73  |^,")', s).    s
0840: 20 3d 20 72 65 2e 73 75 62 28 72 22 5c 62 72 65   = re.sub(r"\bre
0850: 61 6c 65 6e 64 5c 28 5c 29 22 2c 20 27 61 66 74  alend\(\)", 'aft
0860: 65 72 28 22 5e 20 2a 24 22 29 27 2c 20 73 29 0a  er("^ *$")', s).
0870: 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62 28 72      s = re.sub(r
0880: 22 5c 62 65 6e 64 30 5c 28 5c 29 22 2c 20 27 61  "\bend0\(\)", 'a
0890: 66 74 65 72 30 28 22 5e 20 2a 24 7c 5e 2c 22 29  fter0("^ *$|^,")
08a0: 27 2c 20 73 29 0a 20 20 20 20 73 20 3d 20 72 65  ', s).    s = re
08b0: 2e 73 75 62 28 72 22 5c 62 72 65 61 6c 65 6e 64  .sub(r"\brealend
08c0: 30 5c 28 5c 29 22 2c 20 27 61 66 74 65 72 30 28  0\(\)", 'after0(
08d0: 22 5e 20 2a 24 22 29 27 2c 20 73 29 0a 20 20 20  "^ *$")', s).   
08e0: 20 73 20 3d 20 72 65 2e 73 75 62 28 72 22 5c 62   s = re.sub(r"\b
08f0: 73 65 6c 65 63 74 5b 28 5d 5b 5c 5c 5d 28 5c 64  select[(][\\](\d
0900: 2b 29 22 2c 20 27 5c 5c 31 28 64 54 6f 6b 65 6e  +)", '\\1(dToken
0910: 50 6f 73 2c 20 6d 2e 73 74 61 72 74 28 5c 5c 31  Pos, m.start(\\1
0920: 29 2c 20 6d 2e 67 72 6f 75 70 28 5c 5c 31 29 27  ), m.group(\\1)'
0930: 2c 20 73 29 0a 20 20 20 20 73 20 3d 20 72 65 2e  , s).    s = re.
0940: 73 75 62 28 72 22 5c 62 64 65 66 69 6e 65 5b 28  sub(r"\bdefine[(
0950: 5d 5b 5c 5c 5d 28 5c 64 2b 29 22 2c 20 27 64 65  ][\\](\d+)", 'de
0960: 66 69 6e 65 28 64 54 6f 6b 65 6e 50 6f 73 2c 20  fine(dTokenPos, 
0970: 6d 2e 73 74 61 72 74 28 5c 5c 31 29 27 2c 20 73  m.start(\\1)', s
0980: 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62  ).    s = re.sub
0990: 28 72 22 5c 62 28 6d 6f 72 70 68 7c 69 6e 66 6f  (r"\b(morph|info
09a0: 29 5b 28 5d 5b 5c 5c 5d 28 5c 64 2b 29 22 2c 20  )[(][\\](\d+)", 
09b0: 27 5c 5c 31 28 28 6d 2e 73 74 61 72 74 28 5c 5c  '\\1((m.start(\\
09c0: 32 29 2c 20 6d 2e 67 72 6f 75 70 28 5c 5c 32 29  2), m.group(\\2)
09d0: 29 27 2c 20 73 29 0a 20 20 20 20 73 20 3d 20 72  )', s).    s = r
09e0: 65 2e 73 75 62 28 72 22 5c 62 28 6d 6f 72 70 68  e.sub(r"\b(morph
09f0: 7c 69 6e 66 6f 29 5b 28 5d 22 2c 20 27 5c 5c 31  |info)[(]", '\\1
0a00: 28 64 54 6f 6b 65 6e 50 6f 73 2c 20 27 2c 20 73  (dTokenPos, ', s
0a10: 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62  ).    s = re.sub
0a20: 28 72 22 5c 62 28 73 75 67 67 5c 77 2b 7c 73 77  (r"\b(sugg\w+|sw
0a30: 69 74 63 68 5c 77 2b 29 5c 28 40 22 2c 20 27 5c  itch\w+)\(@", '\
0a40: 5c 31 28 6d 2e 67 72 6f 75 70 28 69 5b 34 5d 29  \1(m.group(i[4])
0a50: 27 2c 20 73 29 0a 20 20 20 20 73 20 3d 20 72 65  ', s).    s = re
0a60: 2e 73 75 62 28 72 22 5c 62 77 6f 72 64 5c 28 5c  .sub(r"\bword\(\
0a70: 73 2a 31 5c 62 22 2c 20 27 6e 65 78 74 77 6f 72  s*1\b", 'nextwor
0a80: 64 31 28 73 53 65 6e 74 65 6e 63 65 2c 20 6d 2e  d1(sSentence, m.
0a90: 65 6e 64 28 29 27 2c 20 73 29 20 20 20 20 20 20  end()', s)      
0aa0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0ab0: 20 20 20 20 20 20 20 20 20 20 23 20 77 6f 72 64            # word
0ac0: 28 31 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73  (1).    s = re.s
0ad0: 75 62 28 72 22 5c 62 77 6f 72 64 5c 28 5c 73 2a  ub(r"\bword\(\s*
0ae0: 2d 31 5c 62 22 2c 20 27 70 72 65 76 77 6f 72 64  -1\b", 'prevword
0af0: 31 28 73 53 65 6e 74 65 6e 63 65 2c 20 6d 2e 73  1(sSentence, m.s
0b00: 74 61 72 74 28 29 27 2c 20 73 29 20 20 20 20 20  tart()', s)     
0b10: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0b20: 20 20 20 20 20 20 20 20 23 20 77 6f 72 64 28 2d          # word(-
0b30: 31 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75  1).    s = re.su
0b40: 62 28 72 22 5c 62 77 6f 72 64 5c 28 5c 73 2a 28  b(r"\bword\(\s*(
0b50: 5c 64 29 22 2c 20 27 6e 65 78 74 77 6f 72 64 28  \d)", 'nextword(
0b60: 73 53 65 6e 74 65 6e 63 65 2c 20 6d 2e 65 6e 64  sSentence, m.end
0b70: 28 29 2c 20 5c 5c 31 27 2c 20 73 29 20 20 20 20  (), \\1', s)    
0b80: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0b90: 20 20 20 20 20 20 20 23 20 77 6f 72 64 28 6e 29         # word(n)
0ba0: 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62 28  .    s = re.sub(
0bb0: 72 22 5c 62 77 6f 72 64 5c 28 5c 73 2a 2d 28 5c  r"\bword\(\s*-(\
0bc0: 64 29 22 2c 20 27 70 72 65 76 77 6f 72 64 28 73  d)", 'prevword(s
0bd0: 53 65 6e 74 65 6e 63 65 2c 20 6d 2e 73 74 61 72  Sentence, m.star
0be0: 74 28 29 2c 20 5c 5c 31 27 2c 20 73 29 20 20 20  t(), \\1', s)   
0bf0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0c00: 20 20 20 20 20 23 20 77 6f 72 64 28 2d 6e 29 0a       # word(-n).
0c10: 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62 28 72      s = re.sub(r
0c20: 22 5c 62 62 65 66 6f 72 65 5c 28 5c 73 2a 22 2c  "\bbefore\(\s*",
0c30: 20 27 6c 6f 6f 6b 28 73 53 65 6e 74 65 6e 63 65   'look(sSentence
0c40: 5b 3a 6d 2e 73 74 61 72 74 28 29 5d 2c 20 27 2c  [:m.start()], ',
0c50: 20 73 29 20 20 20 20 20 20 20 20 20 20 20 20 20   s)             
0c60: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0c70: 20 20 20 20 23 20 62 65 66 6f 72 65 28 73 53 65      # before(sSe
0c80: 6e 74 65 6e 63 65 29 0a 20 20 20 20 73 20 3d 20  ntence).    s = 
0c90: 72 65 2e 73 75 62 28 72 22 5c 62 61 66 74 65 72  re.sub(r"\bafter
0ca0: 5c 28 5c 73 2a 22 2c 20 27 6c 6f 6f 6b 28 73 53  \(\s*", 'look(sS
0cb0: 65 6e 74 65 6e 63 65 5b 6d 2e 65 6e 64 28 29 3a  entence[m.end():
0cc0: 5d 2c 20 27 2c 20 73 29 20 20 20 20 20 20 20 20  ], ', s)        
0cd0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0ce0: 20 20 20 20 20 20 20 20 20 20 20 20 23 20 61 66              # af
0cf0: 74 65 72 28 73 53 65 6e 74 65 6e 63 65 29 0a 20  ter(sSentence). 
0d00: 20 20 20 73 20 3d 20 72 65 2e 73 75 62 28 72 22     s = re.sub(r"
0d10: 5c 62 74 65 78 74 61 72 65 61 5c 28 5c 73 2a 22  \btextarea\(\s*"
0d20: 2c 20 27 6c 6f 6f 6b 28 73 53 65 6e 74 65 6e 63  , 'look(sSentenc
0d30: 65 2c 20 27 2c 20 73 29 20 20 20 20 20 20 20 20  e, ', s)        
0d40: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0d50: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0d60: 20 20 20 23 20 74 65 78 74 61 72 65 61 28 73 53     # textarea(sS
0d70: 65 6e 74 65 6e 63 65 29 0a 20 20 20 20 73 20 3d  entence).    s =
0d80: 20 72 65 2e 73 75 62 28 72 22 2f 30 22 2c 20 27   re.sub(r"/0", '
0d90: 73 53 65 6e 74 65 6e 63 65 30 5b 6d 2e 73 74 61  sSentence0[m.sta
0da0: 72 74 28 29 3a 6d 2e 65 6e 64 28 29 5d 27 2c 20  rt():m.end()]', 
0db0: 73 29 20 20 20 20 20 20 20 20 20 20 20 20 20 20  s)              
0dc0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0dd0: 20 20 20 20 20 20 20 20 20 20 20 20 20 23 20 2f               # /
0de0: 30 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75 62  0.    s = re.sub
0df0: 28 72 22 5c 62 62 65 66 6f 72 65 30 5c 28 5c 73  (r"\bbefore0\(\s
0e00: 2a 22 2c 20 27 6c 6f 6f 6b 28 73 53 65 6e 74 65  *", 'look(sSente
0e10: 6e 63 65 30 5b 3a 6d 2e 73 74 61 72 74 28 29 5d  nce0[:m.start()]
0e20: 2c 20 27 2c 20 73 29 20 20 20 20 20 20 20 20 20  , ', s)         
0e30: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0e40: 20 20 20 20 20 20 23 20 62 65 66 6f 72 65 30 28        # before0(
0e50: 73 53 65 6e 74 65 6e 63 65 29 0a 20 20 20 20 73  sSentence).    s
0e60: 20 3d 20 72 65 2e 73 75 62 28 72 22 5c 62 61 66   = re.sub(r"\baf
0e70: 74 65 72 30 5c 28 5c 73 2a 22 2c 20 27 6c 6f 6f  ter0\(\s*", 'loo
0e80: 6b 28 73 53 65 6e 74 65 6e 63 65 30 5b 6d 2e 65  k(sSentence0[m.e
0e90: 6e 64 28 29 3a 5d 2c 20 27 2c 20 73 29 20 20 20  nd():], ', s)   
0ea0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0eb0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 23                 #
0ec0: 20 61 66 74 65 72 30 28 73 53 65 6e 74 65 6e 63   after0(sSentenc
0ed0: 65 29 0a 20 20 20 20 73 20 3d 20 72 65 2e 73 75  e).    s = re.su
0ee0: 62 28 72 22 5c 62 74 65 78 74 61 72 65 61 30 5c  b(r"\btextarea0\
0ef0: 28 5c 73 2a 22 2c 20 27 6c 6f 6f 6b 28 73 53 65  (\s*", 'look(sSe
0f00: 6e 74 65 6e 63 65 30 2c 20 27 2c 20 73 29 20 20  ntence0, ', s)  
0f10: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0f20: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0f30: 20 20 20 20 20 20 20 23 20 74 65 78 74 61 72 65         # textare
0f40: 61 30 28 73 53 65 6e 74 65 6e 63 65 29 0a 20 20  a0(sSentence).  
0f50: 20 20 73 20 3d 20 72 65 2e 73 75 62 28 72 22 5c    s = re.sub(r"\
0f60: 62 73 70 65 6c 6c 20 2a 5b 28 5d 22 2c 20 27 5f  bspell *[(]", '_
0f70: 6f 53 70 65 6c 6c 43 68 65 63 6b 65 72 2e 69 73  oSpellChecker.is
0f80: 56 61 6c 69 64 28 27 2c 20 73 29 0a 20 20 20 20  Valid(', s).    
0f90: 73 20 3d 20 72 65 2e 73 75 62 28 72 22 5b 5c 5c  s = re.sub(r"[\\
0fa0: 5d 28 5c 64 2b 29 22 2c 20 27 6d 2e 67 72 6f 75  ](\d+)", 'm.grou
0fb0: 70 28 5c 5c 31 29 27 2c 20 73 29 0a 20 20 20 20  p(\\1)', s).    
0fc0: 72 65 74 75 72 6e 20 73 0a 0a 0a 64 65 66 20 75  return s...def u
0fd0: 70 70 65 72 63 61 73 65 20 28 73 54 65 78 74 2c  ppercase (sText,
0fe0: 20 73 4c 61 6e 67 29 3a 0a 20 20 20 20 22 28 66   sLang):.    "(f
0ff0: 6c 61 67 20 69 20 69 73 20 6e 6f 74 20 65 6e 6f  lag i is not eno
1000: 75 67 68 29 3a 20 63 6f 6e 76 65 72 74 73 20 72  ugh): converts r
1010: 65 67 65 78 20 74 6f 20 75 70 70 65 72 63 61 73  egex to uppercas
1020: 65 20 72 65 67 65 78 3a 20 27 66 6f 6f 27 20 62  e regex: 'foo' b
1030: 65 63 6f 6d 65 73 20 27 5b 46 66 5d 5b 4f 6f 5d  ecomes '[Ff][Oo]
1040: 5b 4f 6f 5d 27 2c 20 62 75 74 20 27 42 61 72 27  [Oo]', but 'Bar'
1050: 20 62 65 63 6f 6d 65 73 20 27 42 5b 41 61 5d 5b   becomes 'B[Aa][
1060: 52 72 5d 27 2e 22 0a 20 20 20 20 73 55 70 20 3d  Rr]'.".    sUp =
1070: 20 22 22 0a 20 20 20 20 6e 53 74 61 74 65 20 3d   "".    nState =
1080: 20 30 0a 20 20 20 20 66 6f 72 20 69 2c 20 63 20   0.    for i, c 
1090: 69 6e 20 65 6e 75 6d 65 72 61 74 65 28 73 54 65  in enumerate(sTe
10a0: 78 74 29 3a 0a 20 20 20 20 20 20 20 20 69 66 20  xt):.        if 
10b0: 63 20 3d 3d 20 22 5b 22 3a 0a 20 20 20 20 20 20  c == "[":.      
10c0: 20 20 20 20 20 20 6e 53 74 61 74 65 20 3d 20 31        nState = 1
10d0: 0a 20 20 20 20 20 20 20 20 69 66 20 6e 53 74 61  .        if nSta
10e0: 74 65 20 3d 3d 20 31 20 61 6e 64 20 63 20 3d 3d  te == 1 and c ==
10f0: 20 22 5d 22 3a 0a 20 20 20 20 20 20 20 20 20 20   "]":.          
1100: 20 20 6e 53 74 61 74 65 20 3d 20 30 0a 20 20 20    nState = 0.   
1110: 20 20 20 20 20 69 66 20 63 20 3d 3d 20 22 3c 22       if c == "<"
1120: 20 61 6e 64 20 69 20 3e 20 33 20 61 6e 64 20 73   and i > 3 and s
1130: 54 65 78 74 5b 69 2d 33 3a 69 5d 20 3d 3d 20 22  Text[i-3:i] == "
1140: 28 3f 50 22 3a 0a 20 20 20 20 20 20 20 20 20 20  (?P":.          
1150: 20 20 6e 53 74 61 74 65 20 3d 20 32 0a 20 20 20    nState = 2.   
1160: 20 20 20 20 20 69 66 20 6e 53 74 61 74 65 20 3d       if nState =
1170: 3d 20 32 20 61 6e 64 20 63 20 3d 3d 20 22 3e 22  = 2 and c == ">"
1180: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 6e 53  :.            nS
1190: 74 61 74 65 20 3d 20 30 0a 20 20 20 20 20 20 20  tate = 0.       
11a0: 20 69 66 20 63 20 3d 3d 20 22 3f 22 20 61 6e 64   if c == "?" and
11b0: 20 69 20 3e 20 30 20 61 6e 64 20 73 54 65 78 74   i > 0 and sText
11c0: 5b 69 2d 31 3a 69 5d 20 3d 3d 20 22 28 22 20 61  [i-1:i] == "(" a
11d0: 6e 64 20 73 54 65 78 74 5b 69 2b 31 3a 69 2b 32  nd sText[i+1:i+2
11e0: 5d 20 21 3d 20 22 3a 22 3a 0a 20 20 20 20 20 20  ] != ":":.      
11f0: 20 20 20 20 20 20 6e 53 74 61 74 65 20 3d 20 35        nState = 5
1200: 0a 20 20 20 20 20 20 20 20 69 66 20 6e 53 74 61  .        if nSta
1210: 74 65 20 3d 3d 20 35 20 61 6e 64 20 63 20 3d 3d  te == 5 and c ==
1220: 20 22 29 22 3a 0a 20 20 20 20 20 20 20 20 20 20   ")":.          
1230: 20 20 6e 53 74 61 74 65 20 3d 20 30 0a 20 20 20    nState = 0.   
1240: 20 20 20 20 20 69 66 20 63 2e 69 73 61 6c 70 68       if c.isalph
1250: 61 28 29 20 61 6e 64 20 63 2e 69 73 6c 6f 77 65  a() and c.islowe
1260: 72 28 29 20 61 6e 64 20 6e 53 74 61 74 65 20 3d  r() and nState =
1270: 3d 20 30 3a 0a 20 20 20 20 20 20 20 20 20 20 20  = 0:.           
1280: 20 69 66 20 63 20 3d 3d 20 22 69 22 20 61 6e 64   if c == "i" and
1290: 20 73 4c 61 6e 67 20 69 6e 20 28 22 74 72 22 2c   sLang in ("tr",
12a0: 20 22 61 7a 22 29 3a 0a 20 20 20 20 20 20 20 20   "az"):.        
12b0: 20 20 20 20 20 20 20 20 73 55 70 20 2b 3d 20 22          sUp += "
12c0: 5b c4 b0 22 20 2b 20 63 20 2b 20 22 5d 22 0a 20  [.." + c + "]". 
12d0: 20 20 20 20 20 20 20 20 20 20 20 65 6c 73 65 3a             else:
12e0: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
12f0: 20 73 55 70 20 2b 3d 20 22 5b 22 20 2b 20 63 2e   sUp += "[" + c.
1300: 75 70 70 65 72 28 29 20 2b 20 63 20 2b 20 22 5d  upper() + c + "]
1310: 22 0a 20 20 20 20 20 20 20 20 65 6c 69 66 20 63  ".        elif c
1320: 2e 69 73 61 6c 70 68 61 28 29 20 61 6e 64 20 63  .isalpha() and c
1330: 2e 69 73 6c 6f 77 65 72 28 29 20 61 6e 64 20 6e  .islower() and n
1340: 53 74 61 74 65 20 3d 3d 20 31 20 61 6e 64 20 73  State == 1 and s
1350: 54 65 78 74 5b 69 2b 31 3a 69 2b 32 5d 20 21 3d  Text[i+1:i+2] !=
1360: 20 22 2d 22 3a 0a 20 20 20 20 20 20 20 20 20 20   "-":.          
1370: 20 20 69 66 20 73 54 65 78 74 5b 69 2d 31 3a 69    if sText[i-1:i
1380: 5d 20 3d 3d 20 22 2d 22 20 61 6e 64 20 73 54 65  ] == "-" and sTe
1390: 78 74 5b 69 2d 32 3a 69 2d 31 5d 2e 69 73 6c 6f  xt[i-2:i-1].islo
13a0: 77 65 72 28 29 3a 20 20 23 20 5b 61 2d 7a 5d 20  wer():  # [a-z] 
13b0: 2d 3e 20 5b 61 2d 7a 41 2d 5a 5d 0a 20 20 20 20  -> [a-zA-Z].    
13c0: 20 20 20 20 20 20 20 20 20 20 20 20 73 55 70 20              sUp 
13d0: 2b 3d 20 63 20 2b 20 73 54 65 78 74 5b 69 2d 32  += c + sText[i-2
13e0: 3a 69 2d 31 5d 2e 75 70 70 65 72 28 29 20 2b 20  :i-1].upper() + 
13f0: 22 2d 22 20 2b 20 63 2e 75 70 70 65 72 28 29 0a  "-" + c.upper().
1400: 20 20 20 20 20 20 20 20 20 20 20 20 65 6c 69 66              elif
1410: 20 63 20 3d 3d 20 22 69 22 20 61 6e 64 20 73 4c   c == "i" and sL
1420: 61 6e 67 20 69 6e 20 28 22 74 72 22 2c 20 22 61  ang in ("tr", "a
1430: 7a 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20  z"):.           
1440: 20 20 20 20 20 73 55 70 20 2b 3d 20 22 c4 b0 22       sUp += ".."
1450: 20 2b 20 63 0a 20 20 20 20 20 20 20 20 20 20 20   + c.           
1460: 20 65 6c 73 65 3a 0a 20 20 20 20 20 20 20 20 20   else:.         
1470: 20 20 20 20 20 20 20 73 55 70 20 2b 3d 20 63 2e         sUp += c.
1480: 75 70 70 65 72 28 29 20 2b 20 63 0a 20 20 20 20  upper() + c.    
1490: 20 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20      else:.      
14a0: 20 20 20 20 20 20 73 55 70 20 2b 3d 20 63 0a 20        sUp += c. 
14b0: 20 20 20 20 20 20 20 69 66 20 63 20 3d 3d 20 22         if c == "
14c0: 5c 5c 22 3a 0a 20 20 20 20 20 20 20 20 20 20 20  \\":.           
14d0: 20 6e 53 74 61 74 65 20 3d 20 34 0a 20 20 20 20   nState = 4.    
14e0: 20 20 20 20 65 6c 69 66 20 6e 53 74 61 74 65 20      elif nState 
14f0: 3d 3d 20 34 3a 0a 20 20 20 20 20 20 20 20 20 20  == 4:.          
1500: 20 20 6e 53 74 61 74 65 20 3d 20 30 0a 20 20 20    nState = 0.   
1510: 20 72 65 74 75 72 6e 20 73 55 70 0a 0a 0a 64 65   return sUp...de
1520: 66 20 63 6f 75 6e 74 47 72 6f 75 70 49 6e 52 65  f countGroupInRe
1530: 67 65 78 20 28 73 52 65 67 65 78 29 3a 0a 20 20  gex (sRegex):.  
1540: 20 20 22 72 65 74 75 72 6e 73 20 74 68 65 20 6e    "returns the n
1550: 75 6d 62 65 72 20 6f 66 20 67 72 6f 75 70 73 20  umber of groups 
1560: 69 6e 20 3c 73 52 65 67 65 78 3e 22 0a 20 20 20  in <sRegex>".   
1570: 20 74 72 79 3a 0a 20 20 20 20 20 20 20 20 72 65   try:.        re
1580: 74 75 72 6e 20 72 65 2e 63 6f 6d 70 69 6c 65 28  turn re.compile(
1590: 73 52 65 67 65 78 29 2e 67 72 6f 75 70 73 0a 20  sRegex).groups. 
15a0: 20 20 20 65 78 63 65 70 74 20 72 65 2e 65 72 72     except re.err
15b0: 6f 72 3a 0a 20 20 20 20 20 20 20 20 74 72 61 63  or:.        trac
15c0: 65 62 61 63 6b 2e 70 72 69 6e 74 5f 65 78 63 28  eback.print_exc(
15d0: 29 0a 20 20 20 20 20 20 20 20 70 72 69 6e 74 28  ).        print(
15e0: 73 52 65 67 65 78 29 0a 20 20 20 20 72 65 74 75  sRegex).    retu
15f0: 72 6e 20 30 0a 0a 0a 64 65 66 20 63 72 65 61 74  rn 0...def creat
1600: 65 52 75 6c 65 20 28 73 2c 20 6e 4c 69 6e 65 49  eRule (s, nLineI
1610: 64 2c 20 73 4c 61 6e 67 2c 20 62 50 61 72 61 67  d, sLang, bParag
1620: 72 61 70 68 2c 20 64 4f 70 74 50 72 69 6f 72 69  raph, dOptPriori
1630: 74 79 29 3a 0a 20 20 20 20 22 72 65 74 75 72 6e  ty):.    "return
1640: 73 20 72 75 6c 65 20 61 73 20 6c 69 73 74 20 5b  s rule as list [
1650: 6f 70 74 69 6f 6e 20 6e 61 6d 65 2c 20 72 65 67  option name, reg
1660: 65 78 2c 20 62 43 61 73 65 49 6e 73 65 6e 73 69  ex, bCaseInsensi
1670: 74 69 76 65 2c 20 69 64 65 6e 74 69 66 69 65 72  tive, identifier
1680: 2c 20 6c 69 73 74 20 6f 66 20 61 63 74 69 6f 6e  , list of action
1690: 73 5d 22 0a 20 20 20 20 67 6c 6f 62 61 6c 20 64  s]".    global d
16a0: 4a 53 52 45 47 45 58 45 53 0a 0a 20 20 20 20 73  JSREGEXES..    s
16b0: 4c 69 6e 65 49 64 20 3d 20 66 22 23 7b 6e 4c 69  LineId = f"#{nLi
16c0: 6e 65 49 64 7d 22 20 2b 20 28 22 70 22 20 69 66  neId}" + ("p" if
16d0: 20 62 50 61 72 61 67 72 61 70 68 20 65 6c 73 65   bParagraph else
16e0: 20 22 73 22 29 0a 20 20 20 20 73 52 75 6c 65 49   "s").    sRuleI
16f0: 64 20 3d 20 73 4c 69 6e 65 49 64 0a 0a 20 20 20  d = sLineId..   
1700: 20 23 23 23 23 20 47 52 41 50 48 20 43 41 4c 4c   #### GRAPH CALL
1710: 0a 20 20 20 20 69 66 20 73 2e 73 74 61 72 74 73  .    if s.starts
1720: 77 69 74 68 28 22 40 40 40 40 22 29 3a 0a 20 20  with("@@@@"):.  
1730: 20 20 20 20 20 20 69 66 20 62 50 61 72 61 67 72        if bParagr
1740: 61 70 68 3a 0a 20 20 20 20 20 20 20 20 20 20 20  aph:.           
1750: 20 70 72 69 6e 74 28 22 45 72 72 6f 72 2e 20 47   print("Error. G
1760: 72 61 70 68 20 63 61 6c 6c 20 63 61 6e 20 62 65  raph call can be
1770: 20 6d 61 64 65 20 6f 6e 6c 79 20 61 66 74 65 72   made only after
1780: 20 74 68 65 20 66 69 72 73 74 20 70 61 73 73 20   the first pass 
1790: 28 73 65 6e 74 65 6e 63 65 20 62 79 20 73 65 6e  (sentence by sen
17a0: 74 65 6e 63 65 29 22 29 0a 20 20 20 20 20 20 20  tence)").       
17b0: 20 20 20 20 20 65 78 69 74 28 29 0a 20 20 20 20       exit().    
17c0: 20 20 20 20 72 65 74 75 72 6e 20 5b 22 40 40 40      return ["@@@
17d0: 40 22 2c 20 73 5b 34 3a 5d 2c 20 73 4c 69 6e 65  @", s[4:], sLine
17e0: 49 64 5d 0a 0a 20 20 20 20 23 23 23 23 20 4f 50  Id]..    #### OP
17f0: 54 49 4f 4e 53 0a 20 20 20 20 73 4f 70 74 69 6f  TIONS.    sOptio
1800: 6e 20 3d 20 22 22 20 20 20 20 20 20 20 20 20 20  n = ""          
1810: 20 20 23 20 65 6d 70 74 79 20 73 74 72 69 6e 67    # empty string
1820: 20 6f 72 20 5b 61 2d 7a 30 2d 39 5d 2b 20 6e 61   or [a-z0-9]+ na
1830: 6d 65 0a 20 20 20 20 6e 50 72 69 6f 72 69 74 79  me.    nPriority
1840: 20 3d 20 34 20 20 20 20 20 20 20 20 20 20 20 23   = 4           #
1850: 20 44 65 66 61 75 6c 74 20 69 73 20 34 2c 20 76   Default is 4, v
1860: 61 6c 75 65 20 6d 75 73 74 20 62 65 20 62 65 74  alue must be bet
1870: 77 65 65 6e 20 30 20 61 6e 64 20 39 0a 20 20 20  ween 0 and 9.   
1880: 20 74 47 72 6f 75 70 73 20 3d 20 4e 6f 6e 65 20   tGroups = None 
1890: 20 20 20 20 20 20 20 20 20 23 20 63 6f 64 65 20           # code 
18a0: 66 6f 72 20 67 72 6f 75 70 73 20 70 6f 73 69 74  for groups posit
18b0: 69 6f 6e 69 6e 67 20 28 6f 6e 6c 79 20 75 73 65  ioning (only use
18c0: 66 75 6c 20 66 6f 72 20 4a 61 76 61 53 63 72 69  ful for JavaScri
18d0: 70 74 29 0a 20 20 20 20 63 43 61 73 65 4d 6f 64  pt).    cCaseMod
18e0: 65 20 3d 20 27 69 27 20 20 20 20 20 20 20 20 20  e = 'i'         
18f0: 23 20 69 3a 20 63 61 73 65 20 69 6e 73 65 6e 73  # i: case insens
1900: 69 74 69 76 65 2c 20 20 73 3a 20 63 61 73 65 20  itive,  s: case 
1910: 73 65 6e 73 69 74 69 76 65 2c 20 20 75 3a 20 75  sensitive,  u: u
1920: 70 70 65 72 63 61 73 69 6e 67 20 61 6c 6c 6f 77  ppercasing allow
1930: 65 64 0a 20 20 20 20 63 57 6f 72 64 4c 69 6d 69  ed.    cWordLimi
1940: 74 4c 65 66 74 20 3d 20 27 5b 27 20 20 20 20 23  tLeft = '['    #
1950: 20 5b 3a 20 77 6f 72 64 20 6c 69 6d 69 74 2c 20   [: word limit, 
1960: 3c 3a 20 6e 6f 20 73 70 65 63 69 66 69 63 20 6c  <: no specific l
1970: 69 6d 69 74 0a 20 20 20 20 63 57 6f 72 64 4c 69  imit.    cWordLi
1980: 6d 69 74 52 69 67 68 74 20 3d 20 27 5d 27 20 20  mitRight = ']'  
1990: 20 23 20 5d 3a 20 77 6f 72 64 20 6c 69 6d 69 74   # ]: word limit
19a0: 2c 20 3e 3a 20 6e 6f 20 73 70 65 63 69 66 69 63  , >: no specific
19b0: 20 6c 69 6d 69 74 0a 20 20 20 20 6d 20 3d 20 72   limit.    m = r
19c0: 65 2e 6d 61 74 63 68 28 22 5e 5f 5f 28 3f 50 3c  e.match("^__(?P<
19d0: 62 6f 72 64 65 72 73 5f 61 6e 64 5f 63 61 73 65  borders_and_case
19e0: 3e 5b 5c 5c 5b 3c 5d 5c 5c 77 5b 5c 5c 5d 3e 5d  >[\\[<]\\w[\\]>]
19f0: 29 28 3f 50 3c 6f 70 74 69 6f 6e 3e 2f 5b 61 2d  )(?P<option>/[a-
1a00: 7a 41 2d 5a 30 2d 39 5d 2b 7c 29 28 3f 50 3c 72  zA-Z0-9]+|)(?P<r
1a10: 75 6c 65 69 64 3e 5c 5c 28 5c 5c 77 2b 5c 5c 29  uleid>\\(\\w+\\)
1a20: 29 28 3f 50 3c 70 72 69 6f 72 69 74 79 3e 21 5b  )(?P<priority>![
1a30: 30 2d 39 5d 7c 29 5f 5f 20 2a 22 2c 20 73 29 0a  0-9]|)__ *", s).
1a40: 20 20 20 20 69 66 20 6d 3a 0a 20 20 20 20 20 20      if m:.      
1a50: 20 20 63 57 6f 72 64 4c 69 6d 69 74 4c 65 66 74    cWordLimitLeft
1a60: 20 3d 20 6d 2e 67 72 6f 75 70 28 27 62 6f 72 64   = m.group('bord
1a70: 65 72 73 5f 61 6e 64 5f 63 61 73 65 27 29 5b 30  ers_and_case')[0
1a80: 5d 0a 20 20 20 20 20 20 20 20 63 43 61 73 65 4d  ].        cCaseM
1a90: 6f 64 65 20 3d 20 6d 2e 67 72 6f 75 70 28 27 62  ode = m.group('b
1aa0: 6f 72 64 65 72 73 5f 61 6e 64 5f 63 61 73 65 27  orders_and_case'
1ab0: 29 5b 31 5d 0a 20 20 20 20 20 20 20 20 63 57 6f  )[1].        cWo
1ac0: 72 64 4c 69 6d 69 74 52 69 67 68 74 20 3d 20 6d  rdLimitRight = m
1ad0: 2e 67 72 6f 75 70 28 27 62 6f 72 64 65 72 73 5f  .group('borders_
1ae0: 61 6e 64 5f 63 61 73 65 27 29 5b 32 5d 0a 20 20  and_case')[2].  
1af0: 20 20 20 20 20 20 73 4f 70 74 69 6f 6e 20 3d 20        sOption = 
1b00: 6d 2e 67 72 6f 75 70 28 27 6f 70 74 69 6f 6e 27  m.group('option'
1b10: 29 5b 31 3a 5d 20 20 69 66 20 6d 2e 67 72 6f 75  )[1:]  if m.grou
1b20: 70 28 27 6f 70 74 69 6f 6e 27 29 20 20 65 6c 73  p('option')  els
1b30: 65 20 22 22 0a 20 20 20 20 20 20 20 20 73 52 75  e "".        sRu
1b40: 6c 65 49 64 20 3d 20 20 6d 2e 67 72 6f 75 70 28  leId =  m.group(
1b50: 27 72 75 6c 65 69 64 27 29 5b 31 3a 2d 31 5d 0a  'ruleid')[1:-1].
1b60: 20 20 20 20 20 20 20 20 69 66 20 73 52 75 6c 65          if sRule
1b70: 49 64 20 69 6e 20 61 52 55 4c 45 53 45 54 3a 0a  Id in aRULESET:.
1b80: 20 20 20 20 20 20 20 20 20 20 20 20 70 72 69 6e              prin
1b90: 74 28 66 22 23 20 45 72 72 6f 72 2e 20 53 65 76  t(f"# Error. Sev
1ba0: 65 72 61 6c 20 72 75 6c 65 73 20 68 61 76 65 20  eral rules have 
1bb0: 74 68 65 20 73 61 6d 65 20 69 64 3a 20 7b 73 52  the same id: {sR
1bc0: 75 6c 65 49 64 7d 22 29 0a 20 20 20 20 20 20 20  uleId}").       
1bd0: 20 20 20 20 20 65 78 69 74 28 29 0a 20 20 20 20       exit().    
1be0: 20 20 20 20 61 52 55 4c 45 53 45 54 2e 61 64 64      aRULESET.add
1bf0: 28 73 52 75 6c 65 49 64 29 0a 20 20 20 20 20 20  (sRuleId).      
1c00: 20 20 6e 50 72 69 6f 72 69 74 79 20 3d 20 64 4f    nPriority = dO
1c10: 70 74 50 72 69 6f 72 69 74 79 2e 67 65 74 28 73  ptPriority.get(s
1c20: 4f 70 74 69 6f 6e 2c 20 34 29 0a 20 20 20 20 20  Option, 4).     
1c30: 20 20 20 69 66 20 6d 2e 67 72 6f 75 70 28 27 70     if m.group('p
1c40: 72 69 6f 72 69 74 79 27 29 3a 0a 20 20 20 20 20  riority'):.     
1c50: 20 20 20 20 20 20 20 6e 50 72 69 6f 72 69 74 79         nPriority
1c60: 20 3d 20 69 6e 74 28 6d 2e 67 72 6f 75 70 28 27   = int(m.group('
1c70: 70 72 69 6f 72 69 74 79 27 29 5b 31 3a 5d 29 0a  priority')[1:]).
1c80: 20 20 20 20 20 20 20 20 73 20 3d 20 73 5b 6d 2e          s = s[m.
1c90: 65 6e 64 28 30 29 3a 5d 0a 20 20 20 20 65 6c 73  end(0):].    els
1ca0: 65 3a 0a 20 20 20 20 20 20 20 20 70 72 69 6e 74  e:.        print
1cb0: 28 66 22 23 20 57 61 72 6e 69 6e 67 2e 20 52 75  (f"# Warning. Ru
1cc0: 6c 65 20 77 72 6f 6e 67 6c 79 20 73 68 61 70 65  le wrongly shape
1cd0: 64 20 61 74 20 6c 69 6e 65 3a 20 7b 73 4c 69 6e  d at line: {sLin
1ce0: 65 49 64 7d 22 29 0a 20 20 20 20 20 20 20 20 65  eId}").        e
1cf0: 78 69 74 28 29 0a 0a 20 20 20 20 23 23 23 23 20  xit()..    #### 
1d00: 52 45 47 45 58 20 54 52 49 47 47 45 52 0a 20 20  REGEX TRIGGER.  
1d10: 20 20 69 20 3d 20 73 2e 66 69 6e 64 28 22 20 3c    i = s.find(" <
1d20: 3c 2d 22 29 0a 20 20 20 20 69 66 20 69 20 3d 3d  <-").    if i ==
1d30: 20 2d 31 3a 0a 20 20 20 20 20 20 20 20 70 72 69   -1:.        pri
1d40: 6e 74 28 66 22 23 20 45 72 72 6f 72 3a 20 6e 6f  nt(f"# Error: no
1d50: 20 63 6f 6e 64 69 74 69 6f 6e 20 61 74 20 6c 69   condition at li
1d60: 6e 65 20 7b 73 4c 69 6e 65 49 64 7d 22 29 0a 20  ne {sLineId}"). 
1d70: 20 20 20 20 20 20 20 72 65 74 75 72 6e 20 4e 6f         return No
1d80: 6e 65 0a 20 20 20 20 73 52 65 67 65 78 20 3d 20  ne.    sRegex = 
1d90: 73 5b 3a 69 5d 2e 73 74 72 69 70 28 29 0a 20 20  s[:i].strip().  
1da0: 20 20 73 20 3d 20 73 5b 69 2b 34 3a 5d 0a 0a 20    s = s[i+4:].. 
1db0: 20 20 20 23 20 4a 53 20 67 72 6f 75 70 73 20 70     # JS groups p
1dc0: 6f 73 69 74 69 6f 6e 69 6e 67 20 63 6f 64 65 73  ositioning codes
1dd0: 0a 20 20 20 20 6d 20 3d 20 72 65 2e 73 65 61 72  .    m = re.sear
1de0: 63 68 28 22 40 40 5c 5c 53 2b 22 2c 20 73 52 65  ch("@@\\S+", sRe
1df0: 67 65 78 29 0a 20 20 20 20 69 66 20 6d 3a 0a 20  gex).    if m:. 
1e00: 20 20 20 20 20 20 20 74 47 72 6f 75 70 73 20 3d         tGroups =
1e10: 20 6a 73 63 6f 6e 76 2e 67 72 6f 75 70 73 50 6f   jsconv.groupsPo
1e20: 73 69 74 69 6f 6e 69 6e 67 43 6f 64 65 54 6f 4c  sitioningCodeToL
1e30: 69 73 74 28 73 52 65 67 65 78 5b 6d 2e 73 74 61  ist(sRegex[m.sta
1e40: 72 74 28 29 2b 32 3a 5d 29 0a 20 20 20 20 20 20  rt()+2:]).      
1e50: 20 20 73 52 65 67 65 78 20 3d 20 73 52 65 67 65    sRegex = sRege
1e60: 78 5b 3a 6d 2e 73 74 61 72 74 28 29 5d 2e 73 74  x[:m.start()].st
1e70: 72 69 70 28 29 0a 20 20 20 20 23 20 4a 53 20 72  rip().    # JS r
1e80: 65 67 65 78 0a 20 20 20 20 6d 20 3d 20 72 65 2e  egex.    m = re.
1e90: 73 65 61 72 63 68 28 22 3c 6a 73 3e 2e 2b 3c 2f  search("<js>.+</
1ea0: 6a 73 3e 69 3f 22 2c 20 73 52 65 67 65 78 29 0a  js>i?", sRegex).
1eb0: 20 20 20 20 69 66 20 6d 3a 0a 20 20 20 20 20 20      if m:.      
1ec0: 20 20 64 4a 53 52 45 47 45 58 45 53 5b 73 4c 69    dJSREGEXES[sLi
1ed0: 6e 65 49 64 5d 20 3d 20 6d 2e 67 72 6f 75 70 28  neId] = m.group(
1ee0: 30 29 0a 20 20 20 20 20 20 20 20 73 52 65 67 65  0).        sRege
1ef0: 78 20 3d 20 73 52 65 67 65 78 5b 3a 6d 2e 73 74  x = sRegex[:m.st
1f00: 61 72 74 28 29 5d 2e 73 74 72 69 70 28 29 0a 20  art()].strip(). 
1f10: 20 20 20 69 66 20 22 3c 6a 73 3e 22 20 69 6e 20     if "<js>" in 
1f20: 73 52 65 67 65 78 20 6f 72 20 22 3c 2f 6a 73 3e  sRegex or "</js>
1f30: 22 20 69 6e 20 73 52 65 67 65 78 3a 0a 20 20 20  " in sRegex:.   
1f40: 20 20 20 20 20 70 72 69 6e 74 28 66 22 23 20 45       print(f"# E
1f50: 72 72 6f 72 3a 20 4a 61 76 61 53 63 72 69 70 74  rror: JavaScript
1f60: 20 72 65 67 65 78 20 6e 6f 74 20 64 65 6c 69 6d   regex not delim
1f70: 69 74 65 64 20 61 74 20 6c 69 6e 65 20 7b 73 4c  ited at line {sL
1f80: 69 6e 65 49 64 7d 22 29 0a 20 20 20 20 20 20 20  ineId}").       
1f90: 20 72 65 74 75 72 6e 20 4e 6f 6e 65 0a 0a 20 20   return None..  
1fa0: 20 20 23 20 71 75 6f 74 65 73 20 3f 0a 20 20 20    # quotes ?.   
1fb0: 20 69 66 20 73 52 65 67 65 78 2e 73 74 61 72 74   if sRegex.start
1fc0: 73 77 69 74 68 28 27 22 27 29 20 61 6e 64 20 73  swith('"') and s
1fd0: 52 65 67 65 78 2e 65 6e 64 73 77 69 74 68 28 27  Regex.endswith('
1fe0: 22 27 29 3a 0a 20 20 20 20 20 20 20 20 73 52 65  "'):.        sRe
1ff0: 67 65 78 20 3d 20 73 52 65 67 65 78 5b 31 3a 2d  gex = sRegex[1:-
2000: 31 5d 0a 0a 20 20 20 20 23 23 20 64 65 66 69 6e  1]..    ## defin
2010: 69 74 69 6f 6e 73 0a 20 20 20 20 66 6f 72 20 73  itions.    for s
2020: 44 65 66 2c 20 73 52 65 70 6c 20 69 6e 20 64 44  Def, sRepl in dD
2030: 45 46 49 4e 49 54 49 4f 4e 53 2e 69 74 65 6d 73  EFINITIONS.items
2040: 28 29 3a 0a 20 20 20 20 20 20 20 20 73 52 65 67  ():.        sReg
2050: 65 78 20 3d 20 73 52 65 67 65 78 2e 72 65 70 6c  ex = sRegex.repl
2060: 61 63 65 28 73 44 65 66 2c 20 73 52 65 70 6c 29  ace(sDef, sRepl)
2070: 0a 0a 20 20 20 20 23 23 20 63 6f 75 6e 74 20 6e  ..    ## count n
2080: 75 6d 62 65 72 20 6f 66 20 67 72 6f 75 70 73 20  umber of groups 
2090: 28 6d 75 73 74 20 62 65 20 64 6f 6e 65 20 62 65  (must be done be
20a0: 66 6f 72 65 20 6d 6f 64 69 66 79 69 6e 67 20 74  fore modifying t
20b0: 68 65 20 72 65 67 65 78 29 0a 20 20 20 20 6e 47  he regex).    nG
20c0: 72 6f 75 70 20 3d 20 63 6f 75 6e 74 47 72 6f 75  roup = countGrou
20d0: 70 49 6e 52 65 67 65 78 28 73 52 65 67 65 78 29  pInRegex(sRegex)
20e0: 0a 20 20 20 20 69 66 20 6e 47 72 6f 75 70 20 3e  .    if nGroup >
20f0: 20 30 3a 0a 20 20 20 20 20 20 20 20 69 66 20 6e   0:.        if n
2100: 6f 74 20 74 47 72 6f 75 70 73 3a 0a 20 20 20 20  ot tGroups:.    
2110: 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 66 22          print(f"
2120: 23 20 57 61 72 6e 69 6e 67 3a 20 67 72 6f 75 70  # Warning: group
2130: 73 20 70 6f 73 69 74 69 6f 6e 69 6e 67 20 63 6f  s positioning co
2140: 64 65 20 66 6f 72 20 4a 61 76 61 53 63 72 69 70  de for JavaScrip
2150: 74 20 73 68 6f 75 6c 64 20 62 65 20 64 65 66 69  t should be defi
2160: 6e 65 64 20 61 74 20 6c 69 6e 65 20 7b 73 4c 69  ned at line {sLi
2170: 6e 65 49 64 7d 22 29 0a 20 20 20 20 20 20 20 20  neId}").        
2180: 65 6c 73 65 3a 0a 20 20 20 20 20 20 20 20 20 20  else:.          
2190: 20 20 69 66 20 6e 47 72 6f 75 70 20 21 3d 20 6c    if nGroup != l
21a0: 65 6e 28 74 47 72 6f 75 70 73 29 3a 0a 20 20 20  en(tGroups):.   
21b0: 20 20 20 20 20 20 20 20 20 20 20 20 20 70 72 69               pri
21c0: 6e 74 28 66 22 23 20 45 72 72 6f 72 3a 20 67 72  nt(f"# Error: gr
21d0: 6f 75 70 73 20 70 6f 73 69 74 69 6f 6e 69 6e 67  oups positioning
21e0: 20 63 6f 64 65 20 69 72 72 65 6c 65 76 61 6e 74   code irrelevant
21f0: 20 61 74 20 6c 69 6e 65 20 7b 73 4c 69 6e 65 49   at line {sLineI
2200: 64 7d 22 29 0a 0a 20 20 20 20 23 23 20 77 6f 72  d}")..    ## wor
2210: 64 20 6c 69 6d 69 74 0a 20 20 20 20 69 66 20 63  d limit.    if c
2220: 57 6f 72 64 4c 69 6d 69 74 4c 65 66 74 20 3d 3d  WordLimitLeft ==
2230: 20 27 5b 27 20 61 6e 64 20 6e 6f 74 20 73 52 65   '[' and not sRe
2240: 67 65 78 2e 73 74 61 72 74 73 77 69 74 68 28 28  gex.startswith((
2250: 22 5e 22 2c 20 27 e2 80 99 27 2c 20 22 27 22 2c  "^", '...', "'",
2260: 20 22 2c 22 29 29 3a 0a 20 20 20 20 20 20 20 20   ",")):.        
2270: 73 52 65 67 65 78 20 3d 20 73 57 4f 52 44 4c 49  sRegex = sWORDLI
2280: 4d 49 54 4c 45 46 54 20 2b 20 73 52 65 67 65 78  MITLEFT + sRegex
2290: 0a 20 20 20 20 69 66 20 63 57 6f 72 64 4c 69 6d  .    if cWordLim
22a0: 69 74 52 69 67 68 74 20 3d 3d 20 27 5d 27 20 61  itRight == ']' a
22b0: 6e 64 20 6e 6f 74 20 73 52 65 67 65 78 2e 65 6e  nd not sRegex.en
22c0: 64 73 77 69 74 68 28 28 22 24 22 2c 20 27 e2 80  dswith(("$", '..
22d0: 99 27 2c 20 22 27 22 2c 20 22 2c 22 29 29 3a 0a  .', "'", ",")):.
22e0: 20 20 20 20 20 20 20 20 73 52 65 67 65 78 20 3d          sRegex =
22f0: 20 73 52 65 67 65 78 20 2b 20 73 57 4f 52 44 4c   sRegex + sWORDL
2300: 49 4d 49 54 52 49 47 48 54 0a 0a 20 20 20 20 23  IMITRIGHT..    #
2310: 23 20 63 61 73 69 6e 67 20 6d 6f 64 65 0a 20 20  # casing mode.  
2320: 20 20 69 66 20 63 43 61 73 65 4d 6f 64 65 20 3d    if cCaseMode =
2330: 3d 20 22 69 22 3a 0a 20 20 20 20 20 20 20 20 62  = "i":.        b
2340: 43 61 73 65 49 6e 73 65 6e 73 69 74 69 76 65 20  CaseInsensitive 
2350: 3d 20 54 72 75 65 0a 20 20 20 20 20 20 20 20 69  = True.        i
2360: 66 20 6e 6f 74 20 73 52 65 67 65 78 2e 73 74 61  f not sRegex.sta
2370: 72 74 73 77 69 74 68 28 22 28 3f 69 29 22 29 3a  rtswith("(?i)"):
2380: 0a 20 20 20 20 20 20 20 20 20 20 20 20 73 52 65  .            sRe
2390: 67 65 78 20 3d 20 22 28 3f 69 29 22 20 2b 20 73  gex = "(?i)" + s
23a0: 52 65 67 65 78 0a 20 20 20 20 65 6c 69 66 20 63  Regex.    elif c
23b0: 43 61 73 65 4d 6f 64 65 20 3d 3d 20 22 73 22 3a  CaseMode == "s":
23c0: 0a 20 20 20 20 20 20 20 20 62 43 61 73 65 49 6e  .        bCaseIn
23d0: 73 65 6e 73 69 74 69 76 65 20 3d 20 46 61 6c 73  sensitive = Fals
23e0: 65 0a 20 20 20 20 20 20 20 20 73 52 65 67 65 78  e.        sRegex
23f0: 20 3d 20 73 52 65 67 65 78 2e 72 65 70 6c 61 63   = sRegex.replac
2400: 65 28 22 28 3f 69 29 22 2c 20 22 22 29 0a 20 20  e("(?i)", "").  
2410: 20 20 65 6c 69 66 20 63 43 61 73 65 4d 6f 64 65    elif cCaseMode
2420: 20 3d 3d 20 22 75 22 3a 0a 20 20 20 20 20 20 20   == "u":.       
2430: 20 62 43 61 73 65 49 6e 73 65 6e 73 69 74 69 76   bCaseInsensitiv
2440: 65 20 3d 20 46 61 6c 73 65 0a 20 20 20 20 20 20  e = False.      
2450: 20 20 73 52 65 67 65 78 20 3d 20 73 52 65 67 65    sRegex = sRege
2460: 78 2e 72 65 70 6c 61 63 65 28 22 28 3f 69 29 22  x.replace("(?i)"
2470: 2c 20 22 22 29 0a 20 20 20 20 20 20 20 20 73 52  , "").        sR
2480: 65 67 65 78 20 3d 20 75 70 70 65 72 63 61 73 65  egex = uppercase
2490: 28 73 52 65 67 65 78 2c 20 73 4c 61 6e 67 29 0a  (sRegex, sLang).
24a0: 20 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20      else:.      
24b0: 20 20 70 72 69 6e 74 28 66 22 23 20 55 6e 6b 6e    print(f"# Unkn
24c0: 6f 77 6e 20 63 61 73 65 20 6d 6f 64 65 20 5b 7b  own case mode [{
24d0: 63 43 61 73 65 4d 6f 64 65 7d 5d 20 61 74 20 6c  cCaseMode}] at l
24e0: 69 6e 65 20 7b 73 4c 69 6e 65 49 64 7d 22 29 0a  ine {sLineId}").
24f0: 0a 20 20 20 20 23 23 20 63 68 65 63 6b 20 72 65  .    ## check re
2500: 67 65 78 0a 20 20 20 20 74 72 79 3a 0a 20 20 20  gex.    try:.   
2510: 20 20 20 20 20 72 65 2e 63 6f 6d 70 69 6c 65 28       re.compile(
2520: 73 52 65 67 65 78 29 0a 20 20 20 20 65 78 63 65  sRegex).    exce
2530: 70 74 20 72 65 2e 65 72 72 6f 72 3a 0a 20 20 20  pt re.error:.   
2540: 20 20 20 20 20 70 72 69 6e 74 28 66 22 23 20 52       print(f"# R
2550: 65 67 65 78 20 65 72 72 6f 72 20 61 74 20 6c 69  egex error at li
2560: 6e 65 20 7b 73 4c 69 6e 65 49 64 7d 22 29 0a 20  ne {sLineId}"). 
2570: 20 20 20 20 20 20 20 70 72 69 6e 74 28 73 52 65         print(sRe
2580: 67 65 78 29 0a 20 20 20 20 20 20 20 20 72 65 74  gex).        ret
2590: 75 72 6e 20 4e 6f 6e 65 0a 20 20 20 20 23 23 20  urn None.    ## 
25a0: 67 72 6f 75 70 73 20 69 6e 20 6e 6f 6e 20 67 72  groups in non gr
25b0: 6f 75 70 69 6e 67 20 70 61 72 65 6e 74 68 65 73  ouping parenthes
25c0: 69 73 0a 20 20 20 20 66 6f 72 20 5f 20 69 6e 20  is.    for _ in 
25d0: 72 65 2e 66 69 6e 64 69 74 65 72 28 72 22 5c 28  re.finditer(r"\(
25e0: 5c 3f 3a 5b 5e 29 5d 2a 5c 28 5b 5c 5b 5c 77 20  \?:[^)]*\([\[\w 
25f0: 2d 5d 22 2c 20 73 52 65 67 65 78 29 3a 0a 20 20  -]", sRegex):.  
2600: 20 20 20 20 20 20 70 72 69 6e 74 28 66 22 23 20        print(f"# 
2610: 57 61 72 6e 69 6e 67 3a 20 67 72 6f 75 70 73 20  Warning: groups 
2620: 69 6e 73 69 64 65 20 6e 6f 6e 20 67 72 6f 75 70  inside non group
2630: 69 6e 67 20 70 61 72 65 6e 74 68 65 73 69 73 20  ing parenthesis 
2640: 69 6e 20 72 65 67 65 78 20 61 74 20 6c 69 6e 65  in regex at line
2650: 20 7b 73 4c 69 6e 65 49 64 7d 22 29 0a 0a 20 20   {sLineId}")..  
2660: 20 20 23 23 23 23 20 50 41 52 53 45 20 41 43 54    #### PARSE ACT
2670: 49 4f 4e 53 0a 20 20 20 20 6c 41 63 74 69 6f 6e  IONS.    lAction
2680: 73 20 3d 20 5b 5d 0a 20 20 20 20 6e 41 63 74 69  s = [].    nActi
2690: 6f 6e 20 3d 20 31 0a 20 20 20 20 66 6f 72 20 73  on = 1.    for s
26a0: 41 63 74 69 6f 6e 20 69 6e 20 73 2e 73 70 6c 69  Action in s.spli
26b0: 74 28 22 20 3c 3c 2d 20 22 29 3a 0a 20 20 20 20  t(" <<- "):.    
26c0: 20 20 20 20 74 20 3d 20 63 72 65 61 74 65 41 63      t = createAc
26d0: 74 69 6f 6e 28 73 4c 69 6e 65 49 64 2c 20 73 52  tion(sLineId, sR
26e0: 75 6c 65 49 64 20 2b 20 22 5f 22 20 2b 20 73 74  uleId + "_" + st
26f0: 72 28 6e 41 63 74 69 6f 6e 29 2c 20 73 41 63 74  r(nAction), sAct
2700: 69 6f 6e 2c 20 6e 47 72 6f 75 70 29 0a 20 20 20  ion, nGroup).   
2710: 20 20 20 20 20 6e 41 63 74 69 6f 6e 20 2b 3d 20       nAction += 
2720: 31 0a 20 20 20 20 20 20 20 20 69 66 20 74 3a 0a  1.        if t:.
2730: 20 20 20 20 20 20 20 20 20 20 20 20 6c 41 63 74              lAct
2740: 69 6f 6e 73 2e 61 70 70 65 6e 64 28 74 29 0a 20  ions.append(t). 
2750: 20 20 20 69 66 20 6e 6f 74 20 6c 41 63 74 69 6f     if not lActio
2760: 6e 73 3a 0a 20 20 20 20 20 20 20 20 72 65 74 75  ns:.        retu
2770: 72 6e 20 4e 6f 6e 65 0a 0a 20 20 20 20 72 65 74  rn None..    ret
2780: 75 72 6e 20 5b 73 4f 70 74 69 6f 6e 2c 20 73 52  urn [sOption, sR
2790: 65 67 65 78 2c 20 62 43 61 73 65 49 6e 73 65 6e  egex, bCaseInsen
27a0: 73 69 74 69 76 65 2c 20 73 4c 69 6e 65 49 64 2c  sitive, sLineId,
27b0: 20 73 52 75 6c 65 49 64 2c 20 6e 50 72 69 6f 72   sRuleId, nPrior
27c0: 69 74 79 2c 20 6c 41 63 74 69 6f 6e 73 2c 20 74  ity, lActions, t
27d0: 47 72 6f 75 70 73 5d 0a 0a 0a 64 65 66 20 63 68  Groups]...def ch
27e0: 65 63 6b 52 65 66 65 72 65 6e 63 65 4e 75 6d 62  eckReferenceNumb
27f0: 65 72 73 20 28 73 54 65 78 74 2c 20 73 41 63 74  ers (sText, sAct
2800: 69 6f 6e 49 64 2c 20 6e 54 6f 6b 65 6e 29 3a 0a  ionId, nToken):.
2810: 20 20 20 20 22 63 68 65 63 6b 20 69 66 20 74 6f      "check if to
2820: 6b 65 6e 20 72 65 66 65 72 65 6e 63 65 73 20 69  ken references i
2830: 6e 20 3c 73 54 65 78 74 3e 20 67 72 65 61 74 65  n <sText> greate
2840: 72 20 74 68 61 6e 20 3c 6e 54 6f 6b 65 6e 3e 20  r than <nToken> 
2850: 28 64 65 62 75 67 67 69 6e 67 29 22 0a 20 20 20  (debugging)".   
2860: 20 66 6f 72 20 78 20 69 6e 20 72 65 2e 66 69 6e   for x in re.fin
2870: 64 69 74 65 72 28 72 22 5c 5c 28 5c 64 2b 29 22  diter(r"\\(\d+)"
2880: 2c 20 73 54 65 78 74 29 3a 0a 20 20 20 20 20 20  , sText):.      
2890: 20 20 69 66 20 69 6e 74 28 78 2e 67 72 6f 75 70    if int(x.group
28a0: 28 31 29 29 20 3e 20 6e 54 6f 6b 65 6e 3a 0a 20  (1)) > nToken:. 
28b0: 20 20 20 20 20 20 20 20 20 20 20 70 72 69 6e 74             print
28c0: 28 66 22 23 20 45 72 72 6f 72 20 69 6e 20 74 6f  (f"# Error in to
28d0: 6b 65 6e 20 69 6e 64 65 78 20 61 74 20 6c 69 6e  ken index at lin
28e0: 65 20 7b 73 4c 69 6e 65 49 64 7d 20 2f 20 7b 73  e {sLineId} / {s
28f0: 41 63 74 69 6f 6e 49 64 7d 20 28 7b 6e 54 6f 6b  ActionId} ({nTok
2900: 65 6e 7d 20 74 6f 6b 65 6e 73 20 6f 6e 6c 79 29  en} tokens only)
2910: 22 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 70  ").            p
2920: 72 69 6e 74 28 73 54 65 78 74 29 0a 0a 0a 64 65  rint(sText)...de
2930: 66 20 63 68 65 63 6b 49 66 54 68 65 72 65 49 73  f checkIfThereIs
2940: 43 6f 64 65 20 28 73 54 65 78 74 2c 20 73 4c 69  Code (sText, sLi
2950: 6e 65 49 64 2c 20 73 41 63 74 69 6f 6e 49 64 29  neId, sActionId)
2960: 3a 0a 20 20 20 20 22 63 68 65 63 6b 20 69 66 20  :.    "check if 
2970: 74 68 65 72 65 20 69 73 20 63 6f 64 65 20 69 6e  there is code in
2980: 20 3c 73 54 65 78 74 3e 20 28 64 65 62 75 67 67   <sText> (debugg
2990: 69 6e 67 29 22 0a 20 20 20 20 69 66 20 72 65 2e  ing)".    if re.
29a0: 73 65 61 72 63 68 28 72 22 5b 2e 5d 5c 77 2b 5b  search(r"[.]\w+[
29b0: 28 5d 7c 73 75 67 67 5c 77 2b 5b 28 5d 7c 5c 28  (]|sugg\w+[(]|\(
29c0: 5c 5c 5b 30 2d 39 5d 7c 5c 5b 28 3f 3a 5b 30 2d  \\[0-9]|\[(?:[0-
29d0: 39 5d 3a 7c 3a 29 22 2c 20 73 54 65 78 74 29 3a  9]:|:)", sText):
29e0: 0a 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 66  .        print(f
29f0: 22 23 20 57 61 72 6e 69 6e 67 20 61 74 20 6c 69  "# Warning at li
2a00: 6e 65 20 7b 73 4c 69 6e 65 49 64 7d 20 2f 20 7b  ne {sLineId} / {
2a10: 73 41 63 74 69 6f 6e 49 64 7d 3a 20 20 54 68 69  sActionId}:  Thi
2a20: 73 20 6d 65 73 73 61 67 65 20 6c 6f 6f 6b 73 20  s message looks 
2a30: 6c 69 6b 65 20 63 6f 64 65 2e 20 4c 69 6e 65 20  like code. Line 
2a40: 73 68 6f 75 6c 64 20 70 72 6f 62 61 62 6c 79 20  should probably 
2a50: 62 65 67 69 6e 20 77 69 74 68 20 3d 22 29 0a 20  begin with ="). 
2a60: 20 20 20 20 20 20 20 70 72 69 6e 74 28 73 54 65         print(sTe
2a70: 78 74 29 0a 0a 0a 64 65 66 20 63 72 65 61 74 65  xt)...def create
2a80: 41 63 74 69 6f 6e 20 28 73 4c 69 6e 65 49 64 2c  Action (sLineId,
2a90: 20 73 41 63 74 69 6f 6e 49 64 2c 20 73 41 63 74   sActionId, sAct
2aa0: 69 6f 6e 2c 20 6e 47 72 6f 75 70 29 3a 0a 20 20  ion, nGroup):.  
2ab0: 20 20 22 72 65 74 75 72 6e 73 20 61 6e 20 61 63    "returns an ac
2ac0: 74 69 6f 6e 20 74 6f 20 70 65 72 66 6f 72 6d 20  tion to perform 
2ad0: 61 73 20 61 20 74 75 70 6c 65 20 28 63 6f 6e 64  as a tuple (cond
2ae0: 69 74 69 6f 6e 2c 20 61 63 74 69 6f 6e 20 74 79  ition, action ty
2af0: 70 65 2c 20 61 63 74 69 6f 6e 5b 2c 20 69 47 72  pe, action[, iGr
2b00: 6f 75 70 20 5b 2c 20 6d 65 73 73 61 67 65 2c 20  oup [, message, 
2b10: 55 52 4c 20 5d 5d 29 22 0a 20 20 20 20 6d 20 3d  URL ]])".    m =
2b20: 20 72 65 2e 73 65 61 72 63 68 28 72 22 28 5b 2d   re.search(r"([-
2b30: 7e 3d 3e 5d 29 28 5c 64 2a 7c 29 3e 3e 22 2c 20  ~=>])(\d*|)>>", 
2b40: 73 41 63 74 69 6f 6e 29 0a 20 20 20 20 69 66 20  sAction).    if 
2b50: 6e 6f 74 20 6d 3a 0a 20 20 20 20 20 20 20 20 70  not m:.        p
2b60: 72 69 6e 74 28 66 22 23 20 4e 6f 20 61 63 74 69  rint(f"# No acti
2b70: 6f 6e 20 61 74 20 6c 69 6e 65 20 7b 73 4c 69 6e  on at line {sLin
2b80: 65 49 64 7d 20 2f 20 7b 73 41 63 74 69 6f 6e 49  eId} / {sActionI
2b90: 64 7d 22 29 0a 20 20 20 20 20 20 20 20 72 65 74  d}").        ret
2ba0: 75 72 6e 20 4e 6f 6e 65 0a 0a 20 20 20 20 23 23  urn None..    ##
2bb0: 23 23 20 43 4f 4e 44 49 54 49 4f 4e 0a 20 20 20  ## CONDITION.   
2bc0: 20 73 43 6f 6e 64 69 74 69 6f 6e 20 3d 20 73 41   sCondition = sA
2bd0: 63 74 69 6f 6e 5b 3a 6d 2e 73 74 61 72 74 28 29  ction[:m.start()
2be0: 5d 2e 73 74 72 69 70 28 29 0a 20 20 20 20 69 66  ].strip().    if
2bf0: 20 73 43 6f 6e 64 69 74 69 6f 6e 3a 0a 20 20 20   sCondition:.   
2c00: 20 20 20 20 20 73 43 6f 6e 64 69 74 69 6f 6e 20       sCondition 
2c10: 3d 20 70 72 65 70 61 72 65 46 75 6e 63 74 69 6f  = prepareFunctio
2c20: 6e 28 73 43 6f 6e 64 69 74 69 6f 6e 29 0a 20 20  n(sCondition).  
2c30: 20 20 20 20 20 20 6c 46 55 4e 43 54 49 4f 4e 53        lFUNCTIONS
2c40: 2e 61 70 70 65 6e 64 28 28 22 5f 63 5f 22 2b 73  .append(("_c_"+s
2c50: 41 63 74 69 6f 6e 49 64 2c 20 73 43 6f 6e 64 69  ActionId, sCondi
2c60: 74 69 6f 6e 29 29 0a 20 20 20 20 20 20 20 20 63  tion)).        c
2c70: 68 65 63 6b 52 65 66 65 72 65 6e 63 65 4e 75 6d  heckReferenceNum
2c80: 62 65 72 73 28 73 43 6f 6e 64 69 74 69 6f 6e 2c  bers(sCondition,
2c90: 20 73 41 63 74 69 6f 6e 49 64 2c 20 6e 47 72 6f   sActionId, nGro
2ca0: 75 70 29 0a 20 20 20 20 20 20 20 20 69 66 20 22  up).        if "
2cb0: 2e 6d 61 74 63 68 22 20 69 6e 20 73 43 6f 6e 64  .match" in sCond
2cc0: 69 74 69 6f 6e 3a 0a 20 20 20 20 20 20 20 20 20  ition:.         
2cd0: 20 20 20 70 72 69 6e 74 28 66 22 23 20 45 72 72     print(f"# Err
2ce0: 6f 72 20 61 74 20 6c 69 6e 65 20 7b 73 4c 69 6e  or at line {sLin
2cf0: 65 49 64 7d 20 2f 20 7b 73 41 63 74 69 6f 6e 49  eId} / {sActionI
2d00: 64 7d 2e 20 4a 53 20 63 6f 6d 70 61 74 69 62 69  d}. JS compatibi
2d10: 6c 69 74 79 2e 20 44 6f 6e 27 74 20 75 73 65 20  lity. Don't use 
2d20: 2e 6d 61 74 63 68 28 29 20 69 6e 20 63 6f 6e 64  .match() in cond
2d30: 69 74 69 6f 6e 2c 20 75 73 65 20 2e 73 65 61 72  ition, use .sear
2d40: 63 68 28 29 22 29 0a 20 20 20 20 20 20 20 20 73  ch()").        s
2d50: 43 6f 6e 64 69 74 69 6f 6e 20 3d 20 22 5f 63 5f  Condition = "_c_
2d60: 22 2b 73 41 63 74 69 6f 6e 49 64 0a 20 20 20 20  "+sActionId.    
2d70: 65 6c 73 65 3a 0a 20 20 20 20 20 20 20 20 73 43  else:.        sC
2d80: 6f 6e 64 69 74 69 6f 6e 20 3d 20 4e 6f 6e 65 0a  ondition = None.
2d90: 0a 20 20 20 20 23 23 23 23 20 69 47 72 6f 75 70  .    #### iGroup
2da0: 20 2f 20 70 6f 73 69 74 69 6f 6e 69 6e 67 0a 20   / positioning. 
2db0: 20 20 20 69 47 72 6f 75 70 20 3d 20 69 6e 74 28     iGroup = int(
2dc0: 6d 2e 67 72 6f 75 70 28 32 29 29 20 69 66 20 6d  m.group(2)) if m
2dd0: 2e 67 72 6f 75 70 28 32 29 20 65 6c 73 65 20 30  .group(2) else 0
2de0: 0a 20 20 20 20 69 66 20 69 47 72 6f 75 70 20 3e  .    if iGroup >
2df0: 20 6e 47 72 6f 75 70 3a 0a 20 20 20 20 20 20 20   nGroup:.       
2e00: 20 70 72 69 6e 74 28 66 22 23 20 45 72 72 6f 72   print(f"# Error
2e10: 2e 20 53 65 6c 65 63 74 65 64 20 67 72 6f 75 70  . Selected group
2e20: 20 3e 20 67 72 6f 75 70 20 6e 75 6d 62 65 72 20   > group number 
2e30: 69 6e 20 72 65 67 65 78 20 61 74 20 6c 69 6e 65  in regex at line
2e40: 20 7b 73 4c 69 6e 65 49 64 7d 20 2f 20 7b 73 41   {sLineId} / {sA
2e50: 63 74 69 6f 6e 49 64 7d 22 29 0a 0a 20 20 20 20  ctionId}")..    
2e60: 23 23 23 23 20 41 43 54 49 4f 4e 0a 20 20 20 20  #### ACTION.    
2e70: 73 41 63 74 69 6f 6e 20 3d 20 73 41 63 74 69 6f  sAction = sActio
2e80: 6e 5b 6d 2e 65 6e 64 28 29 3a 5d 2e 73 74 72 69  n[m.end():].stri
2e90: 70 28 29 0a 20 20 20 20 63 41 63 74 69 6f 6e 20  p().    cAction 
2ea0: 3d 20 6d 2e 67 72 6f 75 70 28 31 29 0a 20 20 20  = m.group(1).   
2eb0: 20 69 66 20 63 41 63 74 69 6f 6e 20 3d 3d 20 22   if cAction == "
2ec0: 2d 22 3a 0a 20 20 20 20 20 20 20 20 23 23 20 65  -":.        ## e
2ed0: 72 72 6f 72 0a 20 20 20 20 20 20 20 20 69 4d 73  rror.        iMs
2ee0: 67 20 3d 20 73 41 63 74 69 6f 6e 2e 66 69 6e 64  g = sAction.find
2ef0: 28 22 20 26 26 20 22 29 0a 20 20 20 20 20 20 20  (" && ").       
2f00: 20 69 66 20 69 4d 73 67 20 3d 3d 20 2d 31 3a 0a   if iMsg == -1:.
2f10: 20 20 20 20 20 20 20 20 20 20 20 20 73 4d 73 67              sMsg
2f20: 20 3d 20 22 23 20 45 72 72 6f 72 2e 20 45 72 72   = "# Error. Err
2f30: 6f 72 20 6d 65 73 73 61 67 65 20 6e 6f 74 20 66  or message not f
2f40: 6f 75 6e 64 2e 22 0a 20 20 20 20 20 20 20 20 20  ound.".         
2f50: 20 20 20 73 55 52 4c 20 3d 20 22 22 0a 20 20 20     sURL = "".   
2f60: 20 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 66           print(f
2f70: 22 23 20 4e 6f 20 6d 65 73 73 61 67 65 2e 20 49  "# No message. I
2f80: 64 3a 20 7b 73 4c 69 6e 65 49 64 7d 20 2f 20 7b  d: {sLineId} / {
2f90: 73 41 63 74 69 6f 6e 49 64 7d 22 29 0a 20 20 20  sActionId}").   
2fa0: 20 20 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20       else:.     
2fb0: 20 20 20 20 20 20 20 73 4d 73 67 20 3d 20 73 41         sMsg = sA
2fc0: 63 74 69 6f 6e 5b 69 4d 73 67 2b 34 3a 5d 2e 73  ction[iMsg+4:].s
2fd0: 74 72 69 70 28 29 0a 20 20 20 20 20 20 20 20 20  trip().         
2fe0: 20 20 20 73 41 63 74 69 6f 6e 20 3d 20 73 41 63     sAction = sAc
2ff0: 74 69 6f 6e 5b 3a 69 4d 73 67 5d 2e 73 74 72 69  tion[:iMsg].stri
3000: 70 28 29 0a 20 20 20 20 20 20 20 20 20 20 20 20  p().            
3010: 73 55 52 4c 20 3d 20 22 22 0a 20 20 20 20 20 20  sURL = "".      
3020: 20 20 20 20 20 20 6d 55 52 4c 20 3d 20 72 65 2e        mURL = re.
3030: 73 65 61 72 63 68 28 22 5b 7c 5d 20 2a 28 68 74  search("[|] *(ht
3040: 74 70 73 3f 3a 2f 2f 2e 2a 29 22 2c 20 73 4d 73  tps?://.*)", sMs
3050: 67 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 69  g).            i
3060: 66 20 6d 55 52 4c 3a 0a 20 20 20 20 20 20 20 20  f mURL:.        
3070: 20 20 20 20 20 20 20 20 73 55 52 4c 20 3d 20 6d          sURL = m
3080: 55 52 4c 2e 67 72 6f 75 70 28 31 29 2e 73 74 72  URL.group(1).str
3090: 69 70 28 29 0a 20 20 20 20 20 20 20 20 20 20 20  ip().           
30a0: 20 20 20 20 20 73 4d 73 67 20 3d 20 73 4d 73 67       sMsg = sMsg
30b0: 5b 3a 6d 55 52 4c 2e 73 74 61 72 74 28 30 29 5d  [:mURL.start(0)]
30c0: 2e 73 74 72 69 70 28 29 0a 20 20 20 20 20 20 20  .strip().       
30d0: 20 20 20 20 20 63 68 65 63 6b 52 65 66 65 72 65       checkRefere
30e0: 6e 63 65 4e 75 6d 62 65 72 73 28 73 4d 73 67 2c  nceNumbers(sMsg,
30f0: 20 73 41 63 74 69 6f 6e 49 64 2c 20 6e 47 72 6f   sActionId, nGro
3100: 75 70 29 0a 20 20 20 20 20 20 20 20 20 20 20 20  up).            
3110: 69 66 20 73 4d 73 67 5b 30 3a 31 5d 20 3d 3d 20  if sMsg[0:1] == 
3120: 22 3d 22 3a 0a 20 20 20 20 20 20 20 20 20 20 20  "=":.           
3130: 20 20 20 20 20 73 4d 73 67 20 3d 20 70 72 65 70       sMsg = prep
3140: 61 72 65 46 75 6e 63 74 69 6f 6e 28 73 4d 73 67  areFunction(sMsg
3150: 5b 31 3a 5d 29 0a 20 20 20 20 20 20 20 20 20 20  [1:]).          
3160: 20 20 20 20 20 20 6c 46 55 4e 43 54 49 4f 4e 53        lFUNCTIONS
3170: 2e 61 70 70 65 6e 64 28 28 22 5f 6d 5f 22 2b 73  .append(("_m_"+s
3180: 41 63 74 69 6f 6e 49 64 2c 20 73 4d 73 67 29 29  ActionId, sMsg))
3190: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
31a0: 20 73 4d 73 67 20 3d 20 22 3d 5f 6d 5f 22 2b 73   sMsg = "=_m_"+s
31b0: 41 63 74 69 6f 6e 49 64 0a 20 20 20 20 20 20 20  ActionId.       
31c0: 20 20 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20       else:.     
31d0: 20 20 20 20 20 20 20 20 20 20 20 63 68 65 63 6b             check
31e0: 49 66 54 68 65 72 65 49 73 43 6f 64 65 28 73 4d  IfThereIsCode(sM
31f0: 73 67 2c 20 73 4c 69 6e 65 49 64 2c 20 73 41 63  sg, sLineId, sAc
3200: 74 69 6f 6e 49 64 29 0a 0a 20 20 20 20 63 68 65  tionId)..    che
3210: 63 6b 52 65 66 65 72 65 6e 63 65 4e 75 6d 62 65  ckReferenceNumbe
3220: 72 73 28 73 41 63 74 69 6f 6e 2c 20 73 41 63 74  rs(sAction, sAct
3230: 69 6f 6e 49 64 2c 20 6e 47 72 6f 75 70 29 0a 20  ionId, nGroup). 
3240: 20 20 20 69 66 20 73 41 63 74 69 6f 6e 5b 30 3a     if sAction[0:
3250: 31 5d 20 3d 3d 20 22 3d 22 20 6f 72 20 63 41 63  1] == "=" or cAc
3260: 74 69 6f 6e 20 3d 3d 20 22 3d 22 3a 0a 20 20 20  tion == "=":.   
3270: 20 20 20 20 20 73 41 63 74 69 6f 6e 20 3d 20 70       sAction = p
3280: 72 65 70 61 72 65 46 75 6e 63 74 69 6f 6e 28 73  repareFunction(s
3290: 41 63 74 69 6f 6e 29 0a 20 20 20 20 20 20 20 20  Action).        
32a0: 73 41 63 74 69 6f 6e 20 3d 20 73 41 63 74 69 6f  sAction = sActio
32b0: 6e 2e 72 65 70 6c 61 63 65 28 22 6d 2e 67 72 6f  n.replace("m.gro
32c0: 75 70 28 69 5b 34 5d 29 22 2c 20 22 6d 2e 67 72  up(i[4])", "m.gr
32d0: 6f 75 70 28 22 2b 73 74 72 28 69 47 72 6f 75 70  oup("+str(iGroup
32e0: 29 2b 22 29 22 29 0a 20 20 20 20 65 6c 73 65 3a  )+")").    else:
32f0: 0a 20 20 20 20 20 20 20 20 63 68 65 63 6b 49 66  .        checkIf
3300: 54 68 65 72 65 49 73 43 6f 64 65 28 73 41 63 74  ThereIsCode(sAct
3310: 69 6f 6e 2c 20 73 4c 69 6e 65 49 64 2c 20 73 41  ion, sLineId, sA
3320: 63 74 69 6f 6e 49 64 29 0a 0a 20 20 20 20 69 66  ctionId)..    if
3330: 20 63 41 63 74 69 6f 6e 20 3d 3d 20 22 3e 22 3a   cAction == ">":
3340: 0a 20 20 20 20 20 20 20 20 23 23 20 6e 6f 20 61  .        ## no a
3350: 63 74 69 6f 6e 2c 20 62 72 65 61 6b 20 6c 6f 6f  ction, break loo
3360: 70 20 69 66 20 63 6f 6e 64 69 74 69 6f 6e 20 69  p if condition i
3370: 73 20 46 61 6c 73 65 0a 20 20 20 20 20 20 20 20  s False.        
3380: 72 65 74 75 72 6e 20 5b 73 43 6f 6e 64 69 74 69  return [sConditi
3390: 6f 6e 2c 20 63 41 63 74 69 6f 6e 2c 20 22 22 5d  on, cAction, ""]
33a0: 0a 0a 20 20 20 20 69 66 20 6e 6f 74 20 73 41 63  ..    if not sAc
33b0: 74 69 6f 6e 3a 0a 20 20 20 20 20 20 20 20 70 72  tion:.        pr
33c0: 69 6e 74 28 66 22 23 20 45 72 72 6f 72 20 69 6e  int(f"# Error in
33d0: 20 61 63 74 69 6f 6e 20 61 74 20 6c 69 6e 65 20   action at line 
33e0: 7b 73 4c 69 6e 65 49 64 7d 20 2f 20 7b 73 41 63  {sLineId} / {sAc
33f0: 74 69 6f 6e 49 64 7d 3a 20 20 54 68 69 73 20 61  tionId}:  This a
3400: 63 74 69 6f 6e 20 69 73 20 65 6d 70 74 79 2e 22  ction is empty."
3410: 29 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e  ).        return
3420: 20 4e 6f 6e 65 0a 0a 20 20 20 20 69 66 20 63 41   None..    if cA
3430: 63 74 69 6f 6e 20 3d 3d 20 22 2d 22 3a 0a 20 20  ction == "-":.  
3440: 20 20 20 20 20 20 23 23 20 65 72 72 6f 72 20 64        ## error d
3450: 65 74 65 63 74 65 64 20 2d 2d 3e 20 73 75 67 67  etected --> sugg
3460: 65 73 74 69 6f 6e 0a 20 20 20 20 20 20 20 20 69  estion.        i
3470: 66 20 73 41 63 74 69 6f 6e 5b 30 3a 31 5d 20 3d  f sAction[0:1] =
3480: 3d 20 22 3d 22 3a 0a 20 20 20 20 20 20 20 20 20  = "=":.         
3490: 20 20 20 6c 46 55 4e 43 54 49 4f 4e 53 2e 61 70     lFUNCTIONS.ap
34a0: 70 65 6e 64 28 28 22 5f 73 5f 22 2b 73 41 63 74  pend(("_s_"+sAct
34b0: 69 6f 6e 49 64 2c 20 73 41 63 74 69 6f 6e 5b 31  ionId, sAction[1
34c0: 3a 5d 29 29 0a 20 20 20 20 20 20 20 20 20 20 20  :])).           
34d0: 20 73 41 63 74 69 6f 6e 20 3d 20 22 3d 5f 73 5f   sAction = "=_s_
34e0: 22 2b 73 41 63 74 69 6f 6e 49 64 0a 20 20 20 20  "+sActionId.    
34f0: 20 20 20 20 65 6c 69 66 20 73 41 63 74 69 6f 6e      elif sAction
3500: 2e 73 74 61 72 74 73 77 69 74 68 28 27 22 27 29  .startswith('"')
3510: 20 61 6e 64 20 73 41 63 74 69 6f 6e 2e 65 6e 64   and sAction.end
3520: 73 77 69 74 68 28 27 22 27 29 3a 0a 20 20 20 20  swith('"'):.    
3530: 20 20 20 20 20 20 20 20 73 41 63 74 69 6f 6e 20          sAction 
3540: 3d 20 73 41 63 74 69 6f 6e 5b 31 3a 2d 31 5d 0a  = sAction[1:-1].
3550: 20 20 20 20 20 20 20 20 69 66 20 6e 6f 74 20 73          if not s
3560: 4d 73 67 3a 0a 20 20 20 20 20 20 20 20 20 20 20  Msg:.           
3570: 20 70 72 69 6e 74 28 66 22 23 20 45 72 72 6f 72   print(f"# Error
3580: 20 69 6e 20 61 63 74 69 6f 6e 20 61 74 20 6c 69   in action at li
3590: 6e 65 20 7b 73 4c 69 6e 65 49 64 7d 20 2f 20 7b  ne {sLineId} / {
35a0: 73 41 63 74 69 6f 6e 49 64 7d 3a 20 20 74 68 65  sActionId}:  the
35b0: 20 6d 65 73 73 61 67 65 20 69 73 20 65 6d 70 74   message is empt
35c0: 79 2e 22 29 0a 20 20 20 20 20 20 20 20 72 65 74  y.").        ret
35d0: 75 72 6e 20 5b 73 43 6f 6e 64 69 74 69 6f 6e 2c  urn [sCondition,
35e0: 20 63 41 63 74 69 6f 6e 2c 20 73 41 63 74 69 6f   cAction, sActio
35f0: 6e 2c 20 69 47 72 6f 75 70 2c 20 73 4d 73 67 2c  n, iGroup, sMsg,
3600: 20 73 55 52 4c 5d 0a 20 20 20 20 69 66 20 63 41   sURL].    if cA
3610: 63 74 69 6f 6e 20 3d 3d 20 22 7e 22 3a 0a 20 20  ction == "~":.  
3620: 20 20 20 20 20 20 23 23 20 74 65 78 74 20 70 72        ## text pr
3630: 6f 63 65 73 73 6f 72 0a 20 20 20 20 20 20 20 20  ocessor.        
3640: 69 66 20 73 41 63 74 69 6f 6e 5b 30 3a 31 5d 20  if sAction[0:1] 
3650: 3d 3d 20 22 3d 22 3a 0a 20 20 20 20 20 20 20 20  == "=":.        
3660: 20 20 20 20 6c 46 55 4e 43 54 49 4f 4e 53 2e 61      lFUNCTIONS.a
3670: 70 70 65 6e 64 28 28 22 5f 70 5f 22 2b 73 41 63  ppend(("_p_"+sAc
3680: 74 69 6f 6e 49 64 2c 20 73 41 63 74 69 6f 6e 5b  tionId, sAction[
3690: 31 3a 5d 29 29 0a 20 20 20 20 20 20 20 20 20 20  1:])).          
36a0: 20 20 73 41 63 74 69 6f 6e 20 3d 20 22 3d 5f 70    sAction = "=_p
36b0: 5f 22 2b 73 41 63 74 69 6f 6e 49 64 0a 20 20 20  _"+sActionId.   
36c0: 20 20 20 20 20 65 6c 69 66 20 73 41 63 74 69 6f       elif sActio
36d0: 6e 2e 73 74 61 72 74 73 77 69 74 68 28 27 22 27  n.startswith('"'
36e0: 29 20 61 6e 64 20 73 41 63 74 69 6f 6e 2e 65 6e  ) and sAction.en
36f0: 64 73 77 69 74 68 28 27 22 27 29 3a 0a 20 20 20  dswith('"'):.   
3700: 20 20 20 20 20 20 20 20 20 73 41 63 74 69 6f 6e           sAction
3710: 20 3d 20 73 41 63 74 69 6f 6e 5b 31 3a 2d 31 5d   = sAction[1:-1]
3720: 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20  .        return 
3730: 5b 73 43 6f 6e 64 69 74 69 6f 6e 2c 20 63 41 63  [sCondition, cAc
3740: 74 69 6f 6e 2c 20 73 41 63 74 69 6f 6e 2c 20 69  tion, sAction, i
3750: 47 72 6f 75 70 5d 0a 20 20 20 20 69 66 20 63 41  Group].    if cA
3760: 63 74 69 6f 6e 20 3d 3d 20 22 3d 22 3a 0a 20 20  ction == "=":.  
3770: 20 20 20 20 20 20 23 23 20 64 69 73 61 6d 62 69        ## disambi
3780: 67 75 61 74 6f 72 0a 20 20 20 20 20 20 20 20 69  guator.        i
3790: 66 20 73 41 63 74 69 6f 6e 5b 30 3a 31 5d 20 3d  f sAction[0:1] =
37a0: 3d 20 22 3d 22 3a 0a 20 20 20 20 20 20 20 20 20  = "=":.         
37b0: 20 20 20 73 41 63 74 69 6f 6e 20 3d 20 73 41 63     sAction = sAc
37c0: 74 69 6f 6e 5b 31 3a 5d 0a 20 20 20 20 20 20 20  tion[1:].       
37d0: 20 6c 46 55 4e 43 54 49 4f 4e 53 2e 61 70 70 65   lFUNCTIONS.appe
37e0: 6e 64 28 28 22 5f 64 5f 22 2b 73 41 63 74 69 6f  nd(("_d_"+sActio
37f0: 6e 49 64 2c 20 73 41 63 74 69 6f 6e 29 29 0a 20  nId, sAction)). 
3800: 20 20 20 20 20 20 20 73 41 63 74 69 6f 6e 20 3d         sAction =
3810: 20 22 5f 64 5f 22 2b 73 41 63 74 69 6f 6e 49 64   "_d_"+sActionId
3820: 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e 20  .        return 
3830: 5b 73 43 6f 6e 64 69 74 69 6f 6e 2c 20 63 41 63  [sCondition, cAc
3840: 74 69 6f 6e 2c 20 73 41 63 74 69 6f 6e 5d 0a 20  tion, sAction]. 
3850: 20 20 20 70 72 69 6e 74 28 66 22 23 20 55 6e 6b     print(f"# Unk
3860: 6e 6f 77 6e 20 61 63 74 69 6f 6e 20 61 74 20 6c  nown action at l
3870: 69 6e 65 20 7b 73 4c 69 6e 65 49 64 7d 20 2f 20  ine {sLineId} / 
3880: 7b 73 41 63 74 69 6f 6e 49 64 7d 22 29 0a 20 20  {sActionId}").  
3890: 20 20 72 65 74 75 72 6e 20 4e 6f 6e 65 0a 0a 0a    return None...
38a0: 64 65 66 20 5f 63 61 6c 63 52 75 6c 65 73 53 74  def _calcRulesSt
38b0: 61 74 73 20 28 6c 52 75 6c 65 73 29 3a 0a 20 20  ats (lRules):.  
38c0: 20 20 22 63 6f 75 6e 74 20 72 75 6c 65 73 20 61    "count rules a
38d0: 6e 64 20 61 63 74 69 6f 6e 73 22 0a 20 20 20 20  nd actions".    
38e0: 64 20 3d 20 7b 27 3d 27 3a 30 2c 20 27 7e 27 3a  d = {'=':0, '~':
38f0: 20 30 2c 20 27 2d 27 3a 20 30 2c 20 27 3e 27 3a   0, '-': 0, '>':
3900: 20 30 7d 0a 20 20 20 20 66 6f 72 20 61 52 75 6c   0}.    for aRul
3910: 65 20 69 6e 20 6c 52 75 6c 65 73 3a 0a 20 20 20  e in lRules:.   
3920: 20 20 20 20 20 69 66 20 61 52 75 6c 65 5b 30 5d       if aRule[0]
3930: 20 21 3d 20 22 40 40 40 40 22 3a 0a 20 20 20 20   != "@@@@":.    
3940: 20 20 20 20 20 20 20 20 66 6f 72 20 61 41 63 74          for aAct
3950: 69 6f 6e 20 69 6e 20 61 52 75 6c 65 5b 36 5d 3a  ion in aRule[6]:
3960: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
3970: 20 64 5b 61 41 63 74 69 6f 6e 5b 31 5d 5d 20 3d   d[aAction[1]] =
3980: 20 64 5b 61 41 63 74 69 6f 6e 5b 31 5d 5d 20 2b   d[aAction[1]] +
3990: 20 31 0a 20 20 20 20 72 65 74 75 72 6e 20 28 64   1.    return (d
39a0: 2c 20 6c 65 6e 28 6c 52 75 6c 65 73 29 29 0a 0a  , len(lRules))..
39b0: 0a 64 65 66 20 64 69 73 70 6c 61 79 53 74 61 74  .def displayStat
39c0: 73 20 28 6c 50 61 72 61 67 72 61 70 68 52 75 6c  s (lParagraphRul
39d0: 65 73 2c 20 6c 53 65 6e 74 65 6e 63 65 52 75 6c  es, lSentenceRul
39e0: 65 73 29 3a 0a 20 20 20 20 22 64 69 73 70 6c 61  es):.    "displa
39f0: 79 20 72 75 6c 65 73 20 6e 75 6d 62 65 72 73 22  y rules numbers"
3a00: 0a 20 20 20 20 70 72 69 6e 74 28 22 20 20 20 20  .    print("    
3a10: 20 20 20 20 20 20 20 20 20 20 20 7b 3a 3e 31 38             {:>18
3a20: 7d 20 7b 3a 3e 31 38 7d 20 7b 3a 3e 31 38 7d 20  } {:>18} {:>18} 
3a30: 7b 3a 3e 31 38 7d 22 2e 66 6f 72 6d 61 74 28 22  {:>18}".format("
3a40: 44 49 53 41 4d 42 49 47 55 41 54 4f 52 22 2c 20  DISAMBIGUATOR", 
3a50: 22 54 45 58 54 20 50 52 4f 43 45 53 53 4f 52 22  "TEXT PROCESSOR"
3a60: 2c 20 22 47 52 41 4d 4d 41 52 20 43 48 45 43 4b  , "GRAMMAR CHECK
3a70: 49 4e 47 22 2c 20 22 52 45 47 45 58 22 29 29 0a  ING", "REGEX")).
3a80: 20 20 20 20 64 2c 20 6e 52 75 6c 65 20 3d 20 5f      d, nRule = _
3a90: 63 61 6c 63 52 75 6c 65 73 53 74 61 74 73 28 6c  calcRulesStats(l
3aa0: 50 61 72 61 67 72 61 70 68 52 75 6c 65 73 29 0a  ParagraphRules).
3ab0: 20 20 20 20 70 72 69 6e 74 28 22 20 20 20 20 70      print("    p
3ac0: 61 72 61 67 72 61 70 68 3a 20 7b 3a 3e 31 30 7d  aragraph: {:>10}
3ad0: 20 61 63 74 69 6f 6e 73 20 7b 3a 3e 31 30 7d 20   actions {:>10} 
3ae0: 61 63 74 69 6f 6e 73 20 7b 3a 3e 31 30 7d 20 61  actions {:>10} a
3af0: 63 74 69 6f 6e 73 20 20 69 6e 20 7b 3a 3e 38 7d  ctions  in {:>8}
3b00: 20 72 75 6c 65 73 22 2e 66 6f 72 6d 61 74 28 64   rules".format(d
3b10: 5b 27 3d 27 5d 2c 20 64 5b 27 7e 27 5d 2c 20 64  ['='], d['~'], d
3b20: 5b 27 2d 27 5d 2c 20 6e 52 75 6c 65 29 29 0a 20  ['-'], nRule)). 
3b30: 20 20 20 64 2c 20 6e 52 75 6c 65 20 3d 20 5f 63     d, nRule = _c
3b40: 61 6c 63 52 75 6c 65 73 53 74 61 74 73 28 6c 53  alcRulesStats(lS
3b50: 65 6e 74 65 6e 63 65 52 75 6c 65 73 29 0a 20 20  entenceRules).  
3b60: 20 20 70 72 69 6e 74 28 22 20 20 20 20 73 65 6e    print("    sen
3b70: 74 65 6e 63 65 3a 20 20 7b 3a 3e 31 30 7d 20 61  tence:  {:>10} a
3b80: 63 74 69 6f 6e 73 20 7b 3a 3e 31 30 7d 20 61 63  ctions {:>10} ac
3b90: 74 69 6f 6e 73 20 7b 3a 3e 31 30 7d 20 61 63 74  tions {:>10} act
3ba0: 69 6f 6e 73 20 20 69 6e 20 7b 3a 3e 38 7d 20 72  ions  in {:>8} r
3bb0: 75 6c 65 73 22 2e 66 6f 72 6d 61 74 28 64 5b 27  ules".format(d['
3bc0: 3d 27 5d 2c 20 64 5b 27 7e 27 5d 2c 20 64 5b 27  ='], d['~'], d['
3bd0: 2d 27 5d 2c 20 6e 52 75 6c 65 29 29 0a 0a 0a 64  -'], nRule))...d
3be0: 65 66 20 6d 65 72 67 65 52 75 6c 65 73 42 79 4f  ef mergeRulesByO
3bf0: 70 74 69 6f 6e 20 28 6c 52 75 6c 65 73 29 3a 0a  ption (lRules):.
3c00: 20 20 20 20 22 72 65 74 75 72 6e 73 20 61 20 6c      "returns a l
3c10: 69 73 74 20 6f 66 20 74 75 70 6c 65 73 20 5b 6f  ist of tuples [o
3c20: 70 74 69 6f 6e 2c 20 6c 69 73 74 20 6f 66 20 72  ption, list of r
3c30: 75 6c 65 73 5d 20 6b 65 65 70 69 6e 67 20 74 68  ules] keeping th
3c40: 65 20 72 75 6c 65 73 20 6f 72 64 65 72 22 0a 20  e rules order". 
3c50: 20 20 20 6c 46 69 6e 61 6c 20 3d 20 5b 5d 0a 20     lFinal = []. 
3c60: 20 20 20 6c 54 65 6d 70 20 3d 20 5b 5d 0a 20 20     lTemp = [].  
3c70: 20 20 73 4f 70 74 69 6f 6e 20 3d 20 4e 6f 6e 65    sOption = None
3c80: 0a 20 20 20 20 66 6f 72 20 61 52 75 6c 65 20 69  .    for aRule i
3c90: 6e 20 6c 52 75 6c 65 73 3a 0a 20 20 20 20 20 20  n lRules:.      
3ca0: 20 20 69 66 20 61 52 75 6c 65 5b 30 5d 20 21 3d    if aRule[0] !=
3cb0: 20 73 4f 70 74 69 6f 6e 3a 0a 20 20 20 20 20 20   sOption:.      
3cc0: 20 20 20 20 20 20 69 66 20 73 4f 70 74 69 6f 6e        if sOption
3cd0: 20 69 73 20 6e 6f 74 20 4e 6f 6e 65 3a 0a 20 20   is not None:.  
3ce0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 6c 46                lF
3cf0: 69 6e 61 6c 2e 61 70 70 65 6e 64 28 5b 73 4f 70  inal.append([sOp
3d00: 74 69 6f 6e 2c 20 6c 54 65 6d 70 5d 29 0a 20 20  tion, lTemp]).  
3d10: 20 20 20 20 20 20 20 20 20 20 23 20 6e 65 77 20            # new 
3d20: 74 75 70 6c 65 0a 20 20 20 20 20 20 20 20 20 20  tuple.          
3d30: 20 20 73 4f 70 74 69 6f 6e 20 3d 20 61 52 75 6c    sOption = aRul
3d40: 65 5b 30 5d 0a 20 20 20 20 20 20 20 20 20 20 20  e[0].           
3d50: 20 6c 54 65 6d 70 20 3d 20 5b 5d 0a 20 20 20 20   lTemp = [].    
3d60: 20 20 20 20 6c 54 65 6d 70 2e 61 70 70 65 6e 64      lTemp.append
3d70: 28 61 52 75 6c 65 5b 31 3a 5d 29 0a 20 20 20 20  (aRule[1:]).    
3d80: 6c 46 69 6e 61 6c 2e 61 70 70 65 6e 64 28 5b 73  lFinal.append([s
3d90: 4f 70 74 69 6f 6e 2c 20 6c 54 65 6d 70 5d 29 0a  Option, lTemp]).
3da0: 20 20 20 20 72 65 74 75 72 6e 20 6c 46 69 6e 61      return lFina
3db0: 6c 0a 0a 0a 64 65 66 20 63 72 65 61 74 65 52 75  l...def createRu
3dc0: 6c 65 73 41 73 53 74 72 69 6e 67 20 28 6c 52 75  lesAsString (lRu
3dd0: 6c 65 73 29 3a 0a 20 20 20 20 22 63 72 65 61 74  les):.    "creat
3de0: 65 20 72 75 6c 65 73 20 61 73 20 61 20 73 74 72  e rules as a str
3df0: 69 6e 67 20 6f 66 20 61 72 72 61 79 73 20 28 74  ing of arrays (t
3e00: 6f 20 62 65 20 62 75 6e 64 6c 65 64 20 69 6e 20  o be bundled in 
3e10: 61 20 4a 53 4f 4e 20 73 74 72 69 6e 67 29 22 0a  a JSON string)".
3e20: 20 20 20 20 73 41 72 72 61 79 20 3d 20 22 5b 5c      sArray = "[\
3e30: 6e 22 0a 20 20 20 20 66 6f 72 20 73 4f 70 74 69  n".    for sOpti
3e40: 6f 6e 2c 20 61 52 75 6c 65 47 72 6f 75 70 20 69  on, aRuleGroup i
3e50: 6e 20 6c 52 75 6c 65 73 3a 0a 20 20 20 20 20 20  n lRules:.      
3e60: 20 20 73 41 72 72 61 79 20 2b 3d 20 66 27 20 20    sArray += f'  
3e70: 5b 22 7b 73 4f 70 74 69 6f 6e 7d 22 2c 20 5b 5c  ["{sOption}", [\
3e80: 6e 27 0a 20 20 20 20 20 20 20 20 66 6f 72 20 61  n'.        for a
3e90: 52 75 6c 65 20 69 6e 20 61 52 75 6c 65 47 72 6f  Rule in aRuleGro
3ea0: 75 70 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20  up:.            
3eb0: 73 41 72 72 61 79 20 2b 3d 20 66 27 20 20 20 20  sArray += f'    
3ec0: 7b 61 52 75 6c 65 7d 2c 5c 6e 27 0a 20 20 20 20  {aRule},\n'.    
3ed0: 20 20 20 20 73 41 72 72 61 79 20 2b 3d 20 22 20      sArray += " 
3ee0: 20 5d 5d 2c 5c 6e 22 0a 20 20 20 20 73 41 72 72   ]],\n".    sArr
3ef0: 61 79 20 2b 3d 20 22 5d 22 0a 20 20 20 20 72 65  ay += "]".    re
3f00: 74 75 72 6e 20 73 41 72 72 61 79 0a 0a 0a 64 65  turn sArray...de
3f10: 66 20 70 72 65 70 61 72 65 4f 70 74 69 6f 6e 73  f prepareOptions
3f20: 20 28 6c 4f 70 74 69 6f 6e 4c 69 6e 65 73 29 3a   (lOptionLines):
3f30: 0a 20 20 20 20 22 72 65 74 75 72 6e 73 20 61 20  .    "returns a 
3f40: 64 69 63 74 69 6f 6e 61 72 79 20 77 69 74 68 20  dictionary with 
3f50: 64 61 74 61 20 61 62 6f 75 74 20 6f 70 74 69 6f  data about optio
3f60: 6e 73 22 0a 20 20 20 20 73 4c 61 6e 67 20 3d 20  ns".    sLang = 
3f70: 22 22 0a 20 20 20 20 73 44 65 66 61 75 6c 74 55  "".    sDefaultU
3f80: 49 4c 61 6e 67 20 3d 20 22 22 0a 20 20 20 20 6c  ILang = "".    l
3f90: 53 74 72 75 63 74 4f 70 74 20 3d 20 5b 5d 0a 20  StructOpt = []. 
3fa0: 20 20 20 6c 4f 70 74 20 3d 20 5b 5d 0a 20 20 20     lOpt = [].   
3fb0: 20 6c 4f 70 74 43 6f 6c 6f 72 20 3d 20 5b 5d 0a   lOptColor = [].
3fc0: 20 20 20 20 64 43 6f 6c 6f 72 20 3d 20 7b 7d 0a      dColor = {}.
3fd0: 20 20 20 20 64 4f 70 74 4c 61 62 65 6c 20 3d 20      dOptLabel = 
3fe0: 7b 7d 0a 20 20 20 20 64 4f 70 74 50 72 69 6f 72  {}.    dOptPrior
3ff0: 69 74 79 20 3d 20 7b 7d 0a 20 20 20 20 66 6f 72  ity = {}.    for
4000: 20 73 4c 69 6e 65 20 69 6e 20 6c 4f 70 74 69 6f   sLine in lOptio
4010: 6e 4c 69 6e 65 73 3a 0a 20 20 20 20 20 20 20 20  nLines:.        
4020: 73 4c 69 6e 65 20 3d 20 73 4c 69 6e 65 2e 73 74  sLine = sLine.st
4030: 72 69 70 28 29 0a 20 20 20 20 20 20 20 20 69 66  rip().        if
4040: 20 73 4c 69 6e 65 2e 73 74 61 72 74 73 77 69 74   sLine.startswit
4050: 68 28 22 4f 50 54 47 52 4f 55 50 2f 22 29 3a 0a  h("OPTGROUP/"):.
4060: 20 20 20 20 20 20 20 20 20 20 20 20 6d 20 3d 20              m = 
4070: 72 65 2e 6d 61 74 63 68 28 22 4f 50 54 47 52 4f  re.match("OPTGRO
4080: 55 50 2f 28 5b 61 2d 7a 30 2d 39 5d 2b 29 3a 28  UP/([a-z0-9]+):(
4090: 2e 2b 29 24 22 2c 20 73 4c 69 6e 65 29 0a 20 20  .+)$", sLine).  
40a0: 20 20 20 20 20 20 20 20 20 20 6c 53 74 72 75 63            lStruc
40b0: 74 4f 70 74 2e 61 70 70 65 6e 64 28 20 5b 6d 2e  tOpt.append( [m.
40c0: 67 72 6f 75 70 28 31 29 2c 20 6c 69 73 74 28 6d  group(1), list(m
40d0: 61 70 28 73 74 72 2e 73 70 6c 69 74 2c 20 6d 2e  ap(str.split, m.
40e0: 67 72 6f 75 70 28 32 29 2e 73 70 6c 69 74 28 22  group(2).split("
40f0: 2c 22 29 29 29 5d 20 29 0a 20 20 20 20 20 20 20  ,")))] ).       
4100: 20 65 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61 72   elif sLine.star
4110: 74 73 77 69 74 68 28 22 4f 50 54 53 4f 46 54 57  tswith("OPTSOFTW
4120: 41 52 45 3a 22 29 3a 0a 20 20 20 20 20 20 20 20  ARE:"):.        
4130: 20 20 20 20 6c 4f 70 74 20 3d 20 5b 20 5b 73 2c      lOpt = [ [s,
4140: 20 7b 7d 5d 20 20 66 6f 72 20 73 20 69 6e 20 73   {}]  for s in s
4150: 4c 69 6e 65 5b 31 32 3a 5d 2e 73 74 72 69 70 28  Line[12:].strip(
4160: 29 2e 73 70 6c 69 74 28 29 20 5d 20 20 23 20 64  ).split() ]  # d
4170: 6f 6e e2 80 99 74 20 75 73 65 20 74 75 70 6c 65  on...t use tuple
4180: 73 20 28 73 2c 20 7b 7d 29 2c 20 62 65 63 61 75  s (s, {}), becau
4190: 73 65 20 75 6e 6b 6e 6f 77 6e 20 74 6f 20 4a 53  se unknown to JS
41a0: 0a 20 20 20 20 20 20 20 20 65 6c 69 66 20 73 4c  .        elif sL
41b0: 69 6e 65 2e 73 74 61 72 74 73 77 69 74 68 28 22  ine.startswith("
41c0: 4f 50 54 2f 22 29 3a 0a 20 20 20 20 20 20 20 20  OPT/"):.        
41d0: 20 20 20 20 6d 20 3d 20 72 65 2e 6d 61 74 63 68      m = re.match
41e0: 28 22 4f 50 54 2f 28 5b 61 2d 7a 30 2d 39 5d 2b  ("OPT/([a-z0-9]+
41f0: 29 3a 28 2e 2b 29 24 22 2c 20 73 4c 69 6e 65 29  ):(.+)$", sLine)
4200: 0a 20 20 20 20 20 20 20 20 20 20 20 20 66 6f 72  .            for
4210: 20 69 2c 20 73 4f 70 74 20 69 6e 20 65 6e 75 6d   i, sOpt in enum
4220: 65 72 61 74 65 28 6d 2e 67 72 6f 75 70 28 32 29  erate(m.group(2)
4230: 2e 73 70 6c 69 74 28 29 29 3a 0a 20 20 20 20 20  .split()):.     
4240: 20 20 20 20 20 20 20 20 20 20 20 6c 4f 70 74 5b             lOpt[
4250: 69 5d 5b 31 5d 5b 6d 2e 67 72 6f 75 70 28 31 29  i][1][m.group(1)
4260: 5d 20 3d 20 73 4f 70 74 20 69 6e 20 28 22 54 72  ] = sOpt in ("Tr
4270: 75 65 22 2c 20 22 74 72 75 65 22 2c 20 22 59 65  ue", "true", "Ye
4280: 73 22 2c 20 22 79 65 73 22 29 0a 20 20 20 20 20  s", "yes").     
4290: 20 20 20 65 6c 69 66 20 73 4c 69 6e 65 2e 73 74     elif sLine.st
42a0: 61 72 74 73 77 69 74 68 28 22 4f 50 54 43 4f 4c  artswith("OPTCOL
42b0: 4f 52 54 48 45 4d 45 3a 22 29 3a 0a 20 20 20 20  ORTHEME:"):.    
42c0: 20 20 20 20 20 20 20 20 6c 4f 70 74 43 6f 6c 6f          lOptColo
42d0: 72 20 3d 20 5b 20 5b 73 2c 20 7b 7d 5d 20 20 66  r = [ [s, {}]  f
42e0: 6f 72 20 73 20 69 6e 20 73 4c 69 6e 65 5b 31 34  or s in sLine[14
42f0: 3a 5d 2e 73 74 72 69 70 28 29 2e 73 70 6c 69 74  :].strip().split
4300: 28 29 20 5d 20 20 23 20 64 6f 6e e2 80 99 74 20  () ]  # don...t 
4310: 75 73 65 20 74 75 70 6c 65 73 20 28 73 2c 20 7b  use tuples (s, {
4320: 7d 29 2c 20 62 65 63 61 75 73 65 20 75 6e 6b 6e  }), because unkn
4330: 6f 77 6e 20 74 6f 20 4a 53 0a 20 20 20 20 20 20  own to JS.      
4340: 20 20 65 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61    elif sLine.sta
4350: 72 74 73 77 69 74 68 28 22 4f 50 54 43 4f 4c 4f  rtswith("OPTCOLO
4360: 52 2f 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20  R/"):.          
4370: 20 20 6d 20 3d 20 72 65 2e 6d 61 74 63 68 28 22    m = re.match("
4380: 4f 50 54 43 4f 4c 4f 52 2f 28 5b 61 2d 7a 30 2d  OPTCOLOR/([a-z0-
4390: 39 5d 2b 29 3a 28 2e 2b 29 24 22 2c 20 73 4c 69  9]+):(.+)$", sLi
43a0: 6e 65 29 0a 20 20 20 20 20 20 20 20 20 20 20 20  ne).            
43b0: 66 6f 72 20 69 2c 20 73 43 6f 6c 6f 72 20 69 6e  for i, sColor in
43c0: 20 65 6e 75 6d 65 72 61 74 65 28 6d 2e 67 72 6f   enumerate(m.gro
43d0: 75 70 28 32 29 2e 73 70 6c 69 74 28 29 29 3a 0a  up(2).split()):.
43e0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
43f0: 6c 4f 70 74 43 6f 6c 6f 72 5b 69 5d 5b 31 5d 5b  lOptColor[i][1][
4400: 6d 2e 67 72 6f 75 70 28 31 29 5d 20 3d 20 73 43  m.group(1)] = sC
4410: 6f 6c 6f 72 0a 20 20 20 20 20 20 20 20 65 6c 69  olor.        eli
4420: 66 20 73 4c 69 6e 65 2e 73 74 61 72 74 73 77 69  f sLine.startswi
4430: 74 68 28 22 43 4f 4c 4f 52 2f 22 29 3a 0a 20 20  th("COLOR/"):.  
4440: 20 20 20 20 20 20 20 20 20 20 6d 20 3d 20 72 65            m = re
4450: 2e 6d 61 74 63 68 28 22 43 4f 4c 4f 52 2f 28 5b  .match("COLOR/([
4460: 61 2d 7a 41 2d 5a 30 2d 39 5f 5d 2b 29 3a 28 2e  a-zA-Z0-9_]+):(.
4470: 2b 29 24 22 2c 20 73 4c 69 6e 65 29 0a 20 20 20  +)$", sLine).   
4480: 20 20 20 20 20 20 20 20 20 64 43 6f 6c 6f 72 5b           dColor[
4490: 6d 2e 67 72 6f 75 70 28 31 29 5d 20 3d 20 5b 20  m.group(1)] = [ 
44a0: 69 6e 74 28 73 29 20 66 6f 72 20 73 20 69 6e 20  int(s) for s in 
44b0: 6d 2e 67 72 6f 75 70 28 32 29 2e 73 74 72 69 70  m.group(2).strip
44c0: 28 29 2e 73 70 6c 69 74 28 22 2c 22 29 20 5d 0a  ().split(",") ].
44d0: 20 20 20 20 20 20 20 20 65 6c 69 66 20 73 4c 69          elif sLi
44e0: 6e 65 2e 73 74 61 72 74 73 77 69 74 68 28 22 4f  ne.startswith("O
44f0: 50 54 50 52 49 4f 52 49 54 59 2f 22 29 3a 0a 20  PTPRIORITY/"):. 
4500: 20 20 20 20 20 20 20 20 20 20 20 6d 20 3d 20 72             m = r
4510: 65 2e 6d 61 74 63 68 28 22 4f 50 54 50 52 49 4f  e.match("OPTPRIO
4520: 52 49 54 59 2f 28 5b 61 2d 7a 30 2d 39 5d 2b 29  RITY/([a-z0-9]+)
4530: 3a 20 2a 28 5b 30 2d 39 5d 29 24 22 2c 20 73 4c  : *([0-9])$", sL
4540: 69 6e 65 29 0a 20 20 20 20 20 20 20 20 20 20 20  ine).           
4550: 20 64 4f 70 74 50 72 69 6f 72 69 74 79 5b 6d 2e   dOptPriority[m.
4560: 67 72 6f 75 70 28 31 29 5d 20 3d 20 69 6e 74 28  group(1)] = int(
4570: 6d 2e 67 72 6f 75 70 28 32 29 29 0a 20 20 20 20  m.group(2)).    
4580: 20 20 20 20 65 6c 69 66 20 73 4c 69 6e 65 2e 73      elif sLine.s
4590: 74 61 72 74 73 77 69 74 68 28 22 4f 50 54 4c 41  tartswith("OPTLA
45a0: 4e 47 2f 22 29 3a 0a 20 20 20 20 20 20 20 20 20  NG/"):.         
45b0: 20 20 20 6d 20 3d 20 72 65 2e 6d 61 74 63 68 28     m = re.match(
45c0: 22 4f 50 54 4c 41 4e 47 2f 28 5b 61 2d 7a 5d 5b  "OPTLANG/([a-z][
45d0: 61 2d 7a 5d 28 3f 3a 5f 5b 41 2d 5a 5d 5b 41 2d  a-z](?:_[A-Z][A-
45e0: 5a 5d 7c 29 29 3a 28 2e 2b 29 24 22 2c 20 73 4c  Z]|)):(.+)$", sL
45f0: 69 6e 65 29 0a 20 20 20 20 20 20 20 20 20 20 20  ine).           
4600: 20 73 4c 61 6e 67 20 3d 20 6d 2e 67 72 6f 75 70   sLang = m.group
4610: 28 31 29 5b 3a 32 5d 0a 20 20 20 20 20 20 20 20  (1)[:2].        
4620: 20 20 20 20 64 4f 70 74 4c 61 62 65 6c 5b 73 4c      dOptLabel[sL
4630: 61 6e 67 5d 20 3d 20 7b 20 22 5f 5f 6f 70 74 69  ang] = { "__opti
4640: 6f 6e 74 69 74 6c 65 5f 5f 22 3a 20 6d 2e 67 72  ontitle__": m.gr
4650: 6f 75 70 28 32 29 2e 73 74 72 69 70 28 29 20 7d  oup(2).strip() }
4660: 0a 20 20 20 20 20 20 20 20 65 6c 69 66 20 73 4c  .        elif sL
4670: 69 6e 65 2e 73 74 61 72 74 73 77 69 74 68 28 22  ine.startswith("
4680: 4f 50 54 44 45 46 41 55 4c 54 55 49 4c 41 4e 47  OPTDEFAULTUILANG
4690: 3a 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20 20  :"):.           
46a0: 20 6d 20 3d 20 72 65 2e 6d 61 74 63 68 28 22 4f   m = re.match("O
46b0: 50 54 44 45 46 41 55 4c 54 55 49 4c 41 4e 47 3a  PTDEFAULTUILANG:
46c0: 20 2a 28 5b 61 2d 7a 5d 5b 61 2d 7a 5d 28 3f 3a   *([a-z][a-z](?:
46d0: 5f 5b 41 2d 5a 5d 5b 41 2d 5a 5d 7c 29 29 24 22  _[A-Z][A-Z]|))$"
46e0: 2c 20 73 4c 69 6e 65 29 0a 20 20 20 20 20 20 20  , sLine).       
46f0: 20 20 20 20 20 73 44 65 66 61 75 6c 74 55 49 4c       sDefaultUIL
4700: 61 6e 67 20 3d 20 6d 2e 67 72 6f 75 70 28 31 29  ang = m.group(1)
4710: 5b 3a 32 5d 0a 20 20 20 20 20 20 20 20 65 6c 69  [:2].        eli
4720: 66 20 73 4c 69 6e 65 2e 73 74 61 72 74 73 77 69  f sLine.startswi
4730: 74 68 28 22 4f 50 54 4c 41 42 45 4c 2f 22 29 3a  th("OPTLABEL/"):
4740: 0a 20 20 20 20 20 20 20 20 20 20 20 20 6d 20 3d  .            m =
4750: 20 72 65 2e 6d 61 74 63 68 28 22 4f 50 54 4c 41   re.match("OPTLA
4760: 42 45 4c 2f 28 5b 61 2d 7a 30 2d 39 5d 2b 29 3a  BEL/([a-z0-9]+):
4770: 28 2e 2b 29 24 22 2c 20 73 4c 69 6e 65 29 0a 20  (.+)$", sLine). 
4780: 20 20 20 20 20 20 20 20 20 20 20 64 4f 70 74 4c             dOptL
4790: 61 62 65 6c 5b 73 4c 61 6e 67 5d 5b 6d 2e 67 72  abel[sLang][m.gr
47a0: 6f 75 70 28 31 29 5d 20 3d 20 6c 69 73 74 28 6d  oup(1)] = list(m
47b0: 61 70 28 73 74 72 2e 73 74 72 69 70 2c 20 6d 2e  ap(str.strip, m.
47c0: 67 72 6f 75 70 28 32 29 2e 73 70 6c 69 74 28 22  group(2).split("
47d0: 7c 22 29 29 29 20 20 69 66 20 22 7c 22 20 69 6e  |")))  if "|" in
47e0: 20 6d 2e 67 72 6f 75 70 28 32 29 20 20 65 6c 73   m.group(2)  els
47f0: 65 20 20 5b 6d 2e 67 72 6f 75 70 28 32 29 2e 73  e  [m.group(2).s
4800: 74 72 69 70 28 29 2c 20 22 22 5d 0a 20 20 20 20  trip(), ""].    
4810: 20 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20      else:.      
4820: 20 20 20 20 20 20 70 72 69 6e 74 28 22 23 20 45        print("# E
4830: 72 72 6f 72 2e 20 57 72 6f 6e 67 20 6f 70 74 69  rror. Wrong opti
4840: 6f 6e 20 6c 69 6e 65 20 69 6e 3a 5c 6e 20 20 22  on line in:\n  "
4850: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 70 72  ).            pr
4860: 69 6e 74 28 73 4c 69 6e 65 29 0a 20 20 20 20 70  int(sLine).    p
4870: 72 69 6e 74 28 22 20 20 6f 70 74 69 6f 6e 73 20  rint("  options 
4880: 64 65 66 69 6e 65 64 20 66 6f 72 3a 20 22 20 2b  defined for: " +
4890: 20 22 2c 20 22 2e 6a 6f 69 6e 28 5b 20 74 5b 30   ", ".join([ t[0
48a0: 5d 20 66 6f 72 20 74 20 69 6e 20 6c 4f 70 74 20  ] for t in lOpt 
48b0: 5d 29 29 0a 20 20 20 20 64 4f 70 74 69 6f 6e 73  ])).    dOptions
48c0: 20 3d 20 7b 0a 20 20 20 20 20 20 20 20 22 6c 53   = {.        "lS
48d0: 74 72 75 63 74 4f 70 74 22 3a 20 6c 53 74 72 75  tructOpt": lStru
48e0: 63 74 4f 70 74 2c 20 22 64 4f 70 74 4c 61 62 65  ctOpt, "dOptLabe
48f0: 6c 22 3a 20 64 4f 70 74 4c 61 62 65 6c 2c 20 22  l": dOptLabel, "
4900: 73 44 65 66 61 75 6c 74 55 49 4c 61 6e 67 22 3a  sDefaultUILang":
4910: 20 73 44 65 66 61 75 6c 74 55 49 4c 61 6e 67 2c   sDefaultUILang,
4920: 20 5c 0a 20 20 20 20 20 20 20 20 22 64 43 6f 6c   \.        "dCol
4930: 6f 72 54 79 70 65 22 3a 20 63 72 65 61 74 65 43  orType": createC
4940: 6f 6c 6f 72 73 28 64 43 6f 6c 6f 72 29 2c 20 22  olors(dColor), "
4950: 64 4f 70 74 43 6f 6c 6f 72 22 3a 20 7b 20 73 3a  dOptColor": { s:
4960: 20 64 20 20 66 6f 72 20 73 2c 20 64 20 69 6e 20   d  for s, d in 
4970: 6c 4f 70 74 43 6f 6c 6f 72 20 7d 0a 20 20 20 20  lOptColor }.    
4980: 7d 0a 20 20 20 20 64 4f 70 74 69 6f 6e 73 2e 75  }.    dOptions.u
4990: 70 64 61 74 65 28 7b 20 22 64 4f 70 74 22 2b 6b  pdate({ "dOpt"+k
49a0: 3a 20 76 20 20 66 6f 72 20 6b 2c 20 76 20 69 6e  : v  for k, v in
49b0: 20 6c 4f 70 74 20 7d 29 0a 20 20 20 20 72 65 74   lOpt }).    ret
49c0: 75 72 6e 20 64 4f 70 74 69 6f 6e 73 2c 20 64 4f  urn dOptions, dO
49d0: 70 74 50 72 69 6f 72 69 74 79 0a 0a 0a 64 65 66  ptPriority...def
49e0: 20 70 72 69 6e 74 42 6f 6f 6b 6d 61 72 6b 20 28   printBookmark (
49f0: 6e 4c 65 76 65 6c 2c 20 73 43 6f 6d 6d 65 6e 74  nLevel, sComment
4a00: 2c 20 6e 4c 69 6e 65 29 3a 0a 20 20 20 20 22 70  , nLine):.    "p
4a10: 72 69 6e 74 20 62 6f 6f 6b 6d 61 72 6b 20 77 69  rint bookmark wi
4a20: 74 68 69 6e 20 74 68 65 20 72 75 6c 65 73 20 66  thin the rules f
4a30: 69 6c 65 22 0a 20 20 20 20 70 72 69 6e 74 28 22  ile".    print("
4a40: 20 20 7b 3a 3e 36 7d 3a 20 20 7b 7d 22 2e 66 6f    {:>6}:  {}".fo
4a50: 72 6d 61 74 28 6e 4c 69 6e 65 2c 20 22 20 20 22  rmat(nLine, "  "
4a60: 20 2a 20 6e 4c 65 76 65 6c 20 2b 20 73 43 6f 6d   * nLevel + sCom
4a70: 6d 65 6e 74 29 29 0a 0a 0a 64 65 66 20 6d 61 6b  ment))...def mak
4a80: 65 20 28 73 70 4c 61 6e 67 2c 20 73 4c 61 6e 67  e (spLang, sLang
4a90: 2c 20 62 55 73 65 43 61 63 68 65 3d 4e 6f 6e 65  , bUseCache=None
4aa0: 29 3a 0a 20 20 20 20 22 63 6f 6d 70 69 6c 65 20  ):.    "compile 
4ab0: 72 75 6c 65 73 2c 20 72 65 74 75 72 6e 73 20 61  rules, returns a
4ac0: 20 64 69 63 74 69 6f 6e 61 72 79 20 6f 66 20 76   dictionary of v
4ad0: 61 6c 75 65 73 22 0a 20 20 20 20 23 20 66 6f 72  alues".    # for
4ae0: 20 63 6c 61 72 69 74 79 20 70 75 72 70 6f 73 65   clarity purpose
4af0: 2c 20 64 6f 6e e2 80 99 74 20 63 72 65 61 74 65  , don...t create
4b00: 20 61 6e 79 20 66 69 6c 65 20 68 65 72 65 20 28   any file here (
4b10: 65 78 63 65 70 74 20 63 61 63 68 65 29 0a 0a 20  except cache).. 
4b20: 20 20 20 64 43 61 63 68 65 56 61 72 73 20 3d 20     dCacheVars = 
4b30: 4e 6f 6e 65 0a 0a 20 20 20 20 69 66 20 6f 73 2e  None..    if os.
4b40: 70 61 74 68 2e 69 73 66 69 6c 65 28 22 5f 62 75  path.isfile("_bu
4b50: 69 6c 64 2f 64 61 74 61 5f 63 61 63 68 65 2e 6a  ild/data_cache.j
4b60: 73 6f 6e 22 29 3a 0a 20 20 20 20 20 20 20 20 70  son"):.        p
4b70: 72 69 6e 74 28 22 3e 20 64 61 74 61 20 63 61 63  rint("> data cac
4b80: 68 65 20 66 6f 75 6e 64 22 29 0a 20 20 20 20 20  he found").     
4b90: 20 20 20 73 4a 53 4f 4e 20 3d 20 6f 70 65 6e 28     sJSON = open(
4ba0: 22 5f 62 75 69 6c 64 2f 64 61 74 61 5f 63 61 63  "_build/data_cac
4bb0: 68 65 2e 6a 73 6f 6e 22 2c 20 22 72 22 2c 20 65  he.json", "r", e
4bc0: 6e 63 6f 64 69 6e 67 3d 22 75 74 66 2d 38 22 29  ncoding="utf-8")
4bd0: 2e 72 65 61 64 28 29 0a 20 20 20 20 20 20 20 20  .read().        
4be0: 64 43 61 63 68 65 56 61 72 73 20 3d 20 6a 73 6f  dCacheVars = jso
4bf0: 6e 2e 6c 6f 61 64 73 28 73 4a 53 4f 4e 29 0a 20  n.loads(sJSON). 
4c00: 20 20 20 20 20 20 20 73 42 75 69 6c 64 44 61 74         sBuildDat
4c10: 65 20 3d 20 74 69 6d 65 2e 73 74 72 66 74 69 6d  e = time.strftim
4c20: 65 28 22 25 59 2d 25 6d 2d 25 64 20 25 48 3a 25  e("%Y-%m-%d %H:%
4c30: 4d 3a 25 53 22 2c 20 74 69 6d 65 2e 67 6d 74 69  M:%S", time.gmti
4c40: 6d 65 28 64 43 61 63 68 65 56 61 72 73 2e 67 65  me(dCacheVars.ge
4c50: 74 28 22 66 42 75 69 6c 64 54 69 6d 65 22 2c 20  t("fBuildTime", 
4c60: 30 29 29 29 0a 20 20 20 20 20 20 20 20 69 66 20  0))).        if 
4c70: 62 55 73 65 43 61 63 68 65 3a 0a 20 20 20 20 20  bUseCache:.     
4c80: 20 20 20 20 20 20 20 70 72 69 6e 74 28 22 3e 20         print("> 
4c90: 75 73 65 20 63 61 63 68 65 20 28 6e 6f 20 72 65  use cache (no re
4ca0: 62 75 69 6c 64 20 61 73 6b 65 64 29 22 29 0a 20  build asked)"). 
4cb0: 20 20 20 20 20 20 20 20 20 20 20 70 72 69 6e 74             print
4cc0: 28 22 20 20 62 75 69 6c 64 20 6d 61 64 65 20 61  ("  build made a
4cd0: 74 3a 20 22 20 2b 20 73 42 75 69 6c 64 44 61 74  t: " + sBuildDat
4ce0: 65 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 72  e).            r
4cf0: 65 74 75 72 6e 20 64 43 61 63 68 65 56 61 72 73  eturn dCacheVars
4d00: 0a 0a 20 20 20 20 70 72 69 6e 74 28 22 3e 20 72  ..    print("> r
4d10: 65 61 64 20 72 75 6c 65 73 20 66 69 6c 65 2e 2e  ead rules file..
4d20: 2e 22 29 0a 20 20 20 20 74 72 79 3a 0a 20 20 20  .").    try:.   
4d30: 20 20 20 20 20 73 46 69 6c 65 43 6f 6e 74 65 6e       sFileConten
4d40: 74 20 3d 20 6f 70 65 6e 28 73 70 4c 61 6e 67 20  t = open(spLang 
4d50: 2b 20 22 2f 72 75 6c 65 73 2e 67 72 78 22 2c 20  + "/rules.grx", 
4d60: 27 72 27 2c 20 65 6e 63 6f 64 69 6e 67 3d 22 75  'r', encoding="u
4d70: 74 66 2d 38 22 29 2e 72 65 61 64 28 29 0a 20 20  tf-8").read().  
4d80: 20 20 65 78 63 65 70 74 20 4f 53 45 72 72 6f 72    except OSError
4d90: 3a 0a 20 20 20 20 20 20 20 20 70 72 69 6e 74 28  :.        print(
4da0: 66 22 23 20 45 72 72 6f 72 2e 20 52 75 6c 65 73  f"# Error. Rules
4db0: 20 66 69 6c 65 20 69 6e 20 70 72 6f 6a 65 63 74   file in project
4dc0: 20 3c 7b 73 4c 61 6e 67 7d 3e 20 6e 6f 74 20 66   <{sLang}> not f
4dd0: 6f 75 6e 64 2e 22 29 0a 20 20 20 20 20 20 20 20  ound.").        
4de0: 65 78 69 74 28 29 0a 0a 20 20 20 20 23 20 63 61  exit()..    # ca
4df0: 6c 63 75 6c 61 74 65 20 68 61 73 68 20 6f 66 20  lculate hash of 
4e00: 6c 6f 61 64 65 64 20 66 69 6c 65 0a 20 20 20 20  loaded file.    
4e10: 78 48 61 73 68 65 72 20 3d 20 68 61 73 68 6c 69  xHasher = hashli
4e20: 62 2e 6e 65 77 28 22 73 68 61 33 5f 35 31 32 22  b.new("sha3_512"
4e30: 29 0a 20 20 20 20 78 48 61 73 68 65 72 2e 75 70  ).    xHasher.up
4e40: 64 61 74 65 28 73 46 69 6c 65 43 6f 6e 74 65 6e  date(sFileConten
4e50: 74 2e 65 6e 63 6f 64 65 28 22 75 74 66 2d 38 22  t.encode("utf-8"
4e60: 29 29 0a 20 20 20 20 73 46 69 6c 65 48 61 73 68  )).    sFileHash
4e70: 20 3d 20 78 48 61 73 68 65 72 2e 68 65 78 64 69   = xHasher.hexdi
4e80: 67 65 73 74 28 29 0a 0a 20 20 20 20 69 66 20 64  gest()..    if d
4e90: 43 61 63 68 65 56 61 72 73 20 61 6e 64 20 62 55  CacheVars and bU
4ea0: 73 65 43 61 63 68 65 20 21 3d 20 46 61 6c 73 65  seCache != False
4eb0: 20 61 6e 64 20 73 46 69 6c 65 48 61 73 68 20 3d   and sFileHash =
4ec0: 3d 20 64 43 61 63 68 65 56 61 72 73 2e 67 65 74  = dCacheVars.get
4ed0: 28 22 73 46 69 6c 65 48 61 73 68 22 2c 20 22 22  ("sFileHash", ""
4ee0: 29 3a 0a 20 20 20 20 20 20 20 20 23 20 69 66 20  ):.        # if 
4ef0: 3c 62 55 73 65 43 61 63 68 65 3e 20 69 73 20 4e  <bUseCache> is N
4f00: 6f 6e 65 20 6f 72 20 54 72 75 65 2c 20 77 65 20  one or True, we 
4f10: 63 61 6e 20 75 73 65 20 74 68 65 20 63 61 63 68  can use the cach
4f20: 65 0a 20 20 20 20 20 20 20 20 70 72 69 6e 74 28  e.        print(
4f30: 22 3e 20 63 61 63 68 65 20 68 61 73 68 20 69 64  "> cache hash id
4f40: 65 6e 74 69 63 61 6c 20 74 6f 20 66 69 6c 65 20  entical to file 
4f50: 68 61 73 68 2c 20 75 73 65 20 63 61 63 68 65 22  hash, use cache"
4f60: 29 0a 20 20 20 20 20 20 20 20 70 72 69 6e 74 28  ).        print(
4f70: 22 20 20 62 75 69 6c 64 20 6d 61 64 65 20 61 74  "  build made at
4f80: 3a 20 22 20 2b 20 73 42 75 69 6c 64 44 61 74 65  : " + sBuildDate
4f90: 29 0a 20 20 20 20 20 20 20 20 72 65 74 75 72 6e  ).        return
4fa0: 20 64 43 61 63 68 65 56 61 72 73 0a 0a 20 20 20   dCacheVars..   
4fb0: 20 23 20 72 65 6d 6f 76 69 6e 67 20 63 6f 6d 6d   # removing comm
4fc0: 65 6e 74 73 2c 20 7a 65 72 6f 69 6e 67 20 65 6d  ents, zeroing em
4fd0: 70 74 79 20 6c 69 6e 65 73 2c 20 63 72 65 61 74  pty lines, creat
4fe0: 69 6e 67 20 64 65 66 69 6e 69 74 69 6f 6e 73 2c  ing definitions,
4ff0: 20 73 74 6f 72 69 6e 67 20 74 65 73 74 73 2c 20   storing tests, 
5000: 6d 65 72 67 69 6e 67 20 72 75 6c 65 20 6c 69 6e  merging rule lin
5010: 65 73 0a 20 20 20 20 70 72 69 6e 74 28 22 20 20  es.    print("  
5020: 70 61 72 73 69 6e 67 20 72 75 6c 65 73 2e 2e 2e  parsing rules...
5030: 22 29 0a 20 20 20 20 66 42 75 69 6c 64 54 69 6d  ").    fBuildTim
5040: 65 20 3d 20 74 69 6d 65 2e 74 69 6d 65 28 29 0a  e = time.time().
5050: 20 20 20 20 6c 52 75 6c 65 4c 69 6e 65 20 3d 20      lRuleLine = 
5060: 5b 5d 0a 20 20 20 20 6c 54 65 73 74 20 3d 20 5b  [].    lTest = [
5070: 5d 0a 20 20 20 20 6c 4f 70 74 20 3d 20 5b 5d 0a  ].    lOpt = [].
5080: 20 20 20 20 62 47 72 61 70 68 20 3d 20 46 61 6c      bGraph = Fal
5090: 73 65 0a 20 20 20 20 6c 47 72 61 70 68 52 75 6c  se.    lGraphRul
50a0: 65 20 3d 20 5b 5d 0a 0a 20 20 20 20 66 6f 72 20  e = []..    for 
50b0: 69 2c 20 73 4c 69 6e 65 20 69 6e 20 65 6e 75 6d  i, sLine in enum
50c0: 65 72 61 74 65 28 73 46 69 6c 65 43 6f 6e 74 65  erate(sFileConte
50d0: 6e 74 2e 73 70 6c 69 74 28 22 5c 6e 22 29 2c 20  nt.split("\n"), 
50e0: 31 29 3a 0a 20 20 20 20 20 20 20 20 69 66 20 73  1):.        if s
50f0: 4c 69 6e 65 2e 73 74 61 72 74 73 77 69 74 68 28  Line.startswith(
5100: 27 23 45 4e 44 27 29 3a 0a 20 20 20 20 20 20 20  '#END'):.       
5110: 20 20 20 20 20 23 20 61 72 62 69 74 72 61 72 79       # arbitrary
5120: 20 65 6e 64 0a 20 20 20 20 20 20 20 20 20 20 20   end.           
5130: 20 70 72 69 6e 74 42 6f 6f 6b 6d 61 72 6b 28 30   printBookmark(0
5140: 2c 20 22 42 52 45 41 4b 20 42 59 20 23 45 4e 44  , "BREAK BY #END
5150: 22 2c 20 69 29 0a 20 20 20 20 20 20 20 20 20 20  ", i).          
5160: 20 20 62 72 65 61 6b 0a 20 20 20 20 20 20 20 20    break.        
5170: 65 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61 72 74  elif sLine.start
5180: 73 77 69 74 68 28 28 22 23 22 2c 20 22 20 20 20  swith(("#", "   
5190: 20 23 23 22 29 29 3a 0a 20 20 20 20 20 20 20 20   ##")):.        
51a0: 20 20 20 20 23 20 63 6f 6d 6d 65 6e 74 0a 20 20      # comment.  
51b0: 20 20 20 20 20 20 20 20 20 20 70 61 73 73 0a 20            pass. 
51c0: 20 20 20 20 20 20 20 65 6c 69 66 20 73 4c 69 6e         elif sLin
51d0: 65 2e 73 74 61 72 74 73 77 69 74 68 28 22 44 45  e.startswith("DE
51e0: 46 3a 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20  F:"):.          
51f0: 20 20 23 20 64 65 66 69 6e 69 74 69 6f 6e 0a 20    # definition. 
5200: 20 20 20 20 20 20 20 20 20 20 20 6d 20 3d 20 72             m = r
5210: 65 2e 6d 61 74 63 68 28 22 44 45 46 3a 20 2b 28  e.match("DEF: +(
5220: 5b 61 2d 7a 41 2d 5a 5f 5d 5b 61 2d 7a 41 2d 5a  [a-zA-Z_][a-zA-Z
5230: 5f 30 2d 39 5d 2a 29 20 2b 28 2e 2b 29 24 22 2c  _0-9]*) +(.+)$",
5240: 20 73 4c 69 6e 65 2e 73 74 72 69 70 28 29 29 0a   sLine.strip()).
5250: 20 20 20 20 20 20 20 20 20 20 20 20 69 66 20 6d              if m
5260: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  :.              
5270: 20 20 64 44 45 46 49 4e 49 54 49 4f 4e 53 5b 22    dDEFINITIONS["
5280: 7b 22 2b 6d 2e 67 72 6f 75 70 28 31 29 2b 22 7d  {"+m.group(1)+"}
5290: 22 5d 20 3d 20 6d 2e 67 72 6f 75 70 28 32 29 0a  "] = m.group(2).
52a0: 20 20 20 20 20 20 20 20 20 20 20 20 65 6c 73 65              else
52b0: 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  :.              
52c0: 20 20 70 72 69 6e 74 28 22 23 20 45 72 72 6f 72    print("# Error
52d0: 20 69 6e 20 64 65 66 69 6e 69 74 69 6f 6e 3a 20   in definition: 
52e0: 22 2c 20 65 6e 64 3d 22 22 29 0a 20 20 20 20 20  ", end="").     
52f0: 20 20 20 20 20 20 20 20 20 20 20 70 72 69 6e 74             print
5300: 28 73 4c 69 6e 65 2e 73 74 72 69 70 28 29 29 0a  (sLine.strip()).
5310: 20 20 20 20 20 20 20 20 65 6c 69 66 20 73 4c 69          elif sLi
5320: 6e 65 2e 73 74 61 72 74 73 77 69 74 68 28 22 44  ne.startswith("D
5330: 45 43 4c 3a 22 29 3a 0a 20 20 20 20 20 20 20 20  ECL:"):.        
5340: 20 20 20 20 23 20 64 65 63 6c 65 6e 73 69 6f 6e      # declension
5350: 73 0a 20 20 20 20 20 20 20 20 20 20 20 20 6d 20  s.            m 
5360: 3d 20 72 65 2e 6d 61 74 63 68 28 72 22 44 45 43  = re.match(r"DEC
5370: 4c 3a 20 2b 28 5c 2b 5c 77 2b 29 20 28 2e 2b 29  L: +(\+\w+) (.+)
5380: 24 22 2c 20 73 4c 69 6e 65 2e 73 74 72 69 70 28  $", sLine.strip(
5390: 29 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 69  )).            i
53a0: 66 20 6d 3a 0a 20 20 20 20 20 20 20 20 20 20 20  f m:.           
53b0: 20 20 20 20 20 64 44 45 43 4c 45 4e 53 49 4f 4e       dDECLENSION
53c0: 53 5b 6d 2e 67 72 6f 75 70 28 31 29 5d 20 3d 20  S[m.group(1)] = 
53d0: 6d 2e 67 72 6f 75 70 28 32 29 2e 73 74 72 69 70  m.group(2).strip
53e0: 28 29 2e 73 70 6c 69 74 28 29 0a 20 20 20 20 20  ().split().     
53f0: 20 20 20 20 20 20 20 65 6c 73 65 3a 0a 20 20 20         else:.   
5400: 20 20 20 20 20 20 20 20 20 20 20 20 20 70 72 69               pri
5410: 6e 74 28 22 45 72 72 6f 72 20 69 6e 20 64 65 63  nt("Error in dec
5420: 6c 65 6e 73 69 6f 6e 20 6c 69 73 74 3a 20 22 2c  lension list: ",
5430: 20 65 6e 64 3d 22 22 29 0a 20 20 20 20 20 20 20   end="").       
5440: 20 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 73           print(s
5450: 4c 69 6e 65 2e 73 74 72 69 70 28 29 29 0a 20 20  Line.strip()).  
5460: 20 20 20 20 20 20 65 6c 69 66 20 73 4c 69 6e 65        elif sLine
5470: 2e 73 74 61 72 74 73 77 69 74 68 28 22 54 45 53  .startswith("TES
5480: 54 3a 22 29 3a 0a 20 20 20 20 20 20 20 20 20 20  T:"):.          
5490: 20 20 23 20 74 65 73 74 0a 20 20 20 20 20 20 20    # test.       
54a0: 20 20 20 20 20 6c 54 65 73 74 2e 61 70 70 65 6e       lTest.appen
54b0: 64 28 22 7b 3a 3c 38 7d 22 2e 66 6f 72 6d 61 74  d("{:<8}".format
54c0: 28 69 29 20 2b 20 22 20 20 22 20 2b 20 73 4c 69  (i) + "  " + sLi
54d0: 6e 65 5b 35 3a 5d 2e 73 74 72 69 70 28 29 29 0a  ne[5:].strip()).
54e0: 20 20 20 20 20 20 20 20 65 6c 69 66 20 73 4c 69          elif sLi
54f0: 6e 65 2e 73 74 61 72 74 73 77 69 74 68 28 22 54  ne.startswith("T
5500: 4f 44 4f 3a 22 29 3a 0a 20 20 20 20 20 20 20 20  ODO:"):.        
5510: 20 20 20 20 23 20 74 6f 64 6f 0a 20 20 20 20 20      # todo.     
5520: 20 20 20 20 20 20 20 70 61 73 73 0a 20 20 20 20         pass.    
5530: 20 20 20 20 65 6c 69 66 20 73 4c 69 6e 65 2e 73      elif sLine.s
5540: 74 61 72 74 73 77 69 74 68 28 28 22 4f 50 54 47  tartswith(("OPTG
5550: 52 4f 55 50 2f 22 2c 20 22 4f 50 54 53 4f 46 54  ROUP/", "OPTSOFT
5560: 57 41 52 45 3a 22 2c 20 22 4f 50 54 2f 22 2c 20  WARE:", "OPT/", 
5570: 5c 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  \.              
5580: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
5590: 20 20 22 43 4f 4c 4f 52 2f 22 2c 20 22 4f 50 54    "COLOR/", "OPT
55a0: 43 4f 4c 4f 52 54 48 45 4d 45 3a 22 2c 20 22 4f  COLORTHEME:", "O
55b0: 50 54 43 4f 4c 4f 52 2f 22 2c 20 5c 0a 20 20 20  PTCOLOR/", \.   
55c0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
55d0: 20 20 20 20 20 20 20 20 20 20 20 20 20 22 4f 50               "OP
55e0: 54 4c 41 4e 47 2f 22 2c 20 22 4f 50 54 44 45 46  TLANG/", "OPTDEF
55f0: 41 55 4c 54 55 49 4c 41 4e 47 3a 22 2c 20 5c 0a  AULTUILANG:", \.
5600: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
5610: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
5620: 22 4f 50 54 4c 41 42 45 4c 2f 22 2c 20 22 4f 50  "OPTLABEL/", "OP
5630: 54 50 52 49 4f 52 49 54 59 2f 22 29 29 3a 0a 20  TPRIORITY/")):. 
5640: 20 20 20 20 20 20 20 20 20 20 20 23 20 6f 70 74             # opt
5650: 69 6f 6e 73 0a 20 20 20 20 20 20 20 20 20 20 20  ions.           
5660: 20 6c 4f 70 74 2e 61 70 70 65 6e 64 28 73 4c 69   lOpt.append(sLi
5670: 6e 65 29 0a 20 20 20 20 20 20 20 20 65 6c 69 66  ne).        elif
5680: 20 73 4c 69 6e 65 2e 73 74 61 72 74 73 77 69 74   sLine.startswit
5690: 68 28 22 21 21 22 29 3a 0a 20 20 20 20 20 20 20  h("!!"):.       
56a0: 20 20 20 20 20 23 20 62 6f 6f 6b 6d 61 72 6b 0a       # bookmark.
56b0: 20 20 20 20 20 20 20 20 20 20 20 20 6d 20 3d 20              m = 
56c0: 72 65 2e 6d 61 74 63 68 28 22 21 21 2b 22 2c 20  re.match("!!+", 
56d0: 73 4c 69 6e 65 29 0a 20 20 20 20 20 20 20 20 20  sLine).         
56e0: 20 20 20 6e 45 78 4d 6b 20 3d 20 6c 65 6e 28 6d     nExMk = len(m
56f0: 2e 67 72 6f 75 70 28 30 29 29 0a 20 20 20 20 20  .group(0)).     
5700: 20 20 20 20 20 20 20 69 66 20 73 4c 69 6e 65 5b         if sLine[
5710: 6e 45 78 4d 6b 3a 5d 2e 73 74 72 69 70 28 29 3a  nExMk:].strip():
5720: 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  .               
5730: 20 70 72 69 6e 74 42 6f 6f 6b 6d 61 72 6b 28 6e   printBookmark(n
5740: 45 78 4d 6b 2d 32 2c 20 73 4c 69 6e 65 5b 6e 45  ExMk-2, sLine[nE
5750: 78 4d 6b 3a 2d 33 5d 2e 73 74 72 69 70 28 29 2c  xMk:-3].strip(),
5760: 20 69 29 0a 20 20 20 20 20 20 20 20 23 20 47 72   i).        # Gr
5770: 61 70 68 20 72 75 6c 65 73 0a 20 20 20 20 20 20  aph rules.      
5780: 20 20 65 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61    elif sLine.sta
5790: 72 74 73 77 69 74 68 28 22 40 40 40 40 47 52 41  rtswith("@@@@GRA
57a0: 50 48 3a 22 29 3a 0a 20 20 20 20 20 20 20 20 20  PH:"):.         
57b0: 20 20 20 23 20 72 75 6c 65 73 20 67 72 61 70 68     # rules graph
57c0: 20 63 61 6c 6c 0a 20 20 20 20 20 20 20 20 20 20   call.          
57d0: 20 20 6d 20 3d 20 72 65 2e 6d 61 74 63 68 28 72    m = re.match(r
57e0: 22 40 40 40 40 47 52 41 50 48 3a 20 2a 28 5c 77  "@@@@GRAPH: *(\w
57f0: 2b 29 22 2c 20 73 4c 69 6e 65 2e 73 74 72 69 70  +)", sLine.strip
5800: 28 29 29 0a 20 20 20 20 20 20 20 20 20 20 20 20  ()).            
5810: 69 66 20 6d 3a 0a 20 20 20 20 20 20 20 20 20 20  if m:.          
5820: 20 20 20 20 20 20 70 72 69 6e 74 42 6f 6f 6b 6d        printBookm
5830: 61 72 6b 28 30 2c 20 22 47 52 41 50 48 3a 20 22  ark(0, "GRAPH: "
5840: 20 2b 20 6d 2e 67 72 6f 75 70 28 31 29 2c 20 69   + m.group(1), i
5850: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  ).              
5860: 20 20 6c 52 75 6c 65 4c 69 6e 65 2e 61 70 70 65    lRuleLine.appe
5870: 6e 64 28 5b 69 2c 20 22 40 40 40 40 22 2b 6d 2e  nd([i, "@@@@"+m.
5880: 67 72 6f 75 70 28 31 29 5d 29 0a 20 20 20 20 20  group(1)]).     
5890: 20 20 20 20 20 20 20 20 20 20 20 6c 47 72 61 70             lGrap
58a0: 68 52 75 6c 65 2e 61 70 70 65 6e 64 28 5b 69 2c  hRule.append([i,
58b0: 20 73 4c 69 6e 65 5d 29 0a 20 20 20 20 20 20 20   sLine]).       
58c0: 20 20 20 20 20 20 20 20 20 62 47 72 61 70 68 20           bGraph 
58d0: 3d 20 54 72 75 65 0a 20 20 20 20 20 20 20 20 20  = True.         
58e0: 20 20 20 65 6c 73 65 3a 0a 20 20 20 20 20 20 20     else:.       
58f0: 20 20 20 20 20 20 20 20 20 70 72 69 6e 74 28 22           print("
5900: 47 72 61 70 68 20 65 72 72 6f 72 20 61 74 20 6c  Graph error at l
5910: 69 6e 65 22 2c 20 69 29 0a 20 20 20 20 20 20 20  ine", i).       
5920: 20 65 6c 69 66 20 73 4c 69 6e 65 2e 73 74 61 72   elif sLine.star
5930: 74 73 77 69 74 68 28 28 22 40 40 40 40 45 4e 44  tswith(("@@@@END
5940: 5f 47 52 41 50 48 22 2c 20 22 40 40 40 40 45 4e  _GRAPH", "@@@@EN
5950: 44 47 52 41 50 48 22 29 29 3a 0a 20 20 20 20 20  DGRAPH")):.     
5960: 20 20 20 20 20 20 20 23 6c 47 72 61 70 68 52 75         #lGraphRu
5970: 6c 65 2e 61 70 70 65 6e 64 28 5b 69 2c 20 73 4c  le.append([i, sL
5980: 69 6e 65 5d 29 0a 20 20 20 20 20 20 20 20 20 20  ine]).          
5990: 20 20 70 72 69 6e 74 42 6f 6f 6b 6d 61 72 6b 28    printBookmark(
59a0: 30 2c 20 22 45 4e 44 47 52 41 50 48 22 2c 20 69  0, "ENDGRAPH", i
59b0: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 62 47  ).            bG
59c0: 72 61 70 68 20 3d 20 46 61 6c 73 65 0a 20 20 20  raph = False.   
59d0: 20 20 20 20 20 65 6c 69 66 20 72 65 2e 6d 61 74       elif re.mat
59e0: 63 68 28 22 40 40 40 40 20 2a 24 22 2c 20 73 4c  ch("@@@@ *$", sL
59f0: 69 6e 65 29 3a 0a 20 20 20 20 20 20 20 20 20 20  ine):.          
5a00: 20 20 70 61 73 73 0a 20 20 20 20 20 20 20 20 65    pass.        e
5a10: 6c 69 66 20 62 47 72 61 70 68 3a 0a 20 20 20 20  lif bGraph:.    
5a20: 20 20 20 20 20 20 20 20 6c 47 72 61 70 68 52 75          lGraphRu
5a30: 6c 65 2e 61 70 70 65 6e 64 28 5b 69 2c 20 73 4c  le.append([i, sL
5a40: 69 6e 65 5d 29 0a 20 20 20 20 20 20 20 20 23 20  ine]).        # 
5a50: 52 65 67 65 78 20 72 75 6c 65 73 0a 20 20 20 20  Regex rules.    
5a60: 20 20 20 20 65 6c 69 66 20 72 65 2e 6d 61 74 63      elif re.matc
5a70: 68 28 22 5b 20 c2 a0 5c 74 5d 2a 24 22 2c 20 73  h("[ ..\t]*$", s
5a80: 4c 69 6e 65 29 3a 0a 20 20 20 20 20 20 20 20 20  Line):.         
5a90: 20 20 20 23 20 65 6d 70 74 79 20 6c 69 6e 65 0a     # empty line.
5aa0: 20 20 20 20 20 20 20 20 20 20 20 20 70 61 73 73              pass
5ab0: 0a 20 20 20 20 20 20 20 20 65 6c 69 66 20 73 4c  .        elif sL
5ac0: 69 6e 65 2e 73 74 61 72 74 73 77 69 74 68 28 22  ine.startswith("
5ad0: 20 20 20 20 22 29 3a 0a 20 20 20 20 20 20 20 20      "):.        
5ae0: 20 20 20 20 23 20 72 75 6c 65 20 28 63 6f 6e 74      # rule (cont
5af0: 69 6e 75 61 74 69 6f 6e 29 0a 20 20 20 20 20 20  inuation).      
5b00: 20 20 20 20 20 20 6c 52 75 6c 65 4c 69 6e 65 5b        lRuleLine[
5b10: 2d 31 5d 5b 31 5d 20 2b 3d 20 22 20 22 20 2b 20  -1][1] += " " + 
5b20: 73 4c 69 6e 65 2e 73 74 72 69 70 28 29 0a 20 20  sLine.strip().  
5b30: 20 20 20 20 20 20 65 6c 73 65 3a 0a 20 20 20 20        else:.    
5b40: 20 20 20 20 20 20 20 20 23 20 6e 65 77 20 72 75          # new ru
5b50: 6c 65 0a 20 20 20 20 20 20 20 20 20 20 20 20 6c  le.            l
5b60: 52 75 6c 65 4c 69 6e 65 2e 61 70 70 65 6e 64 28  RuleLine.append(
5b70: 5b 69 2c 20 73 4c 69 6e 65 2e 73 74 72 69 70 28  [i, sLine.strip(
5b80: 29 5d 29 0a 0a 20 20 20 20 23 20 67 65 6e 65 72  )])..    # gener
5b90: 61 74 69 6e 67 20 6f 70 74 69 6f 6e 73 20 66 69  ating options fi
5ba0: 6c 65 73 0a 20 20 20 20 70 72 69 6e 74 28 22 20  les.    print(" 
5bb0: 20 70 61 72 73 69 6e 67 20 6f 70 74 69 6f 6e 73   parsing options
5bc0: 2e 2e 2e 22 29 0a 20 20 20 20 64 4f 70 74 69 6f  ...").    dOptio
5bd0: 6e 73 2c 20 64 4f 70 74 50 72 69 6f 72 69 74 79  ns, dOptPriority
5be0: 20 3d 20 70 72 65 70 61 72 65 4f 70 74 69 6f 6e   = prepareOption
5bf0: 73 28 6c 4f 70 74 29 0a 0a 20 20 20 20 23 20 74  s(lOpt)..    # t
5c00: 65 73 74 73 0a 20 20 20 20 70 72 69 6e 74 28 22  ests.    print("
5c10: 20 20 6c 69 73 74 20 74 65 73 74 73 2e 2e 2e 22    list tests..."
5c20: 29 0a 20 20 20 20 73 47 43 54 65 73 74 73 20 3d  ).    sGCTests =
5c30: 20 22 5c 6e 22 2e 6a 6f 69 6e 28 6c 54 65 73 74   "\n".join(lTest
5c40: 29 0a 20 20 20 20 73 47 43 54 65 73 74 73 4a 53  ).    sGCTestsJS
5c50: 20 3d 20 27 7b 20 22 61 44 61 74 61 22 3a 20 27   = '{ "aData": '
5c60: 20 2b 20 6a 73 6f 6e 2e 64 75 6d 70 73 28 6c 54   + json.dumps(lT
5c70: 65 73 74 2c 20 65 6e 73 75 72 65 5f 61 73 63 69  est, ensure_asci
5c80: 69 3d 46 61 6c 73 65 29 20 2b 20 22 20 7d 5c 6e  i=False) + " }\n
5c90: 22 0a 0a 20 20 20 20 23 20 70 72 6f 63 65 73 73  "..    # process
5ca0: 69 6e 67 0a 20 20 20 20 70 72 69 6e 74 28 22 20  ing.    print(" 
5cb0: 20 70 72 65 70 61 72 69 6e 67 20 72 75 6c 65 73   preparing rules
5cc0: 2e 2e 2e 22 29 0a 20 20 20 20 62 50 61 72 61 67  ...").    bParag
5cd0: 72 61 70 68 20 3d 20 54 72 75 65 0a 20 20 20 20  raph = True.    
5ce0: 6c 50 61 72 61 67 72 61 70 68 52 75 6c 65 73 20  lParagraphRules 
5cf0: 3d 20 5b 5d 0a 20 20 20 20 6c 53 65 6e 74 65 6e  = [].    lSenten
5d00: 63 65 52 75 6c 65 73 20 3d 20 5b 5d 0a 20 20 20  ceRules = [].   
5d10: 20 6c 50 61 72 61 67 72 61 70 68 52 75 6c 65 73   lParagraphRules
5d20: 4a 53 20 3d 20 5b 5d 0a 20 20 20 20 6c 53 65 6e  JS = [].    lSen
5d30: 74 65 6e 63 65 52 75 6c 65 73 4a 53 20 3d 20 5b  tenceRulesJS = [
5d40: 5d 0a 0a 20 20 20 20 66 6f 72 20 6e 4c 69 6e 65  ]..    for nLine
5d50: 2c 20 73 4c 69 6e 65 20 69 6e 20 6c 52 75 6c 65  , sLine in lRule
5d60: 4c 69 6e 65 3a 0a 20 20 20 20 20 20 20 20 69 66  Line:.        if
5d70: 20 73 4c 69 6e 65 3a 0a 20 20 20 20 20 20 20 20   sLine:.        
5d80: 20 20 20 20 69 66 20 73 4c 69 6e 65 20 3d 3d 20      if sLine == 
5d90: 22 5b 2b 2b 5d 22 3a 0a 20 20 20 20 20 20 20 20  "[++]":.        
5da0: 20 20 20 20 20 20 20 20 62 50 61 72 61 67 72 61          bParagra
5db0: 70 68 20 3d 20 46 61 6c 73 65 0a 20 20 20 20 20  ph = False.     
5dc0: 20 20 20 20 20 20 20 65 6c 73 65 3a 0a 20 20 20         else:.   
5dd0: 20 20 20 20 20 20 20 20 20 20 20 20 20 61 52 75               aRu
5de0: 6c 65 20 3d 20 63 72 65 61 74 65 52 75 6c 65 28  le = createRule(
5df0: 73 4c 69 6e 65 2c 20 6e 4c 69 6e 65 2c 20 73 4c  sLine, nLine, sL
5e00: 61 6e 67 2c 20 62 50 61 72 61 67 72 61 70 68 2c  ang, bParagraph,
5e10: 20 64 4f 70 74 50 72 69 6f 72 69 74 79 29 0a 20   dOptPriority). 
5e20: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 69                 i
5e30: 66 20 61 52 75 6c 65 3a 0a 20 20 20 20 20 20 20  f aRule:.       
5e40: 20 20 20 20 20 20 20 20 20 20 20 20 20 69 66 20               if 
5e50: 62 50 61 72 61 67 72 61 70 68 3a 0a 20 20 20 20  bParagraph:.    
5e60: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
5e70: 20 20 20 20 6c 50 61 72 61 67 72 61 70 68 52 75      lParagraphRu
5e80: 6c 65 73 2e 61 70 70 65 6e 64 28 61 52 75 6c 65  les.append(aRule
5e90: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20  ).              
5ea0: 20 20 20 20 20 20 20 20 20 20 6c 50 61 72 61 67            lParag
5eb0: 72 61 70 68 52 75 6c 65 73 4a 53 2e 61 70 70 65  raphRulesJS.appe
5ec0: 6e 64 28 6a 73 63 6f 6e 76 2e 70 79 52 75 6c 65  nd(jsconv.pyRule
5ed0: 54 6f 4a 53 28 61 52 75 6c 65 2c 20 64 4a 53 52  ToJS(aRule, dJSR
5ee0: 45 47 45 58 45 53 2c 20 73 57 4f 52 44 4c 49 4d  EGEXES, sWORDLIM
5ef0: 49 54 4c 45 46 54 29 29 0a 20 20 20 20 20 20 20  ITLEFT)).       
5f00: 20 20 20 20 20 20 20 20 20 20 20 20 20 65 6c 73               els
5f10: 65 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 20  e:.             
5f20: 20 20 20 20 20 20 20 20 20 20 20 6c 53 65 6e 74             lSent
5f30: 65 6e 63 65 52 75 6c 65 73 2e 61 70 70 65 6e 64  enceRules.append
5f40: 28 61 52 75 6c 65 29 0a 20 20 20 20 20 20 20 20  (aRule).        
5f50: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
5f60: 6c 53 65 6e 74 65 6e 63 65 52 75 6c 65 73 4a 53  lSentenceRulesJS
5f70: 2e 61 70 70 65 6e 64 28 6a 73 63 6f 6e 76 2e 70  .append(jsconv.p
5f80: 79 52 75 6c 65 54 6f 4a 53 28 61 52 75 6c 65 2c  yRuleToJS(aRule,
5f90: 20 64 4a 53 52 45 47 45 58 45 53 2c 20 73 57 4f   dJSREGEXES, sWO
5fa0: 52 44 4c 49 4d 49 54 4c 45 46 54 29 29 0a 0a 20  RDLIMITLEFT)).. 
5fb0: 20 20 20 23 20 63 72 65 61 74 69 6e 67 20 66 69     # creating fi
5fc0: 6c 65 20 77 69 74 68 20 61 6c 6c 20 66 75 6e 63  le with all func
5fd0: 74 69 6f 6e 73 20 63 61 6c 6c 61 62 6c 65 20 62  tions callable b
5fe0: 79 20 72 75 6c 65 73 0a 20 20 20 20 70 72 69 6e  y rules.    prin
5ff0: 74 28 22 20 20 63 72 65 61 74 69 6e 67 20 63 61  t("  creating ca
6000: 6c 6c 61 62 6c 65 73 20 66 6f 72 20 72 65 67 65  llables for rege
6010: 78 20 72 75 6c 65 73 2e 2e 2e 22 29 0a 20 20 20  x rules...").   
6020: 20 73 50 79 43 61 6c 6c 61 62 6c 65 73 20 3d 20   sPyCallables = 
6030: 22 22 0a 20 20 20 20 73 4a 53 43 61 6c 6c 61 62  "".    sJSCallab
6040: 6c 65 73 20 3d 20 22 22 0a 20 20 20 20 66 6f 72  les = "".    for
6050: 20 73 46 75 6e 63 4e 61 6d 65 2c 20 73 52 65 74   sFuncName, sRet
6060: 75 72 6e 20 69 6e 20 6c 46 55 4e 43 54 49 4f 4e  urn in lFUNCTION
6070: 53 3a 0a 20 20 20 20 20 20 20 20 69 66 20 73 46  S:.        if sF
6080: 75 6e 63 4e 61 6d 65 2e 73 74 61 72 74 73 77 69  uncName.startswi
6090: 74 68 28 22 5f 63 5f 22 29 3a 20 23 20 63 6f 6e  th("_c_"): # con
60a0: 64 69 74 69 6f 6e 0a 20 20 20 20 20 20 20 20 20  dition.         
60b0: 20 20 20 73 50 61 72 61 6d 73 20 3d 20 22 73 53     sParams = "sS
60c0: 65 6e 74 65 6e 63 65 2c 20 73 53 65 6e 74 65 6e  entence, sSenten
60d0: 63 65 30 2c 20 6d 2c 20 64 54 6f 6b 65 6e 50 6f  ce0, m, dTokenPo
60e0: 73 2c 20 73 43 6f 75 6e 74 72 79 2c 20 62 43 6f  s, sCountry, bCo
60f0: 6e 64 4d 65 6d 6f 22 0a 20 20 20 20 20 20 20 20  ndMemo".        
6100: 65 6c 69 66 20 73 46 75 6e 63 4e 61 6d 65 2e 73  elif sFuncName.s
6110: 74 61 72 74 73 77 69 74 68 28 22 5f 6d 5f 22 29  tartswith("_m_")
6120: 3a 20 23 20 6d 65 73 73 61 67 65 0a 20 20 20 20  : # message.    
6130: 20 20 20 20 20 20 20 20 73 50 61 72 61 6d 73 20          sParams 
6140: 3d 20 22 73 53 65 6e 74 65 6e 63 65 2c 20 6d 22  = "sSentence, m"
6150: 0a 20 20 20 20 20 20 20 20 65 6c 69 66 20 73 46  .        elif sF
6160: 75 6e 63 4e 61 6d 65 2e 73 74 61 72 74 73 77 69  uncName.startswi
6170: 74 68 28 22 5f 73 5f 22 29 3a 20 23 20 73 75 67  th("_s_"): # sug
6180: 67 65 73 74 69 6f 6e 0a 20 20 20 20 20 20 20 20  gestion.        
6190: 20 20 20 20 73 50 61 72 61 6d 73 20 3d 20 22 73      sParams = "s
61a0: 53 65 6e 74 65 6e 63 65 2c 20 6d 22 0a 20 20 20  Sentence, m".   
61b0: 20 20 20 20 20 65 6c 69 66 20 73 46 75 6e 63 4e       elif sFuncN
61c0: 61 6d 65 2e 73 74 61 72 74 73 77 69 74 68 28 22  ame.startswith("
61d0: 5f 70 5f 22 29 3a 20 23 20 70 72 65 70 72 6f 63  _p_"): # preproc
61e0: 65 73 73 6f 72 0a 20 20 20 20 20 20 20 20 20 20  essor.          
61f0: 20 20 73 50 61 72 61 6d 73 20 3d 20 22 73 53 65    sParams = "sSe
6200: 6e 74 65 6e 63 65 2c 20 6d 22 0a 20 20 20 20 20  ntence, m".     
6210: 20 20 20 65 6c 69 66 20 73 46 75 6e 63 4e 61 6d     elif sFuncNam
6220: 65 2e 73 74 61 72 74 73 77 69 74 68 28 22 5f 64  e.startswith("_d
6230: 5f 22 29 3a 20 23 20 64 69 73 61 6d 62 69 67 75  _"): # disambigu
6240: 61 74 6f 72 0a 20 20 20 20 20 20 20 20 20 20 20  ator.           
6250: 20 73 50 61 72 61 6d 73 20 3d 20 22 73 53 65 6e   sParams = "sSen
6260: 74 65 6e 63 65 2c 20 6d 2c 20 64 54 6f 6b 65 6e  tence, m, dToken
6270: 50 6f 73 22 0a 20 20 20 20 20 20 20 20 65 6c 73  Pos".        els
6280: 65 3a 0a 20 20 20 20 20 20 20 20 20 20 20 20 70  e:.            p
6290: 72 69 6e 74 28 66 22 23 20 55 6e 6b 6e 6f 77 6e  rint(f"# Unknown
62a0: 20 66 75 6e 63 74 69 6f 6e 20 74 79 70 65 20 69   function type i
62b0: 6e 20 3c 7b 73 46 75 6e 63 4e 61 6d 65 7d 3e 22  n <{sFuncName}>"
62c0: 29 0a 20 20 20 20 20 20 20 20 20 20 20 20 63 6f  ).            co
62d0: 6e 74 69 6e 75 65 0a 20 20 20 20 20 20 20 20 23  ntinue.        #
62e0: 20 50 79 74 68 6f 6e 0a 20 20 20 20 20 20 20 20   Python.        
62f0: 73 50 79 43 61 6c 6c 61 62 6c 65 73 20 2b 3d 20  sPyCallables += 
6300: 66 22 64 65 66 20 7b 73 46 75 6e 63 4e 61 6d 65  f"def {sFuncName
6310: 7d 20 28 7b 73 50 61 72 61 6d 73 7d 29 3a 5c 6e  } ({sParams}):\n
6320: 22 0a 20 20 20 20 20 20 20 20 73 50 79 43 61 6c  ".        sPyCal
6330: 6c 61 62 6c 65 73 20 2b 3d 20 66 22 20 20 20 20  lables += f"    
6340: 72 65 74 75 72 6e 20 7b 73 52 65 74 75 72 6e 7d  return {sReturn}
6350: 5c 6e 22 0a 20 20 20 20 20 20 20 20 23 20 4a 61  \n".        # Ja
6360: 76 61 53 63 72 69 70 74 0a 20 20 20 20 20 20 20  vaScript.       
6370: 20 73 4a 53 43 61 6c 6c 61 62 6c 65 73 20 2b 3d   sJSCallables +=
6380: 20 66 22 20 20 20 20 7b 73 46 75 6e 63 4e 61 6d   f"    {sFuncNam
6390: 65 7d 3a 20 66 75 6e 63 74 69 6f 6e 20 28 7b 73  e}: function ({s
63a0: 50 61 72 61 6d 73 7d 29 20 7b 7b 5c 6e 22 0a 20  Params}) {{\n". 
63b0: 20 20 20 20 20 20 20 73 4a 53 43 61 6c 6c 61 62         sJSCallab
63c0: 6c 65 73 20 2b 3d 20 22 20 20 20 20 20 20 20 20  les += "        
63d0: 72 65 74 75 72 6e 20 22 20 2b 20 6a 73 63 6f 6e  return " + jscon
63e0: 76 2e 70 79 32 6a 73 28 73 52 65 74 75 72 6e 29  v.py2js(sReturn)
63f0: 20 2b 20 22 3b 5c 6e 22 0a 20 20 20 20 20 20 20   + ";\n".       
6400: 20 73 4a 53 43 61 6c 6c 61 62 6c 65 73 20 2b 3d   sJSCallables +=
6410: 20 22 20 20 20 20 7d 2c 5c 6e 22 0a 0a 20 20 20   "    },\n"..   
6420: 20 64 69 73 70 6c 61 79 53 74 61 74 73 28 6c 50   displayStats(lP
6430: 61 72 61 67 72 61 70 68 52 75 6c 65 73 2c 20 6c  aragraphRules, l
6440: 53 65 6e 74 65 6e 63 65 52 75 6c 65 73 29 0a 0a  SentenceRules)..
6450: 20 20 20 20 64 56 61 72 73 20 3d 20 7b 0a 20 20      dVars = {.  
6460: 20 20 20 20 20 20 22 66 42 75 69 6c 64 54 69 6d        "fBuildTim
6470: 65 22 3a 20 66 42 75 69 6c 64 54 69 6d 65 2c 0a  e": fBuildTime,.
6480: 20 20 20 20 20 20 20 20 22 73 46 69 6c 65 48 61          "sFileHa
6490: 73 68 22 3a 20 73 46 69 6c 65 48 61 73 68 2c 0a  sh": sFileHash,.
64a0: 20 20 20 20 20 20 20 20 22 63 61 6c 6c 61 62 6c          "callabl
64b0: 65 73 22 3a 20 73 50 79 43 61 6c 6c 61 62 6c 65  es": sPyCallable
64c0: 73 2c 0a 20 20 20 20 20 20 20 20 22 63 61 6c 6c  s,.        "call
64d0: 61 62 6c 65 73 4a 53 22 3a 20 73 4a 53 43 61 6c  ablesJS": sJSCal
64e0: 6c 61 62 6c 65 73 2c 0a 20 20 20 20 20 20 20 20  lables,.        
64f0: 22 67 63 74 65 73 74 73 22 3a 20 73 47 43 54 65  "gctests": sGCTe
6500: 73 74 73 2c 0a 20 20 20 20 20 20 20 20 22 67 63  sts,.        "gc
6510: 74 65 73 74 73 4a 53 22 3a 20 73 47 43 54 65 73  testsJS": sGCTes
6520: 74 73 4a 53 2c 0a 20 20 20 20 20 20 20 20 22 70  tsJS,.        "p
6530: 61 72 61 67 72 61 70 68 5f 72 75 6c 65 73 22 3a  aragraph_rules":
6540: 20 63 72 65 61 74 65 52 75 6c 65 73 41 73 53 74   createRulesAsSt
6550: 72 69 6e 67 28 6d 65 72 67 65 52 75 6c 65 73 42  ring(mergeRulesB
6560: 79 4f 70 74 69 6f 6e 28 6c 50 61 72 61 67 72 61  yOption(lParagra
6570: 70 68 52 75 6c 65 73 29 29 2c 0a 20 20 20 20 20  phRules)),.     
6580: 20 20 20 22 73 65 6e 74 65 6e 63 65 5f 72 75 6c     "sentence_rul
6590: 65 73 22 3a 20 63 72 65 61 74 65 52 75 6c 65 73  es": createRules
65a0: 41 73 53 74 72 69 6e 67 28 6d 65 72 67 65 52 75  AsString(mergeRu
65b0: 6c 65 73 42 79 4f 70 74 69 6f 6e 28 6c 53 65 6e  lesByOption(lSen
65c0: 74 65 6e 63 65 52 75 6c 65 73 29 29 2c 0a 20 20  tenceRules)),.  
65d0: 20 20 20 20 20 20 22 70 61 72 61 67 72 61 70 68        "paragraph
65e0: 5f 72 75 6c 65 73 5f 4a 53 22 3a 20 6a 73 63 6f  _rules_JS": jsco
65f0: 6e 76 2e 77 72 69 74 65 52 75 6c 65 73 54 6f 4a  nv.writeRulesToJ
6600: 53 41 72 72 61 79 28 6d 65 72 67 65 52 75 6c 65  SArray(mergeRule
6610: 73 42 79 4f 70 74 69 6f 6e 28 6c 50 61 72 61 67  sByOption(lParag
6620: 72 61 70 68 52 75 6c 65 73 4a 53 29 29 2c 0a 20  raphRulesJS)),. 
6630: 20 20 20 20 20 20 20 22 73 65 6e 74 65 6e 63 65         "sentence
6640: 5f 72 75 6c 65 73 5f 4a 53 22 3a 20 6a 73 63 6f  _rules_JS": jsco
6650: 6e 76 2e 77 72 69 74 65 52 75 6c 65 73 54 6f 4a  nv.writeRulesToJ
6660: 53 41 72 72 61 79 28 6d 65 72 67 65 52 75 6c 65  SArray(mergeRule
6670: 73 42 79 4f 70 74 69 6f 6e 28 6c 53 65 6e 74 65  sByOption(lSente
6680: 6e 63 65 52 75 6c 65 73 4a 53 29 29 0a 20 20 20  nceRulesJS)).   
6690: 20 7d 0a 20 20 20 20 64 56 61 72 73 2e 75 70 64   }.    dVars.upd
66a0: 61 74 65 28 64 4f 70 74 69 6f 6e 73 29 0a 0a 20  ate(dOptions).. 
66b0: 20 20 20 23 20 63 6f 6d 70 69 6c 65 20 67 72 61     # compile gra
66c0: 70 68 20 72 75 6c 65 73 0a 20 20 20 20 64 56 61  ph rules.    dVa
66d0: 72 73 32 20 3d 20 63 72 67 2e 6d 61 6b 65 28 6c  rs2 = crg.make(l
66e0: 47 72 61 70 68 52 75 6c 65 2c 20 73 4c 61 6e 67  GraphRule, sLang
66f0: 2c 20 64 44 45 46 49 4e 49 54 49 4f 4e 53 2c 20  , dDEFINITIONS, 
6700: 64 44 45 43 4c 45 4e 53 49 4f 4e 53 2c 20 64 4f  dDECLENSIONS, dO
6710: 70 74 50 72 69 6f 72 69 74 79 29 0a 20 20 20 20  ptPriority).    
6720: 64 56 61 72 73 2e 75 70 64 61 74 65 28 64 56 61  dVars.update(dVa
6730: 72 73 32 29 0a 0a 20 20 20 20 77 69 74 68 20 6f  rs2)..    with o
6740: 70 65 6e 28 22 5f 62 75 69 6c 64 2f 64 61 74 61  pen("_build/data
6750: 5f 63 61 63 68 65 2e 6a 73 6f 6e 22 2c 20 22 77  _cache.json", "w
6760: 22 2c 20 65 6e 63 6f 64 69 6e 67 3d 22 75 74 66  ", encoding="utf
6770: 2d 38 22 29 20 61 73 20 68 44 73 74 3a 0a 20 20  -8") as hDst:.  
6780: 20 20 20 20 20 20 68 44 73 74 2e 77 72 69 74 65        hDst.write
6790: 28 6a 73 6f 6e 2e 64 75 6d 70 73 28 64 56 61 72  (json.dumps(dVar
67a0: 73 2c 20 65 6e 73 75 72 65 5f 61 73 63 69 69 3d  s, ensure_ascii=
67b0: 46 61 6c 73 65 29 29 0a 20 20 20 20 72 65 74 75  False)).    retu
67c0: 72 6e 20 64 56 61 72 73 0a                       rn dVars.