vcode-analysis 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,906 @@
1
+ """Kotlin 正则解析器
2
+
3
+ 使用正则表达式快速解析 Kotlin 代码结构。
4
+ 支持 Kotlin 特有语法特性的识别。
5
+ """
6
+
7
+ import re
8
+ from pathlib import Path
9
+ from typing import Optional
10
+
11
+ from .models import (
12
+ KotlinASTResult,
13
+ KotlinFunctionInfo,
14
+ KotlinPropertyInfo,
15
+ KotlinClassInfo,
16
+ KotlinImportInfo,
17
+ KotlinSealedClassInfo,
18
+ KotlinWhenExpression,
19
+ KotlinCoroutineInfo,
20
+ KotlinFlowOperator,
21
+ KotlinTypeAlias,
22
+ KotlinValueClass,
23
+ KotlinDelegatedProperty,
24
+ KotlinExtensionFunction,
25
+ KotlinExtensionProperty,
26
+ KotlinObjectDeclaration,
27
+ KotlinEnumClassInfo,
28
+ KotlinDataClassInfo,
29
+ TERMINAL_FLOW_OPERATORS,
30
+ STANDARD_DELEGATES,
31
+ )
32
+ from .patterns import KOTLIN_PATTERNS, KOTLIN_ADVANCED_PATTERNS
33
+
34
+
35
+ class KotlinRegexParser:
36
+ """Kotlin 正则解析器(快速模式)"""
37
+
38
+ def __init__(self):
39
+ self.patterns = {**KOTLIN_PATTERNS, **KOTLIN_ADVANCED_PATTERNS}
40
+ # 预编译正则表达式
41
+ self._compiled = {}
42
+ for name, pattern in self.patterns.items():
43
+ try:
44
+ self._compiled[name] = re.compile(pattern, re.MULTILINE)
45
+ except re.error:
46
+ pass # 忽略编译错误的模式
47
+
48
+ def parse_file(self, file_path: str) -> KotlinASTResult:
49
+ """解析 Kotlin 文件"""
50
+ path = Path(file_path)
51
+
52
+ if not path.exists():
53
+ return KotlinASTResult(
54
+ file_path=file_path,
55
+ success=False,
56
+ error=f"文件不存在: {file_path}"
57
+ )
58
+
59
+ if path.suffix not in (".kt", ".kts"):
60
+ return KotlinASTResult(
61
+ file_path=file_path,
62
+ success=False,
63
+ error=f"不是 Kotlin 文件: {file_path}"
64
+ )
65
+
66
+ try:
67
+ content = path.read_text(encoding="utf-8")
68
+ return self.parse_code(content, file_path)
69
+ except Exception as e:
70
+ return KotlinASTResult(
71
+ file_path=file_path,
72
+ success=False,
73
+ error=str(e)
74
+ )
75
+
76
+ def parse_code(self, code: str, file_path: str = "<string>") -> KotlinASTResult:
77
+ """解析 Kotlin 代码字符串"""
78
+ result = KotlinASTResult(
79
+ file_path=file_path,
80
+ success=True,
81
+ parse_mode="fast",
82
+ total_lines=len(code.splitlines())
83
+ )
84
+
85
+ lines = code.split('\n')
86
+
87
+ # 基础解析
88
+ self._parse_package(code, result)
89
+ self._parse_imports(code, result, lines)
90
+
91
+ # Kotlin 特有特性解析
92
+ self._parse_type_aliases(code, result, lines)
93
+ self._parse_value_classes(code, result, lines)
94
+ self._parse_sealed_classes(code, result, lines)
95
+ self._parse_data_classes(code, result, lines)
96
+ self._parse_enum_classes(code, result, lines)
97
+ self._parse_objects(code, result, lines)
98
+ self._parse_delegated_properties(code, result, lines)
99
+ self._parse_coroutines(code, result, lines)
100
+ self._parse_when_expressions(code, result, lines)
101
+ self._parse_extension_functions(code, result, lines)
102
+ self._parse_extension_properties(code, result, lines)
103
+
104
+ # 顶层函数和属性
105
+ self._parse_top_level(code, result, lines)
106
+
107
+ # 普通类解析
108
+ self._parse_classes(code, result, lines)
109
+
110
+ return result
111
+
112
+ def _parse_package(self, code: str, result: KotlinASTResult):
113
+ """解析包声明"""
114
+ match = self._compiled.get('package')
115
+ if match:
116
+ m = match.search(code)
117
+ if m:
118
+ result.package = m.group(1)
119
+
120
+ def _parse_imports(self, code: str, result: KotlinASTResult, lines: list):
121
+ """解析导入语句"""
122
+ pattern = self._compiled.get('import')
123
+ if not pattern:
124
+ return
125
+
126
+ for i, line in enumerate(lines, 1):
127
+ m = pattern.match(line.strip())
128
+ if m:
129
+ result.imports.append(KotlinImportInfo(
130
+ path=m.group(1),
131
+ alias=m.group(2) if len(m.groups()) > 1 else None,
132
+ line=i
133
+ ))
134
+
135
+ # ==================== 类型系统解析 ====================
136
+
137
+ def _parse_type_aliases(self, code: str, result: KotlinASTResult, lines: list):
138
+ """解析类型别名"""
139
+ pattern = self._compiled.get('type_alias')
140
+ if not pattern:
141
+ return
142
+
143
+ for i, line in enumerate(lines, 1):
144
+ m = pattern.search(line.strip())
145
+ if m:
146
+ name = m.group(1)
147
+ type_params = m.group(2).split(',') if m.group(2) else []
148
+ underlying = m.group(3).strip() if m.group(3) else ""
149
+
150
+ result.type_aliases.append(KotlinTypeAlias(
151
+ name=name,
152
+ underlying_type=underlying,
153
+ type_params=type_params,
154
+ line=i
155
+ ))
156
+
157
+ def _parse_value_classes(self, code: str, result: KotlinASTResult, lines: list):
158
+ """解析值类(内联类)"""
159
+ pattern = self._compiled.get('value_class')
160
+ if not pattern:
161
+ return
162
+
163
+ for i, line in enumerate(lines, 1):
164
+ m = pattern.search(line.strip())
165
+ if m:
166
+ name = m.group(1)
167
+ wrapped = m.group(2).strip() if m.group(2) else ""
168
+
169
+ result.value_classes.append(KotlinValueClass(
170
+ name=name,
171
+ wrapped_type=wrapped,
172
+ line=i
173
+ ))
174
+
175
+ # ==================== Sealed 类解析 ====================
176
+
177
+ def _parse_sealed_classes(self, code: str, result: KotlinASTResult, lines: list):
178
+ """解析 Sealed 类"""
179
+ sealed_pattern = self._compiled.get('sealed_class')
180
+ sealed_interface_pattern = self._compiled.get('sealed_interface')
181
+
182
+ for i, line in enumerate(lines, 1):
183
+ stripped = line.strip()
184
+
185
+ # 跳过注释
186
+ if stripped.startswith('//') or stripped.startswith('/*'):
187
+ continue
188
+
189
+ # 检查 sealed class
190
+ m = None
191
+ class_type = "sealed class"
192
+
193
+ if sealed_pattern:
194
+ m = sealed_pattern.search(stripped)
195
+
196
+ if not m and sealed_interface_pattern:
197
+ m = sealed_interface_pattern.search(stripped)
198
+ class_type = "sealed interface"
199
+
200
+ if m:
201
+ name = m.group(1)
202
+ type_params = m.group(2).split(',') if m.group(2) else []
203
+
204
+ # 提取类体
205
+ class_body, end_line = self._extract_block(lines, i)
206
+
207
+ # 解析继承
208
+ extends, implements = self._parse_inheritance(stripped)
209
+
210
+ sealed_info = KotlinSealedClassInfo(
211
+ name=name,
212
+ line_start=i,
213
+ line_end=end_line,
214
+ class_type=class_type,
215
+ type_params=type_params,
216
+ primary_constructor_params=[],
217
+ extends=extends,
218
+ implements=implements,
219
+ modifiers=['sealed'],
220
+ annotations=[],
221
+ functions=[],
222
+ properties=[],
223
+ is_sealed=True,
224
+ permitted_subclasses=[]
225
+ )
226
+
227
+ # 解析类体中的成员
228
+ if class_body:
229
+ self._parse_class_members(class_body, sealed_info)
230
+
231
+ result.sealed_classes.append(sealed_info)
232
+
233
+ def _parse_inheritance(self, line: str) -> tuple[Optional[str], list[str]]:
234
+ """解析继承关系"""
235
+ extends = None
236
+ implements = []
237
+
238
+ # 检查 : 后面的内容
239
+ colon_match = re.search(r':\s*([^{]+?)(?:\s*\{|$)', line)
240
+ if colon_match:
241
+ inherit_str = colon_match.group(1).strip()
242
+ parts = inherit_str.split(',')
243
+
244
+ for part in parts:
245
+ part = part.strip()
246
+ if '(' in part:
247
+ # 有构造函数调用的是继承
248
+ extends = part.split('(')[0].strip()
249
+ elif part:
250
+ implements.append(part)
251
+
252
+ return extends, implements
253
+
254
+ # ==================== 数据类解析 ====================
255
+
256
+ def _parse_data_classes(self, code: str, result: KotlinASTResult, lines: list):
257
+ """解析数据类"""
258
+ pattern = self._compiled.get('data_class')
259
+ if not pattern:
260
+ return
261
+
262
+ for i, line in enumerate(lines, 1):
263
+ m = pattern.search(line.strip())
264
+ if m:
265
+ name = m.group(1)
266
+ type_params = m.group(2).split(',') if m.group(2) else []
267
+ params_str = m.group(3) if m.group(3) else ""
268
+
269
+ # 解析主构造函数参数
270
+ primary_params = self._parse_params(params_str)
271
+
272
+ # 提取类体
273
+ class_body, end_line = self._extract_block(lines, i)
274
+
275
+ extends, implements = self._parse_inheritance(line)
276
+
277
+ data_info = KotlinDataClassInfo(
278
+ name=name,
279
+ line_start=i,
280
+ line_end=end_line,
281
+ class_type="data class",
282
+ type_params=type_params,
283
+ primary_constructor_params=primary_params,
284
+ extends=extends,
285
+ implements=implements,
286
+ modifiers=['data'],
287
+ annotations=[],
288
+ functions=[],
289
+ properties=[],
290
+ component_functions=[f"component{n+1}" for n in range(len(primary_params))],
291
+ copy_function_params=primary_params.copy()
292
+ )
293
+
294
+ if class_body:
295
+ self._parse_class_members(class_body, data_info)
296
+
297
+ result.data_classes.append(data_info)
298
+
299
+ # ==================== 枚举类解析 ====================
300
+
301
+ def _parse_enum_classes(self, code: str, result: KotlinASTResult, lines: list):
302
+ """解析枚举类"""
303
+ pattern = self._compiled.get('enum_class')
304
+ if not pattern:
305
+ return
306
+
307
+ for i, line in enumerate(lines, 1):
308
+ m = pattern.search(line.strip())
309
+ if m:
310
+ name = m.group(1)
311
+ # 值类型(如果有)
312
+ value_type = m.group(2).strip() if m.group(2) else None
313
+
314
+ # 提取类体
315
+ class_body, end_line = self._extract_block(lines, i)
316
+
317
+ # 解析枚举条目
318
+ entries = []
319
+ if class_body:
320
+ entries = self._parse_enum_entries(class_body)
321
+
322
+ enum_info = KotlinEnumClassInfo(
323
+ name=name,
324
+ line_start=i,
325
+ line_end=end_line,
326
+ class_type="enum class",
327
+ type_params=[],
328
+ primary_constructor_params=[],
329
+ extends=None,
330
+ implements=[],
331
+ modifiers=['enum'],
332
+ annotations=[],
333
+ functions=[],
334
+ properties=[],
335
+ entries=entries
336
+ )
337
+
338
+ if class_body:
339
+ self._parse_class_members(class_body, enum_info)
340
+
341
+ result.enum_classes.append(enum_info)
342
+
343
+ def _parse_enum_entries(self, class_body: str) -> list[dict]:
344
+ """解析枚举条目"""
345
+ entries = []
346
+ # 查找枚举条目区域(在 ; 之前或 class body 中)
347
+ entry_pattern = re.compile(r'^\s*(\w+)\s*(?:\(([^)]*)\))?\s*(?:,|(?=\n))', re.MULTILINE)
348
+
349
+ for m in entry_pattern.finditer(class_body):
350
+ name = m.group(1)
351
+ # 跳过关键字
352
+ if name in ('class', 'interface', 'object', 'fun', 'val', 'var'):
353
+ continue
354
+
355
+ params = m.group(2) if m.group(2) else None
356
+ entries.append({
357
+ 'name': name,
358
+ 'params': params,
359
+ 'line': 0 # 简化,不提供精确行号
360
+ })
361
+
362
+ return entries
363
+
364
+ # ==================== Object 解析 ====================
365
+
366
+ def _parse_objects(self, code: str, result: KotlinASTResult, lines: list):
367
+ """解析 Object 声明"""
368
+ pattern = self._compiled.get('object_declaration')
369
+ companion_pattern = self._compiled.get('companion_object')
370
+
371
+ if not pattern:
372
+ return
373
+
374
+ for i, line in enumerate(lines, 1):
375
+ stripped = line.strip()
376
+
377
+ # 跳过 companion object(在类解析中处理)
378
+ if companion_pattern and companion_pattern.search(stripped):
379
+ continue
380
+
381
+ m = pattern.search(stripped)
382
+ if m:
383
+ name = m.group(1)
384
+ extends_str = m.group(2) if m.group(2) else None
385
+
386
+ extends, implements = self._parse_inheritance(stripped)
387
+
388
+ _, end_line = self._extract_block(lines, i)
389
+
390
+ obj_decl = KotlinObjectDeclaration(
391
+ name=name,
392
+ extends=extends or extends_str,
393
+ implements=implements,
394
+ is_companion=False,
395
+ line_start=i,
396
+ line_end=end_line
397
+ )
398
+
399
+ result.object_declarations.append(obj_decl)
400
+
401
+ # ==================== 委托属性解析 ====================
402
+
403
+ def _parse_delegated_properties(self, code: str, result: KotlinASTResult, lines: list):
404
+ """解析委托属性"""
405
+ pattern = self._compiled.get('delegated_property')
406
+ if not pattern:
407
+ return
408
+
409
+ for i, line in enumerate(lines, 1):
410
+ m = pattern.search(line.strip())
411
+ if m:
412
+ is_val = m.group(1) == 'val'
413
+ name = m.group(2)
414
+ prop_type = m.group(3) if m.group(3) else "Unknown"
415
+ delegate_expr = m.group(4).strip() if m.group(4) else ""
416
+
417
+ # 判断委托类型
418
+ delegate_type = "custom"
419
+ for std_name in STANDARD_DELEGATES:
420
+ if delegate_expr.startswith(std_name):
421
+ delegate_type = std_name
422
+ break
423
+
424
+ result.delegated_properties.append(KotlinDelegatedProperty(
425
+ name=name,
426
+ delegate_type=delegate_type,
427
+ delegate_expression=delegate_expr,
428
+ is_val=is_val,
429
+ line=i
430
+ ))
431
+
432
+ # ==================== 协程解析 ====================
433
+
434
+ def _parse_coroutines(self, code: str, result: KotlinASTResult, lines: list):
435
+ """解析协程和 Flow"""
436
+ suspend_pattern = self._compiled.get('suspend_function')
437
+ flow_pattern = self._compiled.get('flow_type')
438
+ builder_pattern = self._compiled.get('coroutine_builder')
439
+ operator_pattern = self._compiled.get('flow_operator')
440
+ dispatcher_pattern = self._compiled.get('dispatcher')
441
+ scope_pattern = self._compiled.get('coroutine_scope')
442
+
443
+ # 解析 suspend 函数
444
+ if suspend_pattern:
445
+ for i, line in enumerate(lines, 1):
446
+ m = suspend_pattern.search(line.strip())
447
+ if m:
448
+ name = m.group(1)
449
+ params = m.group(2) if m.group(2) else ""
450
+ return_type = m.group(3).strip() if m.group(3) else None
451
+
452
+ # 检查 Flow 类型
453
+ flow_type = None
454
+ if return_type and flow_pattern:
455
+ flow_m = flow_pattern.search(return_type)
456
+ if flow_m:
457
+ flow_type = f"Flow<{flow_m.group(1)}>"
458
+
459
+ result.coroutines.append(KotlinCoroutineInfo(
460
+ function_name=name,
461
+ is_suspend=True,
462
+ flow_type=flow_type,
463
+ line=i
464
+ ))
465
+
466
+ # 解析协程构建器
467
+ if builder_pattern:
468
+ for i, line in enumerate(lines, 1):
469
+ for m in builder_pattern.finditer(line):
470
+ builder_type = m.group(1)
471
+
472
+ # 查找 dispatcher
473
+ dispatcher = None
474
+ if dispatcher_pattern:
475
+ disp_m = dispatcher_pattern.search(line)
476
+ if disp_m:
477
+ dispatcher = disp_m.group(1)
478
+
479
+ result.coroutines.append(KotlinCoroutineInfo(
480
+ function_name="<anonymous>",
481
+ is_suspend=False,
482
+ builder_type=builder_type,
483
+ dispatcher=dispatcher,
484
+ line=i
485
+ ))
486
+
487
+ # 解析 Flow 操作符
488
+ if operator_pattern:
489
+ for i, line in enumerate(lines, 1):
490
+ for m in operator_pattern.finditer(line):
491
+ op_name = m.group(1)
492
+ is_terminal = op_name in TERMINAL_FLOW_OPERATORS
493
+
494
+ result.flow_operators.append(KotlinFlowOperator(
495
+ name=op_name,
496
+ is_terminal=is_terminal,
497
+ line=i
498
+ ))
499
+
500
+ # ==================== When 表达式解析 ====================
501
+
502
+ def _parse_when_expressions(self, code: str, result: KotlinASTResult, lines: list):
503
+ """解析 when 表达式"""
504
+ pattern = self._compiled.get('when_expression')
505
+ if not pattern:
506
+ return
507
+
508
+ for i, line in enumerate(lines, 1):
509
+ m = pattern.search(line.strip())
510
+ if m:
511
+ subject_var = m.group(1).strip() if m.group(1) else None
512
+ subject_type = None
513
+
514
+ # 提取 when 体
515
+ when_body, end_line = self._extract_block(lines, i)
516
+
517
+ # 解析分支
518
+ branches = []
519
+ if when_body:
520
+ branches = self._parse_when_branches(when_body)
521
+
522
+ result.when_expressions.append(KotlinWhenExpression(
523
+ subject_type=subject_type,
524
+ subject_variable=subject_var,
525
+ branches=branches,
526
+ is_exhaustive=None, # 需要类型推断
527
+ line_start=i,
528
+ line_end=end_line
529
+ ))
530
+
531
+ def _parse_when_branches(self, when_body: str) -> list[dict]:
532
+ """解析 when 分支"""
533
+ branches = []
534
+ lines = when_body.split('\n')
535
+
536
+ branch_pattern = re.compile(r'^\s*(.+?)\s*->')
537
+
538
+ for line in lines:
539
+ m = branch_pattern.match(line)
540
+ if m:
541
+ pattern_str = m.group(1).strip()
542
+ is_else = pattern_str == 'else'
543
+
544
+ branches.append({
545
+ 'pattern': pattern_str,
546
+ 'is_else': is_else,
547
+ 'line': 0
548
+ })
549
+
550
+ return branches
551
+
552
+ # ==================== 扩展函数/属性解析 ====================
553
+
554
+ def _parse_extension_functions(self, code: str, result: KotlinASTResult, lines: list):
555
+ """解析扩展函数"""
556
+ pattern = self._compiled.get('extension_function')
557
+ if not pattern:
558
+ return
559
+
560
+ for i, line in enumerate(lines, 1):
561
+ m = pattern.search(line.strip())
562
+ if m:
563
+ receiver = m.group(1)
564
+ name = m.group(2)
565
+ params = m.group(3) if m.group(3) else ""
566
+ return_type = m.group(4).strip() if m.group(4) else None
567
+
568
+ # 检查是否在类内(分发接收者)
569
+ in_class = self._is_inside_class(code, i)
570
+
571
+ result.extension_functions.append(KotlinExtensionFunction(
572
+ name=name,
573
+ line_start=i,
574
+ line_end=i,
575
+ return_type=return_type,
576
+ parameters=self._parse_params(params),
577
+ modifiers=[],
578
+ type_params=[],
579
+ receiver_type=receiver,
580
+ dispatch_receiver=in_class
581
+ ))
582
+
583
+ def _parse_extension_properties(self, code: str, result: KotlinASTResult, lines: list):
584
+ """解析扩展属性"""
585
+ pattern = self._compiled.get('extension_property')
586
+ if not pattern:
587
+ return
588
+
589
+ for i, line in enumerate(lines, 1):
590
+ m = pattern.search(line.strip())
591
+ if m:
592
+ is_val = m.group(1) == 'val'
593
+ receiver = m.group(2)
594
+ name = m.group(3)
595
+
596
+ result.extension_properties.append(KotlinExtensionProperty(
597
+ name=name,
598
+ receiver_type=receiver,
599
+ property_type="Unknown",
600
+ is_val=is_val,
601
+ line=i
602
+ ))
603
+
604
+ def _is_inside_class(self, code: str, line_num: int) -> bool:
605
+ """检查某行是否在类内部"""
606
+ lines = code.split('\n')
607
+ depth = 0
608
+
609
+ for i, line in enumerate(lines, 1):
610
+ if i >= line_num:
611
+ return depth > 0
612
+
613
+ depth += line.count('{') - line.count('}')
614
+
615
+ return False
616
+
617
+ # ==================== 顶层结构解析 ====================
618
+
619
+ def _parse_top_level(self, code: str, result: KotlinASTResult, lines: list):
620
+ """解析顶层函数和属性"""
621
+ brace_depth = 0
622
+ in_block_comment = False
623
+
624
+ for i, line in enumerate(lines, 1):
625
+ stripped = line.strip()
626
+
627
+ # 处理块注释
628
+ if '/*' in stripped:
629
+ in_block_comment = True
630
+ if '*/' in stripped:
631
+ in_block_comment = False
632
+ continue
633
+ if in_block_comment:
634
+ continue
635
+
636
+ # 跳过行注释
637
+ if stripped.startswith('//'):
638
+ brace_depth += line.count('{') - line.count('}')
639
+ continue
640
+
641
+ # 只处理顶层
642
+ if brace_depth == 0:
643
+ # 解析顶层函数
644
+ if 'fun ' in stripped and 'class ' not in stripped and 'sealed' not in stripped:
645
+ func = self._parse_function_line(stripped, i)
646
+ if func:
647
+ result.functions.append(func)
648
+
649
+ # 解析顶层属性
650
+ elif stripped.startswith('val ') or stripped.startswith('var '):
651
+ prop = self._parse_property_line(stripped, i)
652
+ if prop:
653
+ result.properties.append(prop)
654
+
655
+ # 更新大括号深度
656
+ brace_depth += line.count('{') - line.count('}')
657
+
658
+ def _parse_function_line(self, line: str, line_num: int) -> Optional[KotlinFunctionInfo]:
659
+ """解析函数行"""
660
+ # 简单提取函数名
661
+ name_match = re.search(r'fun\s+(?:<[^>]+>\s+)?(\w+)\s*\(', line)
662
+ if not name_match:
663
+ return None
664
+
665
+ name = name_match.group(1)
666
+
667
+ # 提取参数
668
+ params_match = re.search(r'fun\s+\w+\s*\(([^)]*)\)', line)
669
+ params = self._parse_params(params_match.group(1)) if params_match else []
670
+
671
+ # 提取返回类型
672
+ return_type = None
673
+ ret_match = re.search(r'\)\s*:\s*([^{=\n]+)', line)
674
+ if ret_match:
675
+ return_type = ret_match.group(1).strip()
676
+
677
+ # 提取修饰符
678
+ modifiers = []
679
+ for mod in ['suspend', 'inline', 'tailrec', 'operator', 'infix', 'public', 'private', 'protected', 'internal', 'open', 'override']:
680
+ if re.search(rf'\b{mod}\b', line.split('fun')[0]):
681
+ modifiers.append(mod)
682
+
683
+ return KotlinFunctionInfo(
684
+ name=name,
685
+ line_start=line_num,
686
+ line_end=line_num,
687
+ return_type=return_type,
688
+ parameters=params,
689
+ modifiers=modifiers,
690
+ type_params=[]
691
+ )
692
+
693
+ def _parse_property_line(self, line: str, line_num: int) -> Optional[KotlinPropertyInfo]:
694
+ """解析属性行"""
695
+ is_val = line.strip().startswith('val')
696
+
697
+ # 提取属性名
698
+ name_match = re.search(r'(val|var)\s+(\w+)', line)
699
+ if not name_match:
700
+ return None
701
+
702
+ name = name_match.group(2)
703
+
704
+ # 提取类型
705
+ prop_type = "Unknown"
706
+ type_match = re.search(r':\s*([^\s=]+)', line)
707
+ if type_match:
708
+ prop_type = type_match.group(1).strip()
709
+
710
+ # 提取修饰符
711
+ modifiers = []
712
+ for mod in ['public', 'private', 'protected', 'internal', 'lateinit', 'const', 'override']:
713
+ prefix = line.split('val')[0] if 'val' in line else line.split('var')[0]
714
+ if mod in prefix:
715
+ modifiers.append(mod)
716
+
717
+ # 检查是否为委托属性
718
+ is_delegate = ' by ' in line
719
+
720
+ return KotlinPropertyInfo(
721
+ name=name,
722
+ type=prop_type,
723
+ line=line_num,
724
+ is_val=is_val,
725
+ modifiers=modifiers,
726
+ is_delegate=is_delegate
727
+ )
728
+
729
+ # ==================== 类解析 ====================
730
+
731
+ def _parse_classes(self, code: str, result: KotlinASTResult, lines: list):
732
+ """解析普通类声明"""
733
+ for i, line in enumerate(lines, 1):
734
+ stripped = line.strip()
735
+
736
+ # 跳过已解析的特殊类型
737
+ if any(kw in stripped for kw in ['sealed class', 'sealed interface', 'data class', 'enum class', 'value class']):
738
+ continue
739
+
740
+ # 检查普通类声明
741
+ class_match = self._match_class_declaration(stripped)
742
+ if class_match:
743
+ class_info = self._parse_class_declaration(code, lines, i, class_match)
744
+ if class_info:
745
+ result.classes.append(class_info)
746
+
747
+ def _match_class_declaration(self, line: str) -> Optional[re.Match]:
748
+ """匹配类声明"""
749
+ patterns = [
750
+ # interface
751
+ r'(?:(public|private|protected|internal)\s+)*'
752
+ r'(interface)\s+(\w+)(?:<([^>]+)>)?',
753
+ # 普通类
754
+ r'(?:(public|private|protected|internal|open|abstract|final|inner)\s+)*'
755
+ r'(class)\s+(\w+)(?:<([^>]+)>)?',
756
+ ]
757
+
758
+ for pattern in patterns:
759
+ match = re.match(pattern, line)
760
+ if match:
761
+ return match
762
+ return None
763
+
764
+ def _parse_class_declaration(self, code: str, lines: list, line_num: int, match: re.Match) -> Optional[KotlinClassInfo]:
765
+ """解析类声明"""
766
+ groups = match.groups()
767
+
768
+ # 提取类类型和名称
769
+ class_type = "class"
770
+ name = "Unknown"
771
+ type_params_str = None
772
+ modifiers = []
773
+
774
+ idx = 0
775
+ # 提取修饰符
776
+ while idx < len(groups) and groups[idx] and groups[idx] in ('public', 'private', 'protected', 'internal', 'open', 'abstract', 'final', 'inner'):
777
+ modifiers.append(groups[idx])
778
+ idx += 1
779
+
780
+ # 类类型
781
+ if idx < len(groups) and groups[idx]:
782
+ class_type = groups[idx]
783
+ idx += 1
784
+
785
+ # 类名
786
+ if idx < len(groups) and groups[idx]:
787
+ name = groups[idx]
788
+ idx += 1
789
+
790
+ # 泛型参数
791
+ if idx < len(groups) and groups[idx]:
792
+ type_params_str = groups[idx]
793
+
794
+ type_params = [p.strip() for p in type_params_str.split(',')] if type_params_str else []
795
+
796
+ # 解析主构造函数参数
797
+ primary_params = []
798
+ constructor_match = re.search(r'\(([^)]*)\)', lines[line_num - 1])
799
+ if constructor_match:
800
+ primary_params = self._parse_params(constructor_match.group(1))
801
+
802
+ # 解析继承
803
+ extends, implements = self._parse_inheritance(lines[line_num - 1])
804
+
805
+ # 提取类体
806
+ class_body, end_line = self._extract_block(lines, line_num)
807
+
808
+ # 创建类信息
809
+ class_info = KotlinClassInfo(
810
+ name=name,
811
+ line_start=line_num,
812
+ line_end=end_line,
813
+ class_type=class_type,
814
+ type_params=type_params,
815
+ primary_constructor_params=primary_params,
816
+ extends=extends,
817
+ implements=implements,
818
+ modifiers=modifiers,
819
+ annotations=[],
820
+ functions=[],
821
+ properties=[]
822
+ )
823
+
824
+ # 解析类体中的成员
825
+ if class_body:
826
+ self._parse_class_members(class_body, class_info)
827
+
828
+ return class_info
829
+
830
+ def _parse_class_members(self, class_body: str, class_info):
831
+ """解析类成员"""
832
+ for line in class_body.split('\n'):
833
+ stripped = line.strip()
834
+
835
+ # 跳过空行和注释
836
+ if not stripped or stripped.startswith('//'):
837
+ continue
838
+
839
+ # 解析函数
840
+ if 'fun ' in stripped:
841
+ func = self._parse_function_line(stripped, 0)
842
+ if func:
843
+ class_info.functions.append(func)
844
+
845
+ # 解析属性
846
+ elif stripped.startswith('val ') or stripped.startswith('var '):
847
+ prop = self._parse_property_line(stripped, 0)
848
+ if prop:
849
+ class_info.properties.append(prop)
850
+
851
+ # ==================== 辅助方法 ====================
852
+
853
+ def _extract_block(self, lines: list, start_line: int) -> tuple[str, int]:
854
+ """提取代码块(大括号包围)"""
855
+ brace_depth = 0
856
+ body_lines = []
857
+ started = False
858
+
859
+ for i in range(start_line - 1, len(lines)):
860
+ line = lines[i]
861
+
862
+ if '{' in line:
863
+ started = True
864
+
865
+ if started:
866
+ body_lines.append(line)
867
+ brace_depth += line.count('{') - line.count('}')
868
+
869
+ if brace_depth == 0:
870
+ return '\n'.join(body_lines), i + 1
871
+
872
+ return '\n'.join(body_lines), len(lines)
873
+
874
+ def _parse_params(self, params_str: str) -> list[dict]:
875
+ """解析参数列表"""
876
+ if not params_str.strip():
877
+ return []
878
+
879
+ params = []
880
+ # 简单分割(不考虑嵌套的括号)
881
+ for param in params_str.split(','):
882
+ param = param.strip()
883
+ if not param:
884
+ continue
885
+
886
+ # 参数格式: name: Type = default
887
+ parts = param.split('=')
888
+ name_type = parts[0].strip()
889
+ default_value = parts[1].strip() if len(parts) > 1 else None
890
+
891
+ # 分离名称和类型
892
+ if ':' in name_type:
893
+ name_part, type_part = name_type.split(':', 1)
894
+ params.append({
895
+ 'name': name_part.strip(),
896
+ 'type': type_part.strip(),
897
+ 'default_value': default_value
898
+ })
899
+ else:
900
+ params.append({
901
+ 'name': name_type,
902
+ 'type': 'Any',
903
+ 'default_value': default_value
904
+ })
905
+
906
+ return params