14
14
15
15
from ..prelude .kbool import TRUE
16
16
from ..prelude .ml import ML_QUANTIFIERS
17
- from ..utils import POSet , filter_none , single , unique
17
+ from ..utils import FrozenDict , POSet , filter_none , single , unique
18
18
from .att import EMPTY_ATT , Atts , Format , KAst , KAtt , WithKAtt
19
19
from .inner import (
20
20
KApply ,
37
37
from os import PathLike
38
38
from typing import Any , Final , TypeVar
39
39
40
- from ..utils import FrozenDict
41
-
42
40
RL = TypeVar ('RL' , bound = 'KRuleLike' )
43
41
44
42
_LOGGER : Final = logging .getLogger (__name__ )
@@ -1001,7 +999,6 @@ class KDefinition(KOuter, WithKAtt, Iterable[KFlatModule]):
1001
999
1002
1000
main_module : InitVar [KFlatModule ]
1003
1001
1004
- _production_for_klabel : dict [KLabel , KProduction ]
1005
1002
_init_config : dict [KSort , KInner ]
1006
1003
_empty_config : dict [KSort , KInner ]
1007
1004
@@ -1027,7 +1024,6 @@ def __init__(
1027
1024
object .__setattr__ (self , 'requires' , tuple (requires ))
1028
1025
object .__setattr__ (self , 'att' , att )
1029
1026
object .__setattr__ (self , 'main_module' , main_module )
1030
- object .__setattr__ (self , '_production_for_klabel' , {})
1031
1027
object .__setattr__ (self , '_init_config' , {})
1032
1028
object .__setattr__ (self , '_empty_config' , {})
1033
1029
@@ -1162,28 +1158,6 @@ def sentence_by_unique_id(self) -> dict[str, KSentence]:
1162
1158
unique_id_map [unique_id ] = sent
1163
1159
return unique_id_map
1164
1160
1165
- def production_for_klabel (self , klabel : KLabel ) -> KProduction :
1166
- """Returns the original production for a given `KLabel` (failing if 0 or >1 are returned)."""
1167
- if klabel not in self ._production_for_klabel :
1168
- prods = [prod for prod in self .productions if prod .klabel and prod .klabel .name == klabel .name ]
1169
- _prods = [prod for prod in prods if Atts .UNPARSE_AVOID not in prod .att ]
1170
- if len (_prods ) < len (prods ):
1171
- _LOGGER .warning (
1172
- f'Discarding { len (prods ) - len (_prods )} productions with `unparseAvoid` attribute for label: { klabel } '
1173
- )
1174
- prods = _prods
1175
- # Automatically defined symbols like isInt may get multiple
1176
- # definitions in different modules.
1177
- _prods = list ({prod .let_att (prod .att .drop_source ()) for prod in prods })
1178
- if len (_prods ) < len (prods ):
1179
- _LOGGER .warning (f'Discarding { len (prods ) - len (_prods )} equivalent productions' )
1180
- prods = _prods
1181
- try :
1182
- self ._production_for_klabel [klabel ] = single (prods )
1183
- except ValueError as err :
1184
- raise ValueError (f'Expected a single production for label { klabel } , not: { prods } ' ) from err
1185
- return self ._production_for_klabel [klabel ]
1186
-
1187
1161
def production_for_cell_sort (self , sort : KSort ) -> KProduction :
1188
1162
"""Returns the production for a given cell-declaration syntax from the cell's declared sort."""
1189
1163
# Typical cell production has 3 productions:
@@ -1208,11 +1182,11 @@ def module(self, name: str) -> KFlatModule:
1208
1182
1209
1183
def return_sort (self , label : KLabel ) -> KSort :
1210
1184
"""Returns the return sort of a given `KLabel` by looking up the production."""
1211
- return self .production_for_klabel ( label ) .sort
1185
+ return self .symbols [ label . name ] .sort
1212
1186
1213
1187
def argument_sorts (self , label : KLabel ) -> list [KSort ]:
1214
1188
"""Returns the argument sorts of a given `KLabel` by looking up the production."""
1215
- return self .production_for_klabel ( label ) .argument_sorts
1189
+ return self .symbols [ label . name ] .argument_sorts
1216
1190
1217
1191
@cached_property
1218
1192
def subsort_table (self ) -> FrozenDict [KSort , frozenset [KSort ]]:
@@ -1224,6 +1198,22 @@ def subsorts(self, sort: KSort) -> frozenset[KSort]:
1224
1198
"""Return all subsorts of a given `KSort` by inspecting the definition."""
1225
1199
return self .subsort_table .get (sort , frozenset ())
1226
1200
1201
+ @cached_property
1202
+ def symbols (self ) -> FrozenDict [str , KProduction ]:
1203
+ symbols : dict [str , KProduction ] = {}
1204
+ for prod in self .productions :
1205
+ if not prod .klabel :
1206
+ continue
1207
+ symbol = prod .klabel .name
1208
+ if symbol in symbols : # Check if duplicate
1209
+ other = symbols [symbol ]
1210
+ if prod .let (att = prod .att .drop_source ()) != other .let (att = prod .att .drop_source ()):
1211
+ prods = [other , prod ]
1212
+ raise AssertionError (f'Found multiple productions for { symbol } : { prods } ' )
1213
+ continue
1214
+ symbols [symbol ] = prod
1215
+ return FrozenDict (symbols )
1216
+
1227
1217
def sort (self , kast : KInner ) -> KSort | None :
1228
1218
"""Computes the sort of a given term using best-effort simple sorting algorithm, returns `None` on algorithm failure."""
1229
1219
match kast :
@@ -1238,7 +1228,7 @@ def sort(self, kast: KInner) -> KSort | None:
1238
1228
case KSequence (_):
1239
1229
return KSort ('K' )
1240
1230
case KApply (label , _):
1241
- prod = self .production_for_klabel ( label )
1231
+ prod = self .symbols [ label . name ]
1242
1232
if prod .sort not in prod .params :
1243
1233
return prod .sort
1244
1234
elif len (prod .params ) == len (label .params ):
@@ -1293,7 +1283,7 @@ def _add_ksequence_under_k_productions(_kast: KInner) -> KInner:
1293
1283
if type (_kast ) is not KApply :
1294
1284
return _kast
1295
1285
1296
- prod = self .production_for_klabel ( _kast .label )
1286
+ prod = self .symbols [ _kast .label . name ]
1297
1287
return KApply (
1298
1288
_kast .label ,
1299
1289
[
@@ -1358,7 +1348,7 @@ def transform(
1358
1348
del occurrences [var .name ]
1359
1349
return (Subst (subst )(term ), occurrences )
1360
1350
else :
1361
- prod = self .production_for_klabel ( term .label )
1351
+ prod = self .symbols [ term .label . name ]
1362
1352
if len (prod .params ) == 0 :
1363
1353
for t , a in zip (prod .argument_sorts , term .args , strict = True ):
1364
1354
if type (a ) is KVariable :
@@ -1386,7 +1376,7 @@ def add_sort_params(self, kast: KInner) -> KInner:
1386
1376
1387
1377
def _add_sort_params (_k : KInner ) -> KInner :
1388
1378
if type (_k ) is KApply :
1389
- prod = self .production_for_klabel ( _k .label )
1379
+ prod = self .symbols [ _k .label . name ]
1390
1380
if len (_k .label .params ) == 0 and len (prod .params ) > 0 :
1391
1381
sort_dict : dict [KSort , KSort ] = {}
1392
1382
for psort , asort in zip (prod .argument_sorts , map (self .sort , _k .args ), strict = True ):
@@ -1467,7 +1457,7 @@ def _kdefinition_empty_config(_sort: KSort) -> KApply:
1467
1457
cell_prod = self .production_for_cell_sort (_sort )
1468
1458
cell_klabel = cell_prod .klabel
1469
1459
assert cell_klabel is not None
1470
- production = self .production_for_klabel ( cell_klabel )
1460
+ production = self .symbols [ cell_klabel . name ]
1471
1461
args : list [KInner ] = []
1472
1462
num_nonterminals = 0
1473
1463
num_freshvars = 0
@@ -1490,8 +1480,8 @@ def instantiate_cell_vars(self, term: KInner) -> KInner:
1490
1480
1491
1481
def _cell_vars_to_labels (_kast : KInner ) -> KInner :
1492
1482
if type (_kast ) is KApply and _kast .is_cell :
1493
- production = self .production_for_klabel ( _kast .label )
1494
- production_arity = [prod_item .sort for prod_item in production .items if type ( prod_item ) is KNonTerminal ]
1483
+ production = self .symbols [ _kast .label . name ]
1484
+ production_arity = [item .sort for item in production .non_terminals ]
1495
1485
new_args = []
1496
1486
for sort , arg in zip (production_arity , _kast .args , strict = True ):
1497
1487
if sort .name .endswith ('Cell' ) and type (arg ) is KVariable :
0 commit comments