cppgolf 0.1.0__tar.gz → 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cppgolf
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: C++ multi-file merge & code golf / minifier tool
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/yourname/cppgolf
@@ -96,8 +96,8 @@ def build_parser() -> argparse.ArgumentParser:
96
96
  help='单语句 if/for/while 去花括号')
97
97
  g2.add_argument('--shortcuts', dest='define_shortcuts', action='store_true',
98
98
  help='高频 cout/cin 用 #define 缩写')
99
- g2.add_argument('--rename', dest='rename_symbols', action='store_true',
100
- help='将用户变量/成员名压缩为短名(需要 tree-sitter-cpp)')
99
+ g2.add_argument('-no-rename', dest='no_rename_symbols', action='store_true',
100
+ help='不将用户变量/成员名压缩为短名(需要 tree-sitter-cpp)')
101
101
 
102
102
  p.add_argument('--stats', action='store_true', help='显示压缩率统计')
103
103
  return p
@@ -124,7 +124,7 @@ def main():
124
124
  keep_inline=args.keep_inline,
125
125
  aggressive=args.aggressive,
126
126
  define_shortcuts=args.define_shortcuts,
127
- rename_symbols=args.rename_symbols,
127
+ rename_symbols=not(args.no_rename_symbols),
128
128
  )
129
129
 
130
130
  def print_stats(final_size: int):
@@ -2,9 +2,11 @@
2
2
  golf_rename.py — Pass 5: 符号名压缩(tree-sitter AST 驱动)
