Skip to content

Commit 3c75eea

Browse files
authored
Merge pull request #520 from EvgSkv/main
Catch up ti2023.
2 parents 28769bf + 6f0b5ac commit 3c75eea

1 file changed

Lines changed: 49 additions & 2 deletions

File tree

parser_cpp/logica_parse_cpp.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,53 @@
4141
_LIB: Optional[ctypes.CDLL] = None
4242

4343

44+
_KEY_ORDER_PRIORITY = {
45+
# High-level rule structure.
46+
'head': 0,
47+
'body': 1,
48+
'full_text': 99,
49+
50+
# Common predicate/call shapes.
51+
'predicate_name': 0,
52+
'record': 1,
53+
'field_value': 0,
54+
'field': 0,
55+
'value': 1,
56+
57+
# Expressions.
58+
'expression': 0,
59+
'literal': 1,
60+
'variable': 2,
61+
'predicate': 3,
62+
63+
# Bodies.
64+
'conjunction': 0,
65+
'conjunct': 1,
66+
}
67+
68+
69+
def _NormalizeKeyOrder(node):
70+
"""Recursively normalizes dict insertion order for downstream determinism.
71+
72+
The C++ parser produces JSON objects backed by `std::map`, so keys are
73+
serialized in lexicographic order. The Python parser creates dicts with
74+
a more semantic insertion order (e.g. head, body, full_text).
75+
76+
Some downstream code (notably type inference) walks dicts in insertion order,
77+
which can affect outcomes like assigned `type_id`s.
78+
79+
This function rebuilds dictionaries to approximate the Python parser's key
80+
order while preserving values exactly.
81+
"""
82+
if isinstance(node, list):
83+
return [_NormalizeKeyOrder(x) for x in node]
84+
if isinstance(node, dict):
85+
items = list(node.items())
86+
items.sort(key=lambda kv: (_KEY_ORDER_PRIORITY.get(kv[0], 50), kv[0]))
87+
return {k: _NormalizeKeyOrder(v) for k, v in items}
88+
return node
89+
90+
4491
def _GetParseModule():
4592
global _PARSE_MOD
4693
if _PARSE_MOD is not None:
@@ -267,7 +314,7 @@ def ParseRules(program_text: str,
267314
if rc != 0:
268315
raise _CppParsingExceptionClass(exception_thrower)(err)
269316
try:
270-
return json.loads(out)
317+
return _NormalizeKeyOrder(json.loads(out))
271318
except Exception as e:
272319
raise RuntimeError('Failed to json-parse C++ parser output: %s' % e) from e
273320

@@ -302,6 +349,6 @@ def ParseFile(program_text: str,
302349
if rc != 0:
303350
raise _CppParsingExceptionClass(exception_thrower)(err)
304351
try:
305-
return json.loads(out)
352+
return _NormalizeKeyOrder(json.loads(out))
306353
except Exception as e:
307354
raise RuntimeError('Failed to json-parse C++ parser output: %s' % e) from e

0 commit comments

Comments
 (0)