-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.py
116 lines (89 loc) · 2.38 KB
/
parser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env python3
import json
import sys
import time
from typing import Iterable
from absl import logging
from lark import Lark
# Lark has recursion issues
if sys.getrecursionlimit() < 5000:
sys.setrecursionlimit(5000)
NAMED_DICE = {
"coin": 2,
"pyramid": 4,
"cube": 6,
"tetrahedron": 8,
"octahedron": 8,
"decahedron": 10,
"dodecahedron": 12,
"icosahedron": 20,
"saving throw": 20,
"skill check": 20,
"to hit": 20,
"death saving throw": 20,
"percentile": 100,
"percent": 100
}
SPELLS = json.load(open("data/spells.json"))
WEAPONS = json.load(open("data/weapons.json"))
def list_to_lark_literal(
literal_name: str, values: Iterable[str], case_sensitive=False) -> str:
case_marker = "" if case_sensitive else "i"
spec = f"\n{literal_name}:"
spec += ("\n|").join(f"\"{v}\"{case_marker}" for v in values)
return spec
GRAMMER = '''
start: sum
%import common.INT
%ignore " "
%ignore ","
_PLUS: "+"i
| "plus"i
_MINUS: "-"i
| "minus"i
_TIMES: "*"i
| "times"i
| "multiplied by"i
| "multiplied with"i
sum: sum _PLUS mul -> add
| sum _MINUS mul -> sub
| mul -> value
mul: mul _TIMES value
| value -> value
value: dice
| critical
| advantage
| "("i sum ")"i
| INT
critical: "critical"i "to"i? "hit"i? "with"? "a"? _damage
| _damage -> value
_damage: WEAPON
| spell
dice: _die -> roll_one
| value _die -> roll_n
advantage: dice "with advantage"i
| dice "with disadvantage"i -> disadvantage
_die: "d"i value
| value "sided"i ("dice"i|"die"i)
| NAMED_DICE
spell: SPELL_NAME -> spell_default
| SPELL_NAME "at level"i INT
| SPELL_NAME "at"? INT _ORDINAL "level"i
| "level" INT SPELL_NAME -> spell_reversed
| INT _ORDINAL "level" SPELL_NAME -> spell_reversed
_ORDINAL: "st"i | "nd"i | "rd"i | "th"i
'''
GRAMMER += list_to_lark_literal("NAMED_DICE", NAMED_DICE.keys())
GRAMMER += list_to_lark_literal("WEAPON", (w["name"] for w in WEAPONS))
GRAMMER += list_to_lark_literal("SPELL_NAME", (s["name"] for s in SPELLS))
_PARSER = None
def initialize_parser():
global _PARSER
start = time.process_time()
_PARSER = Lark(GRAMMER)
end = time.process_time()
logging.info("compiling grammer took %f seconds", end-start)
def get_parser() -> Lark:
if _PARSER is None:
initialize_parser()
return _PARSER