3
3
  """
4
4
  import re
5
- import sys
6
5
  import itertools
7
6
 
7
+ from tree_sitter import Language, Parser
8
+ import tree_sitter_cpp as tscpp
9
+
8
10
  _DECLARATOR_CONTAINERS = frozenset({
9
11
  'init_declarator', 'pointer_declarator', 'reference_declarator',
10
12
  'array_declarator', 'abstract_pointer_declarator',
@@ -12,6 +14,28 @@ _DECLARATOR_CONTAINERS = frozenset({
12
14
  })
13
15
  _MIN_RENAME_LEN = 2
14
16
 
17
+ # C/C++ 保留关键字,生成短名时不得使用
18
+ _CXX_KEYWORDS = frozenset({
19
+ # C keywords
20
+ 'auto', 'break', 'case', 'char', 'const', 'continue', 'default',
21
+ 'do', 'double', 'else', 'enum', 'extern', 'float', 'for', 'goto',
22
+ 'if', 'inline', 'int', 'long', 'register', 'restrict', 'return',
23
+ 'short', 'signed', 'sizeof', 'static', 'struct', 'switch', 'typedef',
24
+ 'union', 'unsigned', 'void', 'volatile', 'while',
25
+ # C++ keywords
26
+ 'alignas', 'alignof', 'and', 'and_eq', 'asm', 'bitand', 'bitor',
27
+ 'bool', 'catch', 'class', 'compl', 'concept', 'consteval', 'constexpr',
28
+ 'constinit', 'co_await', 'co_return', 'co_yield', 'decltype', 'delete',
29
+ 'explicit', 'export', 'false', 'friend', 'mutable', 'namespace',
30
+ 'new', 'noexcept', 'not', 'not_eq', 'nullptr', 'operator', 'or',
31
+ 'or_eq', 'private', 'protected', 'public', 'requires', 'static_assert',
32
+ 'static_cast', 'dynamic_cast', 'reinterpret_cast', 'const_cast',
33
+ 'template', 'this', 'thread_local', 'throw', 'true', 'try', 'typeid',
34
+ 'typename', 'using', 'virtual', 'wchar_t', 'xor', 'xor_eq',
35
+ # common macros / built-ins that must not be shadowed
36
+ 'NULL', 'TRUE', 'FALSE', 'EOF', 'stdin', 'stdout', 'stderr',
37
+ })
38
+
15
39
 
16
40
  def _gen_short_names():
17
41
  for length in itertools.count(1):
@@ -54,14 +78,20 @@ class _RenameCtx:
54
78
  return self.src[node.start_byte:node.end_byte].decode('utf-8')
55
79
 
56
80
  def _get_primary_type_name(self, node) -> str | None:
81
+ result = None
57
82
  for ch in node.children:
58
83
  if ch.type in ('type_identifier', 'primitive_type'):
59
- return self.name_of(ch)
60
- if ch.type == 'qualified_identifier':
84
+ result = self.name_of(ch)
85
+ elif ch.type == 'qualified_identifier':
61
86
  for sub in reversed(ch.children):
62
87
  if sub.type in ('identifier', 'type_identifier'):
63
- return self.name_of(sub)
64
- return None
88
+ result = self.name_of(sub); break
89
+ elif ch.type == 'ERROR':
90
+ # tree-sitter 遇到宏(如 F_BEGIN)时会把真正的类型包进 ERROR 节点
91
+ for sub in ch.children:
92
+ if sub.type in ('type_identifier', 'identifier'):
93
+ result = self.name_of(sub); break
94
+ return result
65
95
 
66
96
  def _is_qid_name(self, node) -> bool:
67
97
  par = node.parent
@@ -219,16 +249,82 @@ class _RenameCtx:
219
249
  if vtype:
220
250
  return vtype
221
251
  return self._extract_init_cast_type(child, var_name)
252
+ # function_definition:参数列表不在祖先链上,需主动下探
253
+ if node.type == 'function_definition':
254
+ for child in node.children:
255
+ if child.type in ('function_declarator', 'pointer_declarator',
256
+ 'reference_declarator'):
257
+ for sub in child.children:
258
+ if sub.type == 'parameter_list':
259
+ for param in sub.children:
260
+ if param.type != 'parameter_declaration':
261
+ continue
262
+ vtype = self._get_primary_type_name(param)
263
+ if not vtype:
264
+ continue
265
+ for ch in param.children:
266
+ if ch.type == 'identifier' and self.name_of(ch) == var_name:
267
+ return vtype
268
+ elif ch.type in _DECLARATOR_CONTAINERS:
269
+ id_nd = _extract_declarator_id(ch, False)
270
+ if id_nd and self.name_of(id_nd) == var_name:
271
+ return vtype
272
+ # for-range loop 变量:for (Type var : range)
273
+ if node.type == 'for_range_loop':
274
+ loop_type = self._get_primary_type_name(node) # 直接子节点里找 type_identifier
275
+ found_first = False
276
+ for ch in node.children:
277
+ if ch.type in (':', 'compound_statement'):
278
+ break
279
+ if ch.is_named and not found_first:
280
+ found_first = True # 跳过类型说明符节点本身
281
+ continue
282
+ if ch.type == 'identifier' and self.name_of(ch) == var_name:
283
+ return loop_type
284
+ elif ch.type in _DECLARATOR_CONTAINERS:
285
+ id_nd = _extract_declarator_id(ch, False)
286
+ if id_nd and self.name_of(id_nd) == var_name:
287
+ return loop_type
288
+ # 类/结构体成员字段(方法内访问 this->field 或其他成员变量)
289
+ if node.type in ('struct_specifier', 'class_specifier', 'union_specifier'):
290
+ for ch in node.children:
291
+ if ch.type == 'field_declaration_list':
292
+ for fd in ch.children:
293
+ if fd.type != 'field_declaration':
294
+ continue
295
+ vtype = self._get_primary_type_name(fd)
296
+ for fc in fd.children:
297
+ if fc.type == 'field_identifier' and self.name_of(fc) == var_name:
298
+ return vtype
299
+ elif fc.type in _DECLARATOR_CONTAINERS or fc.type == 'init_declarator':
300
+ id_nd = _extract_declarator_id(fc, True)
301
+ if id_nd and self.name_of(id_nd) == var_name:
302
+ return vtype
303
+ break
222
304
  node = node.parent
223
305
  return self.var_type_map.get(var_name)
224
306
 
225
307
  # ── 字段访问对象类型推断 ─────────────────────────────────────────────
308
+ def _enclosing_class(self, node) -> str | None:
309
+ """向上找最近的 class/struct/union 定义,返回其名字。"""
310
+ n = node.parent
311
+ while n is not None:
312
+ if n.type in ('struct_specifier', 'class_specifier', 'union_specifier'):
313
+ for ch in n.children:
314
+ if ch.type == 'type_identifier':
315
+ return self.name_of(ch)
316
+ n = n.parent
317
+ return None
318
+
226
319
  def _resolve_field_object_type(self, field_expr_node) -> str | None:
227
320
  if not field_expr_node.children:
228
321
  return None
229
322
  value_node = field_expr_node.children[0]
230
323
  vt = value_node.type
231
324
  td = self.typedef_map
325
+ if vt == 'this':
326
+ cls = self._enclosing_class(field_expr_node)
327
+ return td.get(cls, cls) if cls else None
232
328
  if vt == 'identifier':
233
329
  t = self._lookup_var_type_in_scope(value_node)
234
330
  return td.get(t, t)
@@ -255,198 +351,191 @@ class _RenameCtx:
255
351
  elif arr.type == 'field_expression':
256
352
  return self._resolve_field_object_type(arr)
257
353
  return None
258
-
259
- # ── 步骤 1:收集声明位节点 ────────────────────────────────────────────
260
- def collect_decl_nodes(self):
261
- local_decl: list = []
262
- member_decl: list = []
263
-
264
- def walk(node):
265
- nt = node.type
266
- if nt == 'declaration':
267
- for ch in node.children:
268
- if ch.type == 'identifier':
269
- local_decl.append(ch)
270
- elif ch.type in _DECLARATOR_CONTAINERS or ch.type == 'init_declarator':
271
- id_node = _extract_declarator_id(ch, False)
272
- if id_node: local_decl.append(id_node)
273
- elif ch.type == 'function_declarator':
274
- decl_type = self._get_primary_type_name(node)
275
- if decl_type and decl_type in self.user_struct_names:
276
- for sub in ch.children:
277
- if sub.type == 'identifier':
278
- local_decl.append(sub); break
279
- elif nt == 'parameter_declaration':
280
- for ch in node.children:
281
- if ch.type == 'identifier':
282
- local_decl.append(ch)
283
- elif ch.type in _DECLARATOR_CONTAINERS:
284
- id_node = _extract_declarator_id(ch, False)
285
- if id_node: local_decl.append(id_node)
286
- elif nt == 'for_range_loop':
287
- found_type = False
288
- for ch in node.children:
289
- if ch.type in (':', 'compound_statement'): break
290
- if ch.is_named and not found_type:
291
- found_type = True; continue
292
- if ch.type == 'identifier':
293
- local_decl.append(ch); break
294
- elif ch.type in _DECLARATOR_CONTAINERS:
295
- id_node = _extract_declarator_id(ch, False)
296
- if id_node: local_decl.append(id_node)
297
- break
298
- elif nt == 'field_declaration':
299
- for ch in node.children:
300
- if ch.type == 'field_identifier':
301
- member_decl.append(ch)
302
- elif ch.type in _DECLARATOR_CONTAINERS or ch.type == 'init_declarator':
303
- id_node = _extract_declarator_id(ch, True)
304
- if id_node: member_decl.append(id_node)
305
- if nt == 'function_declarator':
306
- for ch in node.children:
307
- if ch.type != 'identifier': walk(ch)
308
- else:
309
- for ch in node.children: walk(ch)
310
-
311
- walk(self.tree.root_node)
312
- return local_decl, member_decl
313
-
314
- # ── 步骤 3:统计频率 ──────────────────────────────────────────────────
315
- def count_freq(self, local_names, member_names) -> dict:
316
- freq: dict = {}
317
- def walk(node):
318
- if node.type == 'identifier':
319
- n = self.name_of(node)
320
- if n in local_names:
321
- freq[n] = freq.get(n, 0) + 1
322
- elif n in member_names and self._is_qid_name(node):
323
- scope_cls = self._get_qid_scope_class(node.parent)
324
- real_cls = self.typedef_map.get(scope_cls, scope_cls) if scope_cls else None
325
- if real_cls and real_cls in self.user_struct_names:
326
- freq[n] = freq.get(n, 0) + 1
327
- elif node.type == 'field_identifier':
328
- n = self.name_of(node)
329
- if n in member_names: freq[n] = freq.get(n, 0) + 1
330
- elif node.type == 'type_identifier':
331
- n = self.name_of(node)
332
- if n in local_names:
333
- par = node.parent
334
- if (par and par.type == 'parameter_declaration'
335
- and par.parent and par.parent.type == 'parameter_list'
336
- and par.parent.parent and par.parent.parent.type == 'function_declarator'
337
- and par.parent.parent.parent
338
- and par.parent.parent.parent.type == 'declaration'):
339
- freq[n] = freq.get(n, 0) + 1
340
- for ch in node.children: walk(ch)
341
- walk(self.tree.root_node)
354
+
355
+ # ── 步骤 1:收集声明位节点 ────────────────────────────────────────────
356
+ def collect_decl_nodes(self):
357
+ local_decl: list = []
358
+ member_decl: list = []
359
+
360
+ def walk(node):
361
+ nt = node.type
362
+ if nt == 'declaration':
363
+ for ch in node.children:
364
+ if ch.type == 'identifier':
365
+ local_decl.append(ch)
366
+ elif ch.type in _DECLARATOR_CONTAINERS or ch.type == 'init_declarator':
367
+ id_node = _extract_declarator_id(ch, False)
368
+ if id_node: local_decl.append(id_node)
369
+ elif ch.type == 'function_declarator':
370
+ decl_type = self._get_primary_type_name(node)
371
+ if decl_type and decl_type in self.user_struct_names:
372
+ for sub in ch.children:
373
+ if sub.type == 'identifier':
374
+ local_decl.append(sub); break
375
+ elif nt == 'parameter_declaration':
376
+ for ch in node.children:
377
+ if ch.type == 'identifier':
378
+ local_decl.append(ch)
379
+ elif ch.type in _DECLARATOR_CONTAINERS:
380
+ id_node = _extract_declarator_id(ch, False)
381
+ if id_node: local_decl.append(id_node)
382
+ elif nt == 'for_range_loop':
383
+ found_type = False
384
+ for ch in node.children:
385
+ if ch.type in (':', 'compound_statement'): break
386
+ if ch.is_named and not found_type:
387
+ found_type = True; continue
388
+ if ch.type == 'identifier':
389
+ local_decl.append(ch); break
390
+ elif ch.type in _DECLARATOR_CONTAINERS:
391
+ id_node = _extract_declarator_id(ch, False)
392
+ if id_node: local_decl.append(id_node)
393
+ break
394
+ elif nt == 'field_declaration':
395
+ for ch in node.children:
396
+ if ch.type == 'field_identifier':
397
+ member_decl.append(ch)
398
+ elif ch.type in _DECLARATOR_CONTAINERS or ch.type == 'init_declarator':
399
+ id_node = _extract_declarator_id(ch, True)
400
+ if id_node: member_decl.append(id_node)
401
+ if nt == 'function_declarator':
402
+ for ch in node.children:
403
+ if ch.type != 'identifier': walk(ch)
404
+ else:
405
+ for ch in node.children: walk(ch)
406
+
407
+ walk(self.tree.root_node)
408
+ return local_decl, member_decl
409
+
410
+ # ── 步骤 3:统计频率 ──────────────────────────────────────────────────
411
+ def count_freq(self, local_names, member_names) -> dict:
412
+ freq: dict = {}
413
+ def walk(node):
414
+ if node.type == 'identifier':
415
+ n = self.name_of(node)
416
+ if n in local_names:
417
+ freq[n] = freq.get(n, 0) + 1
418
+ elif n in member_names and self._is_qid_name(node):
419
+ scope_cls = self._get_qid_scope_class(node.parent)
420
+ real_cls = self.typedef_map.get(scope_cls, scope_cls) if scope_cls else None
421
+ if real_cls and real_cls in self.user_struct_names:
422
+ freq[n] = freq.get(n, 0) + 1
423
+ elif node.type == 'field_identifier':
424
+ n = self.name_of(node)
425
+ if n in member_names: freq[n] = freq.get(n, 0) + 1
426
+ elif node.type == 'type_identifier':
427
+ n = self.name_of(node)
428
+ if n in local_names:
429
+ par = node.parent
430
+ if (par and par.type == 'parameter_declaration'
431
+ and par.parent and par.parent.type == 'parameter_list'
432
+ and par.parent.parent and par.parent.parent.type == 'function_declarator'
433
+ and par.parent.parent.parent
434
+ and par.parent.parent.parent.type == 'declaration'):
435
+ freq[n] = freq.get(n, 0) + 1
436
+ for ch in node.children: walk(ch)
437
+ walk(self.tree.root_node)
342
438
  return freq
343
-
344
- # ── 步骤 5:收集替换位置 ──────────────────────────────────────────────
345
- def build_replacements(self, rename_map, local_names, member_names):
346
- replacements: list = []
347
- class_stack: list = []
348
-
349
- def walk(node):
350
- entered = False
351
- nt = node.type
352
- if nt in ('struct_specifier', 'class_specifier', 'union_specifier'):
353
- for ch in node.children:
354
- if ch.type == 'type_identifier':
355
- class_stack.append(self.name_of(ch)); entered = True; break
356
-
357
- if nt == 'identifier':
358
- n = self.name_of(node)
359
- if n in rename_map and n in local_names:
360
- replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
361
- elif n in rename_map and n in member_names and class_stack:
362
- replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
363
- elif n in rename_map and n in member_names and self._is_qid_name(node):
364
- scope_cls = self._get_qid_scope_class(node.parent)
365
- real_cls = self.typedef_map.get(scope_cls, scope_cls) if scope_cls else None
366
- if real_cls and real_cls in self.user_struct_names:
367
- replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
368
- elif nt == 'type_identifier':
369
- n = self.name_of(node)
370
- if n in rename_map and n in local_names:
371
- par = node.parent
372
- if (par and par.type == 'parameter_declaration'
373
- and par.parent and par.parent.type == 'parameter_list'
374
- and par.parent.parent and par.parent.parent.type == 'function_declarator'
375
- and par.parent.parent.parent
376
- and par.parent.parent.parent.type == 'declaration'):
377
- decl_type = self._get_primary_type_name(par.parent.parent.parent)
378
- if decl_type and decl_type in self.user_struct_names:
379
- replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
380
- elif nt == 'field_identifier':
381
- n = self.name_of(node)
382
- if n in rename_map and n in member_names:
383
- parent = node.parent
384
- if parent and parent.type == 'field_expression':
385
- obj_type = self._resolve_field_object_type(parent)
386
- if obj_type and obj_type in self.user_struct_names:
387
- replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
388
- else:
389
- replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
390
-
391
- for ch in node.children: walk(ch)
392
- if entered: class_stack.pop()
393
-
394
- walk(self.tree.root_node)
395
- return replacements
396
-
397
- # ── 步骤 6:应用替换 ──────────────────────────────────────────────────
398
- def apply(self, replacements) -> str:
399
- replacements.sort(key=lambda x: x[0], reverse=True)
400
- buf = bytearray(self.src)
401
- for start, end, new in replacements:
402
- buf[start:end] = new
403
- return buf.decode('utf-8')
404
-
405
-
406
- # ─────────────────────────────────────────────────────────────────────────────
407
- # 公开入口
408
- # ─────────────────────────────────────────────────────────────────────────────
409
- def golf_rename_symbols(code: str) -> str:
410
- try:
411
- from tree_sitter import Language, Parser
412
- import tree_sitter_cpp as tscpp
413
- _lang = Language(tscpp.language())
414
- except ImportError:
415
- print('[警告] 未找到 tree-sitter,跳过符号重命名。'
416
- ' 运行: pip install tree-sitter tree-sitter-cpp', file=sys.stderr)
417
- return code
418
-
419
- src_bytes = code.encode('utf-8')
420
- parser = Parser(_lang)
421
- tree = parser.parse(src_bytes)
422
-
423
- ctx = _RenameCtx(src_bytes, tree)
424
- ctx.build_type_context()
425
-
426
- local_decl, member_decl = ctx.collect_decl_nodes()
427
- name_of = ctx.name_of
428
-
429
- local_names = {name_of(n) for n in local_decl if len(name_of(n)) >= _MIN_RENAME_LEN}
430
- member_names = {name_of(n) for n in member_decl if len(name_of(n)) >= _MIN_RENAME_LEN}
431
- if not local_names and not member_names:
432
- return code
433
-
434
- all_targets = local_names | member_names
435
- freq = ctx.count_freq(local_names, member_names)
436
-
437
- # 步骤 4:生成重命名映射
438
- all_existing = set(re.findall(r'\b[A-Za-z_]\w*\b', code))
439
- occupied = set(all_existing)
440
- rename_map: dict = {}
441
- gen = _gen_short_names()
442
- for original in sorted(all_targets, key=lambda x: -freq.get(x, 0)):
443
- short = next(gen)
444
- while short in occupied or short == original:
445
- short = next(gen)
446
- rename_map[original] = short
447
- occupied.add(short)
448
-
449
- replacements = ctx.build_replacements(rename_map, local_names, member_names)
450
- if not replacements:
451
- return code
439
+
440
+ # ── 步骤 5:收集替换位置 ──────────────────────────────────────────────
441
+ def build_replacements(self, rename_map, local_names, member_names):
442
+ replacements: list = []
443
+ class_stack: list = []
444
+
445
+ def walk(node):
446
+ entered = False
447
+ nt = node.type
448
+ if nt in ('struct_specifier', 'class_specifier', 'union_specifier'):
449
+ for ch in node.children:
450
+ if ch.type == 'type_identifier':
451
+ class_stack.append(self.name_of(ch)); entered = True; break
452
+
453
+ if nt == 'identifier':
454
+ n = self.name_of(node)
455
+ if n in rename_map and n in local_names:
456
+ replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
457
+ elif n in rename_map and n in member_names and class_stack:
458
+ replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
459
+ elif n in rename_map and n in member_names and self._is_qid_name(node):
460
+ scope_cls = self._get_qid_scope_class(node.parent)
461
+ real_cls = self.typedef_map.get(scope_cls, scope_cls) if scope_cls else None
462
+ if real_cls and real_cls in self.user_struct_names:
463
+ replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
464
+ elif nt == 'type_identifier':
465
+ n = self.name_of(node)
466
+ if n in rename_map and n in local_names:
467
+ par = node.parent
468
+ if (par and par.type == 'parameter_declaration'
469
+ and par.parent and par.parent.type == 'parameter_list'
470
+ and par.parent.parent and par.parent.parent.type == 'function_declarator'
471
+ and par.parent.parent.parent
472
+ and par.parent.parent.parent.type == 'declaration'):
473
+ decl_type = self._get_primary_type_name(par.parent.parent.parent)
474
+ if decl_type and decl_type in self.user_struct_names:
475
+ replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
476
+ elif nt == 'field_identifier':
477
+ n = self.name_of(node)
478
+ if n in rename_map and n in member_names:
479
+ parent = node.parent
480
+ if parent and parent.type == 'field_expression':
481
+ obj_type = self._resolve_field_object_type(parent)
482
+ if obj_type and obj_type in self.user_struct_names:
483
+ replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
484
+ else:
485
+ replacements.append((node.start_byte, node.end_byte, rename_map[n].encode()))
486
+
487
+ for ch in node.children: walk(ch)
488
+ if entered: class_stack.pop()
489
+
490
+ walk(self.tree.root_node)
491
+ return replacements
492
+
493
+ # ── 步骤 6:应用替换 ──────────────────────────────────────────────────
494
+ def apply(self, replacements) -> str:
495
+ replacements.sort(key=lambda x: x[0], reverse=True)
496
+ buf = bytearray(self.src)
497
+ for start, end, new in replacements:
498
+ buf[start:end] = new
499
+ return buf.decode('utf-8')
500
+
501
+
502
+ # ─────────────────────────────────────────────────────────────────────────────
503
+ # 公开入口
504
+ # ─────────────────────────────────────────────────────────────────────────────
505
+ def golf_rename_symbols(code: str) -> str:
506
+ _lang = Language(tscpp.language())
507
+
508
+ src_bytes = code.encode('utf-8')
509
+ parser = Parser(_lang)
510
+ tree = parser.parse(src_bytes)
511
+
512
+ ctx = _RenameCtx(src_bytes, tree)
513
+ ctx.build_type_context()
514
+
515
+ local_decl, member_decl = ctx.collect_decl_nodes()
516
+ name_of = ctx.name_of
517
+
518
+ local_names = {name_of(n) for n in local_decl if len(name_of(n)) >= _MIN_RENAME_LEN}
519
+ member_names = {name_of(n) for n in member_decl if len(name_of(n)) >= _MIN_RENAME_LEN}
520
+ if not local_names and not member_names:
521
+ return code
522
+
523
+ all_targets = local_names | member_names
524
+ freq = ctx.count_freq(local_names, member_names)
525
+
526
+ # 步骤 4:生成重命名映射
527
+ all_existing = set(re.findall(r'\b[A-Za-z_]\w*\b', code))
528
+ occupied = all_existing | _CXX_KEYWORDS
529
+ rename_map: dict = {}
530
+ gen = _gen_short_names()
531
+ for original in sorted(all_targets, key=lambda x: -freq.get(x, 0)):
532
+ short = next(gen)
533
+ while short in occupied or short == original:
534
+ short = next(gen)
535
+ rename_map[original] = short
536
+ occupied.add(short)
537
+
538
+ replacements = ctx.build_replacements(rename_map, local_names, member_names)
539
+ if not replacements:
540
+ return code
452
541
  return ctx.apply(replacements)
@@ -20,29 +20,40 @@ def golf_std_namespace(code: str) -> str:
20
20
 
21
21
 
22
22
  def golf_typedefs(code: str) -> str:
23
- """对高频长类型名添加 #define 缩写(出现 ≥2 次时触发)。"""
23
+ """对高频长类型名添加 typedef 缩写(出现 ≥2 次时触发)。"""
24
24
  replacements = [
25
- (r'\blong long\b', 'll', '#define ll long long'),
26
- (r'\bunsigned long long\b', 'ull', '#define ull unsigned long long'),
27
- (r'\blong double\b', 'ld', '#define ld long double'),
28
- (r'\bvector<int>\b', 'vi', '#define vi vector<int>'),
29
- (r'\bvector<ll>\b', 'vll', '#define vll vector<ll>'),
30
- (r'\bpair<int,int>\b', 'pii', '#define pii pair<int,int>'),
31
- (r'\bpair<ll,ll>\b', 'pll', '#define pll pair<ll,ll>'),
25
+ (r'\blong long\b', 'll', 'typedef long long ll;'),
26
+ (r'\bunsigned long long\b', 'ull', 'typedef unsigned long long ull;'),
27
+ (r'\blong double\b', 'ld', 'typedef long double ld;'),
28
+ (r'\bvector<int>\b', 'vi', 'typedef vector<int> vi;'),
29
+ (r'\bvector<ll>\b', 'vll', 'typedef vector<ll> vll;'),
30
+ (r'\bpair<int,int>\b', 'pii', 'typedef pair<int,int> pii;'),
31
+ (r'\bpair<ll,ll>\b', 'pll', 'typedef pair<ll,ll> pll;'),
32
32
  ]
