lambda_custom.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. # Copyright (c) 2020-2022 Rocky Bernstein
  2. #
  3. # This program is free software: you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation, either version 3 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. """
  16. Grammar Customization rules for Python 3.7's Lambda expression grammar.
  17. """
  18. from decompyle3.parsers.p37.base import Python37BaseParser
  19. from decompyle3.parsers.parse_heads import nop_func
  20. class Python37LambdaCustom(Python37BaseParser):
  21. def __init__(self):
  22. self.new_rules = set()
  23. self.customized = {}
  24. def customize_grammar_rules_lambda37(self, tokens, customize):
  25. Python37BaseParser.customize_grammar_rules37(self, tokens, customize)
  26. self.check_reduce["call_kw"] = "AST"
  27. # For a rough break out on the first word. This may
  28. # include instructions that don't need customization,
  29. # but we'll do a finer check after the rough breakout.
  30. customize_instruction_basenames = frozenset(
  31. (
  32. "BEFORE",
  33. "BUILD",
  34. "CALL",
  35. "DICT",
  36. "GET",
  37. "FORMAT",
  38. "LIST",
  39. "LOAD",
  40. "MAKE",
  41. "SETUP",
  42. "UNPACK",
  43. )
  44. )
  45. # Opcode names in the custom_ops_processed set have rules that get added
  46. # unconditionally and the rules are constant. So they need to be done
  47. # only once and if we see the opcode a second we don't have to consider
  48. # adding more rules.
  49. #
  50. # Note: BUILD_TUPLE_UNPACK_WITH_CALL gets considered by
  51. # default because it starts with BUILD. So we'll set to ignore it from
  52. # the start.
  53. custom_ops_processed = {"BUILD_TUPLE_UNPACK_WITH_CALL"}
  54. for i, token in enumerate(tokens):
  55. opname = token.kind
  56. opname_base = opname[: opname.rfind("_")]
  57. # Do a quick breakout before testing potentially
  58. # each of the dozen or so instruction in if elif.
  59. if (
  60. opname[: opname.find("_")] not in customize_instruction_basenames
  61. or opname in custom_ops_processed
  62. ):
  63. continue
  64. if opname == "LOAD_ASSERT":
  65. if "PyPy" in customize:
  66. rules_str = """
  67. stmt ::= JUMP_IF_NOT_DEBUG stmts COME_FROM
  68. """
  69. self.add_unique_doc_rules(rules_str, customize)
  70. elif opname == "FORMAT_VALUE":
  71. rules_str = """
  72. expr ::= formatted_value1
  73. formatted_value1 ::= expr FORMAT_VALUE
  74. """
  75. self.add_unique_doc_rules(rules_str, customize)
  76. elif opname == "FORMAT_VALUE_ATTR":
  77. rules_str = """
  78. expr ::= formatted_value2
  79. formatted_value2 ::= expr expr FORMAT_VALUE_ATTR
  80. """
  81. self.add_unique_doc_rules(rules_str, customize)
  82. elif opname == "MAKE_FUNCTION_CLOSURE":
  83. if "LOAD_DICTCOMP" in self.seen_ops:
  84. # Is there something general going on here?
  85. rule = """
  86. dict_comp ::= load_closure LOAD_DICTCOMP LOAD_STR
  87. MAKE_FUNCTION_CLOSURE expr
  88. GET_ITER CALL_FUNCTION_1
  89. """
  90. self.addRule(rule, nop_func)
  91. elif "LOAD_SETCOMP" in self.seen_ops:
  92. rule = """
  93. set_comp ::= load_closure LOAD_SETCOMP LOAD_STR
  94. MAKE_FUNCTION_CLOSURE expr
  95. GET_ITER CALL_FUNCTION_1
  96. """
  97. self.addRule(rule, nop_func)
  98. elif opname == "BEFORE_ASYNC_WITH":
  99. rules_str = """
  100. stmt ::= async_with_stmt SETUP_ASYNC_WITH
  101. async_with_pre ::= BEFORE_ASYNC_WITH GET_AWAITABLE LOAD_CONST YIELD_FROM SETUP_ASYNC_WITH
  102. async_with_post ::= COME_FROM_ASYNC_WITH
  103. WITH_CLEANUP_START GET_AWAITABLE LOAD_CONST YIELD_FROM
  104. WITH_CLEANUP_FINISH END_FINALLY
  105. stmt ::= async_with_as_stmt
  106. async_with_as_stmt ::= expr
  107. async_with_pre
  108. store
  109. suite_stmts_opt
  110. POP_BLOCK LOAD_CONST
  111. async_with_post
  112. async_with_stmt ::= expr
  113. async_with_pre
  114. POP_TOP
  115. c_suite_stmts
  116. POP_BLOCK
  117. BEGIN_FINALLY
  118. WITH_CLEANUP_START GET_AWAITABLE LOAD_CONST YIELD_FROM
  119. WITH_CLEANUP_FINISH POP_FINALLY POP_TOP JUMP_FORWARD
  120. POP_BLOCK
  121. BEGIN_FINALLY
  122. COME_FROM_ASYNC_WITH
  123. WITH_CLEANUP_START
  124. GET_AWAITABLE
  125. LOAD_CONST
  126. YIELD_FROM
  127. WITH_CLEANUP_FINISH
  128. END_FINALLY
  129. async_with_stmt ::= expr
  130. async_with_pre
  131. POP_TOP
  132. suite_stmts_opt
  133. POP_BLOCK LOAD_CONST
  134. async_with_post
  135. async_with_stmt ::= expr
  136. async_with_pre
  137. POP_TOP
  138. suite_stmts_opt
  139. async_with_post
  140. """
  141. self.addRule(rules_str, nop_func)
  142. elif opname in ("BUILD_CONST_LIST", "BUILD_CONST_DICT", "BUILD_CONST_SET"):
  143. if opname == "BUILD_CONST_DICT":
  144. rule = f"""
  145. add_consts ::= ADD_VALUE*
  146. const_list ::= COLLECTION_START add_consts {opname}
  147. dict ::= const_list
  148. expr ::= dict
  149. """
  150. else:
  151. rule = f"""
  152. add_consts ::= ADD_VALUE*
  153. const_list ::= COLLECTION_START add_consts {opname}
  154. expr ::= const_list
  155. """
  156. self.addRule(rule, nop_func)
  157. elif opname_base in (
  158. "BUILD_LIST",
  159. "BUILD_SET",
  160. "BUILD_SET_UNPACK",
  161. "BUILD_TUPLE",
  162. "BUILD_TUPLE_UNPACK",
  163. ):
  164. v = token.attr
  165. is_LOAD_CLOSURE = False
  166. if opname_base == "BUILD_TUPLE":
  167. # If is part of a "load_closure", then it is not part of a
  168. # "list".
  169. is_LOAD_CLOSURE = True
  170. for j in range(v):
  171. if tokens[i - j - 1].kind != "LOAD_CLOSURE":
  172. is_LOAD_CLOSURE = False
  173. break
  174. if is_LOAD_CLOSURE:
  175. rule = "load_closure ::= %s%s" % (("LOAD_CLOSURE " * v), opname)
  176. self.add_unique_rule(rule, opname, token.attr, customize)
  177. elif opname_base == "BUILD_LIST":
  178. v = token.attr
  179. if v == 0:
  180. rule_str = """
  181. list ::= BUILD_LIST_0
  182. list_unpack ::= BUILD_LIST_0 expr LIST_EXTEND
  183. list ::= list_unpack
  184. """
  185. self.add_unique_doc_rules(rule_str, customize)
  186. elif opname == "BUILD_TUPLE_UNPACK_WITH_CALL":
  187. # FIXME: should this be parameterized by EX value?
  188. self.addRule(
  189. """expr ::= call_ex_kw3
  190. call_ex_kw3 ::= expr
  191. build_tuple_unpack_with_call
  192. expr
  193. CALL_FUNCTION_EX_KW
  194. """,
  195. nop_func,
  196. )
  197. if not is_LOAD_CLOSURE or v == 0:
  198. # We do this complicated test to speed up parsing of
  199. # pathelogically long literals, especially those over 1024.
  200. build_count = token.attr
  201. thousands = build_count // 1024
  202. thirty32s = (build_count // 32) % 32
  203. if thirty32s > 0:
  204. rule = "expr32 ::=%s" % (" expr" * 32)
  205. self.add_unique_rule(rule, opname_base, build_count, customize)
  206. pass
  207. if thousands > 0:
  208. self.add_unique_rule(
  209. "expr1024 ::=%s" % (" expr32" * 32),
  210. opname_base,
  211. build_count,
  212. customize,
  213. )
  214. pass
  215. collection = opname_base[opname_base.find("_") + 1 :].lower()
  216. rule = (
  217. ("%s ::= " % collection)
  218. + "expr1024 " * thousands
  219. + "expr32 " * thirty32s
  220. + "expr " * (build_count % 32)
  221. + opname
  222. )
  223. self.add_unique_rules(["expr ::= %s" % collection, rule], customize)
  224. continue
  225. continue
  226. elif opname.startswith("BUILD_STRING"):
  227. v = token.attr
  228. rules_str = """
  229. expr ::= joined_str
  230. joined_str ::= %sBUILD_STRING_%d
  231. """ % (
  232. "expr " * v,
  233. v,
  234. )
  235. self.add_unique_doc_rules(rules_str, customize)
  236. if "FORMAT_VALUE_ATTR" in self.seen_ops:
  237. rules_str = """
  238. formatted_value_attr ::= expr expr FORMAT_VALUE_ATTR expr BUILD_STRING
  239. expr ::= formatted_value_attr
  240. """
  241. self.add_unique_doc_rules(rules_str, customize)
  242. elif opname.startswith("BUILD_MAP_UNPACK_WITH_CALL"):
  243. v = token.attr
  244. rule = "build_map_unpack_with_call ::= %s%s" % ("expr " * v, opname)
  245. self.addRule(rule, nop_func)
  246. elif opname.startswith("BUILD_TUPLE_UNPACK_WITH_CALL"):
  247. v = token.attr
  248. rule = (
  249. "build_tuple_unpack_with_call ::= "
  250. + "expr1024 " * int(v // 1024)
  251. + "expr32 " * int((v // 32) % 32)
  252. + "expr " * (v % 32)
  253. + opname
  254. )
  255. self.addRule(rule, nop_func)
  256. rule = "starred ::= %s %s" % ("expr " * v, opname)
  257. self.addRule(rule, nop_func)
  258. elif opname == "FORMAT_VALUE":
  259. rules_str = """
  260. expr ::= formatted_value1
  261. formatted_value1 ::= expr FORMAT_VALUE
  262. """
  263. self.add_unique_doc_rules(rules_str, customize)
  264. elif opname == "FORMAT_VALUE_ATTR":
  265. rules_str = """
  266. expr ::= formatted_value2
  267. formatted_value2 ::= expr expr FORMAT_VALUE_ATTR
  268. """
  269. self.add_unique_doc_rules(rules_str, customize)
  270. elif opname == "GET_AITER":
  271. self.add_unique_doc_rules("get_aiter ::= expr GET_AITER", customize)
  272. self.addRule(
  273. """
  274. expr ::= dict_comp_async
  275. expr ::= generator_exp_async
  276. expr ::= list_comp_async
  277. dict_comp_async ::= LOAD_DICTCOMP
  278. LOAD_STR
  279. MAKE_FUNCTION_0
  280. get_aiter
  281. CALL_FUNCTION_1
  282. dict_comp_async ::= BUILD_MAP_0 LOAD_ARG
  283. dict_comp_async
  284. func_async_middle ::= POP_BLOCK JUMP_FORWARD COME_FROM_EXCEPT
  285. DUP_TOP LOAD_GLOBAL COMPARE_OP POP_JUMP_IF_TRUE
  286. END_FINALLY COME_FROM
  287. generator_exp_async ::= load_genexpr LOAD_STR MAKE_FUNCTION_0
  288. get_aiter CALL_FUNCTION_1
  289. # FIXME this is a workaround for probably some bug in the Earley parser
  290. # if we use get_aiter, then list_comp_async doesn't match, and I don't
  291. # understand why.
  292. expr_get_aiter ::= expr GET_AITER
  293. list_afor ::= get_aiter list_afor2
  294. list_afor2 ::= func_async_prefix
  295. store func_async_middle list_iter
  296. JUMP_LOOP COME_FROM
  297. POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP
  298. list_comp_async ::= BUILD_LIST_0 LOAD_ARG list_afor2
  299. list_comp_async ::= LOAD_LISTCOMP LOAD_STR MAKE_FUNCTION_0
  300. expr_get_aiter CALL_FUNCTION_1
  301. GET_AWAITABLE LOAD_CONST
  302. YIELD_FROM
  303. list_iter ::= list_afor
  304. set_comp_async ::= LOAD_SETCOMP
  305. LOAD_STR
  306. MAKE_FUNCTION_0
  307. get_aiter
  308. CALL_FUNCTION_1
  309. set_comp_async ::= LOAD_CLOSURE
  310. BUILD_TUPLE_1
  311. LOAD_SETCOMP
  312. LOAD_STR MAKE_FUNCTION_CLOSURE
  313. get_aiter CALL_FUNCTION_1
  314. await
  315. """,
  316. nop_func,
  317. )
  318. custom_ops_processed.add(opname)
  319. self.addRule(
  320. """
  321. dict_comp_async ::= BUILD_MAP_0 LOAD_ARG
  322. dict_comp_async
  323. expr ::= dict_comp_async
  324. expr ::= generator_exp_async
  325. expr ::= list_comp_async
  326. expr ::= set_comp_async
  327. func_async_middle ::= POP_BLOCK JUMP_FORWARD COME_FROM_EXCEPT
  328. DUP_TOP LOAD_GLOBAL COMPARE_OP POP_JUMP_IF_TRUE
  329. END_FINALLY _come_froms
  330. # async_iter ::= block_break SETUP_EXCEPT GET_ANEXT LOAD_CONST YIELD_FROM
  331. get_aiter ::= expr GET_AITER
  332. list_afor ::= get_aiter list_afor2
  333. list_comp_async ::= BUILD_LIST_0 LOAD_ARG list_afor2
  334. list_iter ::= list_afor
  335. set_afor ::= get_aiter set_afor2
  336. set_iter ::= set_afor
  337. set_comp_async ::= BUILD_SET_0 LOAD_ARG
  338. set_comp_async
  339. """,
  340. nop_func,
  341. )
  342. custom_ops_processed.add(opname)
  343. elif opname == "GET_ANEXT":
  344. self.addRule(
  345. """
  346. expr ::= genexpr_func_async
  347. expr ::= BUILD_MAP_0 genexpr_func_async
  348. expr ::= list_comp_async
  349. dict_comp_async ::= BUILD_MAP_0 genexpr_func_async
  350. async_iter ::= _come_froms
  351. SETUP_EXCEPT GET_ANEXT LOAD_CONST YIELD_FROM
  352. store_async_iter_end ::= store
  353. POP_BLOCK JUMP_FORWARD COME_FROM_EXCEPT
  354. DUP_TOP LOAD_GLOBAL COMPARE_OP POP_JUMP_IF_TRUE
  355. END_FINALLY COME_FROM
  356. func_async_prefix ::= _come_froms SETUP_EXCEPT GET_ANEXT LOAD_CONST YIELD_FROM
  357. # We use store_async_iter_end to make comp_iter come out in the right position,
  358. # (after the logical "store")
  359. genexpr_func_async ::= LOAD_ARG async_iter
  360. store_async_iter_end
  361. comp_iter
  362. JUMP_LOOP COME_FROM
  363. POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP
  364. genexpr_func_async ::= LOAD_ARG func_async_prefix
  365. store func_async_middle comp_iter
  366. JUMP_LOOP COME_FROM
  367. POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP
  368. list_afor2 ::= async_iter
  369. store
  370. list_iter
  371. JUMP_LOOP
  372. COME_FROM_FINALLY
  373. END_ASYNC_FOR
  374. list_comp_async ::= BUILD_LIST_0 LOAD_ARG list_afor2
  375. set_afor2 ::= async_iter
  376. store
  377. func_async_middle
  378. set_iter
  379. JUMP_LOOP COME_FROM
  380. POP_TOP POP_TOP POP_TOP POP_EXCEPT POP_TOP
  381. set_afor2 ::= expr_or_arg
  382. set_iter_async
  383. set_comp_async ::= BUILD_SET_0 set_afor2
  384. set_iter_async ::= async_iter
  385. store
  386. set_iter
  387. JUMP_LOOP
  388. _come_froms
  389. END_ASYNC_FOR
  390. return_expr_lambda ::= genexpr_func_async
  391. LOAD_CONST RETURN_VALUE
  392. RETURN_VALUE_LAMBDA
  393. return_expr_lambda ::= BUILD_SET_0 genexpr_func_async
  394. RETURN_VALUE_LAMBDA
  395. """,
  396. nop_func,
  397. )
  398. custom_ops_processed.add(opname)
  399. elif opname == "GET_AWAITABLE":
  400. rule_str = """
  401. await_expr ::= expr GET_AWAITABLE LOAD_CONST YIELD_FROM
  402. expr ::= await_expr
  403. """
  404. self.add_unique_doc_rules(rule_str, customize)
  405. elif opname == "GET_ITER":
  406. self.addRule(
  407. """
  408. expr ::= get_iter
  409. get_iter ::= expr GET_ITER
  410. """,
  411. nop_func,
  412. )
  413. custom_ops_processed.add(opname)
  414. elif opname == "LOAD_ASSERT":
  415. if "PyPy" in customize:
  416. rules_str = """
  417. stmt ::= JUMP_IF_NOT_DEBUG stmts COME_FROM
  418. """
  419. self.add_unique_doc_rules(rules_str, customize)
  420. elif opname == "LOAD_ATTR":
  421. self.addRule(
  422. """
  423. expr ::= attribute
  424. attribute ::= expr LOAD_ATTR
  425. """,
  426. nop_func,
  427. )
  428. custom_ops_processed.add(opname)
  429. elif opname == "MAKE_FUNCTION_CLOSURE":
  430. if "LOAD_DICTCOMP" in self.seen_ops:
  431. # Is there something general going on here?
  432. rule = """
  433. dict_comp ::= load_closure LOAD_DICTCOMP LOAD_STR
  434. MAKE_FUNCTION_CLOSURE expr
  435. GET_ITER CALL_FUNCTION_1
  436. """
  437. self.addRule(rule, nop_func)
  438. elif "LOAD_SETCOMP" in self.seen_ops:
  439. rule = """
  440. set_comp ::= load_closure LOAD_SETCOMP LOAD_STR
  441. MAKE_FUNCTION_CLOSURE expr
  442. GET_ITER CALL_FUNCTION_1
  443. """
  444. self.addRule(rule, nop_func)
  445. elif opname == "MAKE_FUNCTION_CLOSURE_POS":
  446. args_pos, args_kw, annotate_args, closure = token.attr
  447. stack_count = args_pos + args_kw + annotate_args
  448. if args_pos:
  449. # This was seen ion line 447 of Python 3.8
  450. # This is needed for Python 3.8 line 447 of site-packages/nltk/tgrep.py
  451. # line 447:
  452. # lambda i: lambda n, m=None, l=None: ...
  453. # which has
  454. # L. 447 0 LOAD_CONST (None, None)
  455. # 2 LOAD_CLOSURE 'i'
  456. # 4 LOAD_CLOSURE 'predicate'
  457. # 6 BUILD_TUPLE_2 2
  458. # 8 LOAD_LAMBDA '<code_object <lambda>>'
  459. # 10 LOAD_STR '_tgrep_relation_action.<locals>.<lambda>.<locals>.<lambda>'
  460. # 12 MAKE_FUNCTION_CLOSURE_POS 'default, closure'
  461. # FIXME: Possibly we need to generalize for more nested lambda's of lambda's?
  462. rule = """
  463. expr ::= lambda_body
  464. lambda_body ::= %s%s%s%s
  465. """ % (
  466. "expr " * stack_count,
  467. "load_closure " * closure,
  468. "LOAD_LAMBDA LOAD_STR ",
  469. opname,
  470. )
  471. self.add_unique_rule(rule, opname, token.attr, customize)
  472. elif opname == "SETUP_WITH":
  473. rules_str = """
  474. with ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH
  475. WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
  476. # Removes POP_BLOCK LOAD_CONST from 3.6-
  477. with_as ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH
  478. WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
  479. """
  480. if self.version < (3, 8):
  481. rules_str += """
  482. with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
  483. LOAD_CONST
  484. WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
  485. """
  486. else:
  487. rules_str += """
  488. with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
  489. BEGIN_FINALLY COME_FROM_WITH
  490. WITH_CLEANUP_START WITH_CLEANUP_FINISH
  491. END_FINALLY
  492. """
  493. self.addRule(rules_str, nop_func)
  494. pass
  495. pass
  496. def custom_classfunc_rule(self, opname, token, customize, next_token):
  497. args_pos, args_kw = self.get_pos_kw(token)
  498. # Additional exprs for * and ** args:
  499. # 0 if neither
  500. # 1 for CALL_FUNCTION_VAR or CALL_FUNCTION_KW
  501. # 2 for * and ** args (CALL_FUNCTION_VAR_KW).
  502. # Yes, this computation based on instruction name is a little bit hoaky.
  503. nak = (len(opname) - len("CALL_FUNCTION")) // 3
  504. uniq_param = args_kw + args_pos
  505. if frozenset(("GET_AWAITABLE", "YIELD_FROM")).issubset(self.seen_ops):
  506. rule_str = """
  507. await ::= GET_AWAITABLE LOAD_CONST YIELD_FROM
  508. await_expr ::= expr await
  509. expr ::= await_expr
  510. """
  511. self.add_unique_doc_rules(rule_str, customize)
  512. rule = (
  513. "async_call ::= expr "
  514. + ("expr " * args_pos)
  515. + ("kwarg " * args_kw)
  516. + "expr " * nak
  517. + token.kind
  518. + " GET_AWAITABLE LOAD_CONST YIELD_FROM"
  519. )
  520. self.add_unique_rule(rule, token.kind, uniq_param, customize)
  521. self.add_unique_rule(
  522. "expr ::= async_call", token.kind, uniq_param, customize
  523. )
  524. if opname.startswith("CALL_FUNCTION_KW"):
  525. self.addRule("expr ::= call_kw36", nop_func)
  526. values = "expr " * token.attr
  527. rule = "call_kw36 ::= expr {values} LOAD_CONST {opname}".format(**locals())
  528. self.add_unique_rule(rule, token.kind, token.attr, customize)
  529. elif opname == "CALL_FUNCTION_EX_KW":
  530. # Note that we don't add to customize token.kind here. Instead, the non-terminal
  531. # names call_ex_kw... are is in semantic actions.
  532. self.addRule(
  533. """expr ::= call_ex_kw4
  534. call_ex_kw4 ::= expr
  535. expr
  536. expr
  537. CALL_FUNCTION_EX_KW
  538. """,
  539. nop_func,
  540. )
  541. if "BUILD_MAP_UNPACK_WITH_CALL" in self.seen_op_basenames:
  542. self.addRule(
  543. """expr ::= call_ex_kw
  544. call_ex_kw ::= expr expr build_map_unpack_with_call
  545. CALL_FUNCTION_EX_KW
  546. """,
  547. nop_func,
  548. )
  549. if "BUILD_TUPLE_UNPACK_WITH_CALL" in self.seen_op_basenames:
  550. # FIXME: should this be parameterized by EX value?
  551. self.addRule(
  552. """expr ::= call_ex_kw3
  553. call_ex_kw3 ::= expr
  554. build_tuple_unpack_with_call
  555. expr
  556. CALL_FUNCTION_EX_KW
  557. """,
  558. nop_func,
  559. )
  560. if "BUILD_MAP_UNPACK_WITH_CALL" in self.seen_op_basenames:
  561. # FIXME: should this be parameterized by EX value?
  562. self.addRule(
  563. """expr ::= call_ex_kw2
  564. call_ex_kw2 ::= expr
  565. build_tuple_unpack_with_call
  566. build_map_unpack_with_call
  567. CALL_FUNCTION_EX_KW
  568. """,
  569. nop_func,
  570. )
  571. elif opname == "CALL_FUNCTION_EX":
  572. self.addRule(
  573. """
  574. expr ::= call_ex
  575. starred ::= expr
  576. call_ex ::= expr starred CALL_FUNCTION_EX
  577. """,
  578. nop_func,
  579. )
  580. if "BUILD_MAP_UNPACK_WITH_CALL" in self.seen_ops:
  581. self.addRule(
  582. """
  583. expr ::= call_ex_kw
  584. call_ex_kw ::= expr expr
  585. build_map_unpack_with_call CALL_FUNCTION_EX
  586. """,
  587. nop_func,
  588. )
  589. if "BUILD_TUPLE_UNPACK_WITH_CALL" in self.seen_ops:
  590. self.addRule(
  591. """
  592. expr ::= call_ex_kw3
  593. call_ex_kw3 ::= expr
  594. build_tuple_unpack_with_call
  595. %s
  596. CALL_FUNCTION_EX
  597. """
  598. % "expr "
  599. * token.attr,
  600. nop_func,
  601. )
  602. pass
  603. # FIXME: Is this right?
  604. self.addRule(
  605. """
  606. expr ::= call_ex_kw4
  607. call_ex_kw4 ::= expr
  608. expr
  609. expr
  610. CALL_FUNCTION_EX
  611. """,
  612. nop_func,
  613. )
  614. pass
  615. else:
  616. Python37BaseParser.custom_classfunc_rule(
  617. self, opname, token, customize, next_token
  618. )