33
33
  defines_to_add = []
34
34
  for pattern, short, defline in replacements:
35
- macro = defline.split()[1]
36
- if re.search(r'\b' + re.escape(macro) + r'\b', code):
37
- continue
38
- if len(re.findall(pattern, code)) >= 2:
35
+ # 提取缩写名(typedef ... short;)
36
+ macro = defline.rstrip(';').split()[-1]
37
+ # 匹配已有的 typedef 或 #define 形式
38
+ existing_re = re.compile(
39
+ r'^[ \t]*(?:'
40
+ r'typedef\b[^\n]+\b' + re.escape(macro) + r'\s*;'
41
+ r'|#[ \t]*define[ \t]+' + re.escape(macro) + r'\b[^\n]*'
42
+ r')[ \t]*\n?',
43
+ re.MULTILINE,
44
+ )
45
+ existing = existing_re.search(code)
46
+ if existing:
47
+ # 已有定义:从原位删掉,稍后统一插到顶部
48
+ code = code[:existing.start()] + code[existing.end():]
49
+ defines_to_add.append(defline)
50
+ elif len(re.findall(pattern, code)) >= 2:
39
51
  defines_to_add.append(defline)
40
52
  code = re.sub(pattern, short, code)
41
53
  if defines_to_add:
42
- last = max(
43
- (m.end() for m in re.finditer(r'^#(?:include|define)\b.*$', code, re.MULTILINE)),
44
- default=0,
45
- )
54
+ # 插入点:文件顶部 include 块末尾
55
+ include_ends = [m.end() for m in re.finditer(r'^[ \t]*#[ \t]*include\b.*$', code, re.MULTILINE)]
56
+ last = include_ends[-1] if include_ends else 0
46
57
  code = code[:last] + '\n' + '\n'.join(defines_to_add) + '\n' + code[last:]
47
58
  return code
48
59
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cppgolf
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: C++ multi-file merge & code golf / minifier tool
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/yourname/cppgolf
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cppgolf"
7
- version = "0.1.0"
7
+ version = "0.1.1"
8
8
  description = "C++ multi-file merge & code golf / minifier tool"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
File without changes
File without changes
File without changes
File without changes
File without changes