code-explore-by-sql 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.
- code_explore_by_sql-0.1.0.dist-info/METADATA +205 -0
- code_explore_by_sql-0.1.0.dist-info/RECORD +29 -0
- code_explore_by_sql-0.1.0.dist-info/WHEEL +4 -0
- code_explore_by_sql-0.1.0.dist-info/entry_points.txt +3 -0
- code_explore_by_sql-0.1.0.dist-info/licenses/LICENSE +21 -0
- code_source_sql/__init__.py +9 -0
- code_source_sql/__main__.py +5 -0
- code_source_sql/bracket_scanner.py +385 -0
- code_source_sql/build_db.py +284 -0
- code_source_sql/code_block_summary.py +522 -0
- code_source_sql/configs.py +402 -0
- code_source_sql/db.py +625 -0
- code_source_sql/edge_extractor.py +183 -0
- code_source_sql/languages/__init__.py +31 -0
- code_source_sql/languages/c.py +118 -0
- code_source_sql/languages/cpp.py +106 -0
- code_source_sql/languages/csharp.py +103 -0
- code_source_sql/languages/glsl.py +162 -0
- code_source_sql/languages/go.py +91 -0
- code_source_sql/languages/hlsl.py +155 -0
- code_source_sql/languages/java.py +98 -0
- code_source_sql/languages/javascript.py +215 -0
- code_source_sql/languages/kotlin.py +108 -0
- code_source_sql/languages/python.py +105 -0
- code_source_sql/languages/rust.py +91 -0
- code_source_sql/languages/swift.py +116 -0
- code_source_sql/server.py +264 -0
- code_source_sql/symbol_analyzer.py +487 -0
- code_source_sql/unreal_rules.py +163 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Strict edge extractor — only deterministic, unambiguous relationships.
|
|
2
|
+
|
|
3
|
+
Extracts exactly 4 edge types per plan.md:
|
|
4
|
+
- inheritance: class A : public B
|
|
5
|
+
- type_dependency: function signature types (excluding basic types)
|
|
6
|
+
- static_call: explicit scope calls (Super::BeginPlay, UGameplayStatics::...)
|
|
7
|
+
- rpc_routing: framework-determined implicit routing (Server -> _Implementation)
|
|
8
|
+
|
|
9
|
+
Anti-Cartesian-Product rules:
|
|
10
|
+
- NEVER extract generalized pointer calls (Comp->Init())
|
|
11
|
+
- Basic types (TArray, FString, int, FName) generate NO edges
|
|
12
|
+
|
|
13
|
+
Refactored to accept LanguageConfig + FrameworkConfig instead of hardcoded constants.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
|
|
20
|
+
from .configs import FrameworkConfig, LanguageConfig
|
|
21
|
+
from .symbol_analyzer import ExtraSymbol, SymbolDef
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class StrictEdge:
|
|
26
|
+
source_qn: str
|
|
27
|
+
target_qn: str
|
|
28
|
+
edge_type: str # inheritance, type_dependency, static_call, rpc_routing
|
|
29
|
+
language: str = ""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def extract_edges(
|
|
33
|
+
symbols: list[SymbolDef],
|
|
34
|
+
extra_symbols: list[ExtraSymbol],
|
|
35
|
+
lines: list[str],
|
|
36
|
+
fw: FrameworkConfig,
|
|
37
|
+
lang: LanguageConfig,
|
|
38
|
+
) -> list[StrictEdge]:
|
|
39
|
+
"""Extract all deterministic edges for a file.
|
|
40
|
+
|
|
41
|
+
Uses both symbol metadata and source text to find strict edges.
|
|
42
|
+
All regex patterns come from LanguageConfig and FrameworkConfig.
|
|
43
|
+
"""
|
|
44
|
+
language = lang.name
|
|
45
|
+
base_kw = lang.base_keyword
|
|
46
|
+
type_re = lang.type_re
|
|
47
|
+
static_call_re = lang.static_call_re
|
|
48
|
+
super_call_re = lang.super_call_re
|
|
49
|
+
param_type_re = lang.param_type_re
|
|
50
|
+
control_flow_names = lang.control_flow_names
|
|
51
|
+
access_spec_names = lang.access_spec_names
|
|
52
|
+
|
|
53
|
+
edges: list[StrictEdge] = []
|
|
54
|
+
seen: set[tuple[str, str, str]] = set()
|
|
55
|
+
|
|
56
|
+
all_skip = lang.basic_skip_types | fw.skip_types | fw.noise_type_names
|
|
57
|
+
|
|
58
|
+
def _add(src: str, tgt: str, etype: str) -> None:
|
|
59
|
+
if src == tgt:
|
|
60
|
+
return
|
|
61
|
+
key = (src, tgt, etype)
|
|
62
|
+
if key not in seen:
|
|
63
|
+
seen.add(key)
|
|
64
|
+
edges.append(StrictEdge(source_qn=src, target_qn=tgt, edge_type=etype, language=language))
|
|
65
|
+
|
|
66
|
+
# Build a lookup of QN -> SymbolDef for resolving static calls
|
|
67
|
+
qn_set: set[str] = set()
|
|
68
|
+
for s in symbols:
|
|
69
|
+
qn_set.add(s.qualified_name)
|
|
70
|
+
|
|
71
|
+
# --- Pass 1: Symbol metadata edges ---
|
|
72
|
+
|
|
73
|
+
for sym in symbols:
|
|
74
|
+
qn = sym.qualified_name
|
|
75
|
+
|
|
76
|
+
# 1. Inheritance
|
|
77
|
+
if sym.block_type == "class" and sym.inheritance_base:
|
|
78
|
+
base = sym.inheritance_base
|
|
79
|
+
if base not in all_skip and len(base) >= 3:
|
|
80
|
+
_add(qn, base, "inheritance")
|
|
81
|
+
|
|
82
|
+
# 2. Framework-specific edges from decoration metadata
|
|
83
|
+
if sym.decoration_meta and fw.extract_framework_edges:
|
|
84
|
+
for target_qn, edge_type in fw.extract_framework_edges(qn, sym.decoration_meta):
|
|
85
|
+
_add(qn, target_qn, edge_type)
|
|
86
|
+
|
|
87
|
+
# --- Pass 2: Source text scanning for static_call and type_dependency ---
|
|
88
|
+
|
|
89
|
+
# QN internal convention uses "::" as separator regardless of language.
|
|
90
|
+
# scope_operator is only used for source text regex matching above.
|
|
91
|
+
_QN_SEP = "::"
|
|
92
|
+
|
|
93
|
+
method_symbols = [
|
|
94
|
+
s for s in symbols
|
|
95
|
+
if s.block_type in ("method", "function")
|
|
96
|
+
and s.qualified_name.split(_QN_SEP)[-1].lower() not in control_flow_names
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
for sym in method_symbols:
|
|
100
|
+
qn = sym.qualified_name
|
|
101
|
+
start = sym.start_line - 1
|
|
102
|
+
end = sym.end_line
|
|
103
|
+
|
|
104
|
+
for line_idx in range(start, min(end, len(lines))):
|
|
105
|
+
line = lines[line_idx].strip()
|
|
106
|
+
|
|
107
|
+
# Skip comments and preprocessor
|
|
108
|
+
if ((lang.line_comment and line.startswith(lang.line_comment)) or
|
|
109
|
+
(lang.block_comment_pair and line.startswith(lang.block_comment_pair[0])) or
|
|
110
|
+
(lang.preprocessor_prefix and line.startswith(lang.preprocessor_prefix))):
|
|
111
|
+
continue
|
|
112
|
+
# Skip framework decoration macro lines
|
|
113
|
+
if fw.decoration_macro_names and any(
|
|
114
|
+
line.startswith(m) for m in fw.decoration_macro_names
|
|
115
|
+
):
|
|
116
|
+
continue
|
|
117
|
+
# Skip string literals (rough check)
|
|
118
|
+
if line.startswith('"') or (lang.raw_string_char and line.startswith(lang.raw_string_char + '"')):
|
|
119
|
+
continue
|
|
120
|
+
|
|
121
|
+
# 3. Static calls: ClassName.Method( or ClassName::Method(
|
|
122
|
+
if static_call_re:
|
|
123
|
+
for m in static_call_re.finditer(line):
|
|
124
|
+
cls_name = m.group(1)
|
|
125
|
+
method_name = m.group(2)
|
|
126
|
+
if cls_name == base_kw and sym.parent_class:
|
|
127
|
+
target = f"{sym.parent_class}::{method_name}"
|
|
128
|
+
_add(qn, target, "static_call")
|
|
129
|
+
elif cls_name not in all_skip and cls_name not in control_flow_names:
|
|
130
|
+
target = f"{cls_name}::{method_name}"
|
|
131
|
+
_add(qn, target, "static_call")
|
|
132
|
+
|
|
133
|
+
# Super/base calls
|
|
134
|
+
if super_call_re:
|
|
135
|
+
for m in super_call_re.finditer(line):
|
|
136
|
+
method_name = m.group(1)
|
|
137
|
+
if sym.parent_class:
|
|
138
|
+
target = f"{sym.parent_class}::{method_name}"
|
|
139
|
+
_add(qn, target, "static_call")
|
|
140
|
+
|
|
141
|
+
# 4. Type dependencies from function signature (only on declaration lines)
|
|
142
|
+
if line_idx == start and param_type_re:
|
|
143
|
+
for m in param_type_re.finditer(line):
|
|
144
|
+
tname = m.group(1)
|
|
145
|
+
if tname and tname not in all_skip and len(tname) >= 3:
|
|
146
|
+
_add(qn, tname, "type_dependency")
|
|
147
|
+
|
|
148
|
+
# --- Pass 3: Type dependencies from class member variables ---
|
|
149
|
+
class_symbols = [s for s in symbols if s.block_type == "class"]
|
|
150
|
+
for sym in class_symbols:
|
|
151
|
+
qn = sym.qualified_name
|
|
152
|
+
start = sym.start_line - 1
|
|
153
|
+
end = sym.end_line
|
|
154
|
+
|
|
155
|
+
for line_idx in range(start, min(end, len(lines))):
|
|
156
|
+
line = lines[line_idx].strip()
|
|
157
|
+
if not line:
|
|
158
|
+
continue
|
|
159
|
+
if ((lang.line_comment and line.startswith(lang.line_comment)) or
|
|
160
|
+
(lang.block_comment_pair and line.startswith(lang.block_comment_pair[0])) or
|
|
161
|
+
(lang.preprocessor_prefix and line.startswith(lang.preprocessor_prefix))):
|
|
162
|
+
continue
|
|
163
|
+
if line in access_spec_names:
|
|
164
|
+
continue
|
|
165
|
+
if fw.decoration_macro_names and any(
|
|
166
|
+
line.startswith(m) for m in fw.decoration_macro_names
|
|
167
|
+
):
|
|
168
|
+
continue
|
|
169
|
+
|
|
170
|
+
# Member variable: Type* Name; or Type& Name; or Type Name;
|
|
171
|
+
if type_re:
|
|
172
|
+
for m in type_re.finditer(line):
|
|
173
|
+
tname = m.group(1)
|
|
174
|
+
if not tname or tname in all_skip:
|
|
175
|
+
continue
|
|
176
|
+
if len(tname) < 3:
|
|
177
|
+
continue
|
|
178
|
+
pos = m.end()
|
|
179
|
+
rest = line[pos:].lstrip() if pos < len(line) else ""
|
|
180
|
+
if rest and (rest[0] in lang.type_indicator_chars or (rest[0].isalpha() or rest[0] == "_")):
|
|
181
|
+
_add(qn, tname, "type_dependency")
|
|
182
|
+
|
|
183
|
+
return edges
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Language factory registry — imports all language factories and registers them."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ..configs import register_language
|
|
6
|
+
from .c import make_c_language
|
|
7
|
+
from .cpp import make_cpp_language
|
|
8
|
+
from .csharp import make_csharp_language
|
|
9
|
+
from .glsl import make_glsl_language
|
|
10
|
+
from .go import make_go_language
|
|
11
|
+
from .hlsl import make_hlsl_language
|
|
12
|
+
from .java import make_java_language
|
|
13
|
+
from .javascript import make_javascript_language, make_typescript_language
|
|
14
|
+
from .kotlin import make_kotlin_language
|
|
15
|
+
from .python import make_python_language
|
|
16
|
+
from .rust import make_rust_language
|
|
17
|
+
from .swift import make_swift_language
|
|
18
|
+
|
|
19
|
+
register_language("cpp", make_cpp_language)
|
|
20
|
+
register_language("csharp", make_csharp_language)
|
|
21
|
+
register_language("c", make_c_language)
|
|
22
|
+
register_language("java", make_java_language)
|
|
23
|
+
register_language("glsl", make_glsl_language)
|
|
24
|
+
register_language("go", make_go_language)
|
|
25
|
+
register_language("hlsl", make_hlsl_language)
|
|
26
|
+
register_language("rust", make_rust_language)
|
|
27
|
+
register_language("javascript", make_javascript_language)
|
|
28
|
+
register_language("typescript", make_typescript_language)
|
|
29
|
+
register_language("kotlin", make_kotlin_language)
|
|
30
|
+
register_language("swift", make_swift_language)
|
|
31
|
+
register_language("python", make_python_language)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""C language configuration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from ..configs import LanguageConfig
|
|
8
|
+
|
|
9
|
+
_NEVER_MATCH = re.compile(r"(?!x)x")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def make_c_language() -> LanguageConfig:
|
|
13
|
+
"""C language configuration — similar to C++ but no templates, namespaces,
|
|
14
|
+
classes, lambdas, or export macros."""
|
|
15
|
+
return LanguageConfig(
|
|
16
|
+
name="c",
|
|
17
|
+
# C has struct/union (no class); enum same as C++
|
|
18
|
+
class_re=re.compile(
|
|
19
|
+
r"(?:^|\s)(struct|union)\s+"
|
|
20
|
+
r"(?:(?:[A-Z][A-Z0-9_]*_API|[A-Z][A-Z0-9_]*(?:\s*\([^)]*\))?)\s+)*"
|
|
21
|
+
r"(\w+)"
|
|
22
|
+
r"\s*",
|
|
23
|
+
),
|
|
24
|
+
enum_re=re.compile(r"\benum\s+(\w+)"),
|
|
25
|
+
# No namespaces in C
|
|
26
|
+
namespace_re=_NEVER_MATCH,
|
|
27
|
+
func_name_re=re.compile(r"(\w+)\s*\([^)]*\)\s*$"),
|
|
28
|
+
# No export macros in plain C
|
|
29
|
+
export_macro_re=_NEVER_MATCH,
|
|
30
|
+
calling_conv_re=re.compile(
|
|
31
|
+
r"\b(?:__cdecl|__stdcall|__fastcall|__thiscall|__vectorcall|WINAPI|CALLBACK|"
|
|
32
|
+
r"STDMETHODCALLTYPE|FORCEINLINE|FORCENOINLINE|FORCEINLINE_DEBUGGABLE|inline)\b"
|
|
33
|
+
),
|
|
34
|
+
attribute_re=re.compile(
|
|
35
|
+
r"\b(?:__declspec|__attribute__|alignas)\s*\([^)]*(?:\)[^)]*)?\)|\[\[[^\]]*\]\]"
|
|
36
|
+
),
|
|
37
|
+
# No templates in C
|
|
38
|
+
template_re=_NEVER_MATCH,
|
|
39
|
+
# No destructors in C
|
|
40
|
+
dtor_re=_NEVER_MATCH,
|
|
41
|
+
control_flow_re=re.compile(r"\b(if|else\s+if|else|while|for|do|switch|catch|try)\b"),
|
|
42
|
+
control_flow_names=frozenset({
|
|
43
|
+
"if", "else", "while", "for", "do", "switch", "catch", "try",
|
|
44
|
+
"return", "delete", "goto", "break", "continue", "throw",
|
|
45
|
+
}),
|
|
46
|
+
trailing_mods_re=re.compile(
|
|
47
|
+
r"\s*(?:const|constexpr|inline|static)\s*[;{]*\s*$"
|
|
48
|
+
),
|
|
49
|
+
access_spec_re=re.compile(r"^(?!x)x"), # C has no access specifiers
|
|
50
|
+
macro_like_re=re.compile(r"^[A-Z][A-Z0-9_]*\s*(?:\([^{};]*\))?\s*$"),
|
|
51
|
+
define_re=re.compile(r"#\s*define\s+"),
|
|
52
|
+
extern_c_re=re.compile(r'\bextern\s+"C"'),
|
|
53
|
+
operator_re=None,
|
|
54
|
+
uses_braces=True,
|
|
55
|
+
uses_namespaces=False,
|
|
56
|
+
uses_colon_inheritance=False,
|
|
57
|
+
# Edge extraction
|
|
58
|
+
scope_operator="::",
|
|
59
|
+
base_keyword="Super",
|
|
60
|
+
static_call_re=re.compile(r"\b([A-Z][A-Za-z0-9_]+)::([A-Za-z_][A-Za-z0-9_]*)\s*\("),
|
|
61
|
+
super_call_re=None,
|
|
62
|
+
type_re=re.compile(r"\b([A-Z][A-Za-z0-9_]+)\b"),
|
|
63
|
+
param_type_re=re.compile(
|
|
64
|
+
r"(?:const\s+)?([A-Z][A-Za-z0-9_]+)\s*(?:\*+|&)?\s+\w+"
|
|
65
|
+
),
|
|
66
|
+
basic_skip_types=frozenset({
|
|
67
|
+
"int8", "int16", "int32", "int64",
|
|
68
|
+
"uint8", "uint16", "uint32", "uint64",
|
|
69
|
+
"float", "double", "bool", "void", "int", "char", "long", "short",
|
|
70
|
+
"unsigned", "size_t",
|
|
71
|
+
}),
|
|
72
|
+
# Block classification helpers
|
|
73
|
+
block_keyword_re=re.compile(r"\b(?:struct|enum|union)\b"),
|
|
74
|
+
# No lambdas in C
|
|
75
|
+
lambda_re=None,
|
|
76
|
+
# No namespaces in C
|
|
77
|
+
namespace_sig_re=_NEVER_MATCH,
|
|
78
|
+
init_list_re=None,
|
|
79
|
+
# View / summary helpers
|
|
80
|
+
access_spec_names=frozenset(),
|
|
81
|
+
view_structural_kws=("struct ", "enum ", "union "),
|
|
82
|
+
view_modifier_kws=("static ", "FORCEINLINE"),
|
|
83
|
+
local_var_modifiers="const|static|volatile",
|
|
84
|
+
# Bracket scanner hints
|
|
85
|
+
verbatim_string_prefix=None,
|
|
86
|
+
raw_string_char="R",
|
|
87
|
+
# Function body summary hints — C has no range-based for
|
|
88
|
+
range_for_re=None,
|
|
89
|
+
# Comment syntax
|
|
90
|
+
line_comment="//",
|
|
91
|
+
block_comment_pair=("/*", "*/"),
|
|
92
|
+
# String syntax
|
|
93
|
+
string_delimiters=frozenset({'"', "'"}),
|
|
94
|
+
string_escape_char="\\",
|
|
95
|
+
triple_quote_strings=(),
|
|
96
|
+
# Block style
|
|
97
|
+
uses_indent_blocks=False,
|
|
98
|
+
# Preprocessor
|
|
99
|
+
preprocessor_prefix="#",
|
|
100
|
+
has_preprocessor_macros=True,
|
|
101
|
+
# Statement / block close
|
|
102
|
+
statement_terminator=";",
|
|
103
|
+
block_close_suffix="};",
|
|
104
|
+
summary_comment_prefix="//",
|
|
105
|
+
# Config-driven control flow
|
|
106
|
+
control_flow_patterns=(
|
|
107
|
+
("for", re.compile(r"^\s*for\s*\((.{1,80})\)\s*\{?\s*$")),
|
|
108
|
+
("while", re.compile(r"^\s*while\s*\((.{1,80})\)\s*\{?\s*$")),
|
|
109
|
+
("if", re.compile(r"^\s*(?:else\s+)?if\s*\((.{1,80})\)\s*\{?\s*$")),
|
|
110
|
+
("switch", re.compile(r"^\s*switch\s*\((.{1,40})\)\s*\{?\s*$")),
|
|
111
|
+
),
|
|
112
|
+
return_re=re.compile(r"^\s*return\s+(.{1,60});"),
|
|
113
|
+
# Extra syntax hints
|
|
114
|
+
type_indicator_chars="*&",
|
|
115
|
+
define_line_re=re.compile(r"#\s*define\s+(\w+)(\([^)]*\))?\s*(.*)"),
|
|
116
|
+
has_template_strings=False,
|
|
117
|
+
raw_string_style="cpp",
|
|
118
|
+
)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""C/C++ language configuration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from ..configs import LanguageConfig
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def make_cpp_language() -> LanguageConfig:
|
|
11
|
+
"""C/C++ language configuration."""
|
|
12
|
+
return LanguageConfig(
|
|
13
|
+
name="cpp",
|
|
14
|
+
class_re=re.compile(
|
|
15
|
+
r"(?:^|\s)(class|struct)\s+"
|
|
16
|
+
r"(?:(?:[A-Z][A-Z0-9_]*_API|[A-Z][A-Z0-9_]*(?:\s*\([^)]*\))?)\s+)*"
|
|
17
|
+
r"(\w+)"
|
|
18
|
+
r"\s*(?::\s*(?:public|protected|private)\s+(\w+))?",
|
|
19
|
+
),
|
|
20
|
+
enum_re=re.compile(r"\benum\s+(?:(?:class|struct)\s+)?(\w+)"),
|
|
21
|
+
namespace_re=re.compile(r"\bnamespace\s+(\w+)"),
|
|
22
|
+
func_name_re=re.compile(r"(\w+(?:\s*::\s*\w+)*)\s*\([^)]*\)\s*$"),
|
|
23
|
+
export_macro_re=re.compile(r"\b[A-Z][A-Z0-9_]*_API\b"),
|
|
24
|
+
calling_conv_re=re.compile(
|
|
25
|
+
r"\b(?:__cdecl|__stdcall|__fastcall|__thiscall|__vectorcall|WINAPI|CALLBACK|"
|
|
26
|
+
r"STDMETHODCALLTYPE|FORCEINLINE|FORCENOINLINE|FORCEINLINE_DEBUGGABLE|inline)\b"
|
|
27
|
+
),
|
|
28
|
+
attribute_re=re.compile(
|
|
29
|
+
r"\b(?:__declspec|__attribute__|alignas)\s*\([^)]*(?:\)[^)]*)?\)|\[\[[^\]]*\]\]"
|
|
30
|
+
),
|
|
31
|
+
template_re=re.compile(r"\btemplate\s*<[^<>]*>"),
|
|
32
|
+
dtor_re=re.compile(r"~(\w+)\s*\("),
|
|
33
|
+
control_flow_re=re.compile(r"\b(if|else\s+if|else|while|for|do|switch|catch|try)\b"),
|
|
34
|
+
control_flow_names=frozenset({
|
|
35
|
+
"if", "else", "while", "for", "do", "switch", "catch", "try",
|
|
36
|
+
"return", "delete", "goto", "break", "continue", "throw",
|
|
37
|
+
"co_await", "co_yield", "co_return",
|
|
38
|
+
}),
|
|
39
|
+
trailing_mods_re=re.compile(
|
|
40
|
+
r"\s*(?:const|override|final|noexcept|mutable|constexpr|inline|static)\s*[;{]*\s*$"
|
|
41
|
+
),
|
|
42
|
+
access_spec_re=re.compile(r"^(?:public|private|protected)\s*:\s*(?://.*)?$"),
|
|
43
|
+
macro_like_re=re.compile(r"^[A-Z][A-Z0-9_]*\s*(?:\([^{};]*\))?\s*$"),
|
|
44
|
+
define_re=re.compile(r"#\s*define\s+"),
|
|
45
|
+
extern_c_re=re.compile(r'\bextern\s+"C"'),
|
|
46
|
+
operator_re=re.compile(r"\boperator\b"),
|
|
47
|
+
uses_braces=True,
|
|
48
|
+
uses_namespaces=True,
|
|
49
|
+
uses_colon_inheritance=True,
|
|
50
|
+
scope_operator="::",
|
|
51
|
+
base_keyword="Super",
|
|
52
|
+
static_call_re=re.compile(r"\b([A-Z][A-Za-z0-9_]+)::([A-Za-z_][A-Za-z0-9_]*)\s*\("),
|
|
53
|
+
super_call_re=re.compile(r"\bSuper::([A-Za-z_][A-Za-z0-9_]*)\s*\("),
|
|
54
|
+
type_re=re.compile(r"\b([A-Z][A-Za-z0-9_]+)\b"),
|
|
55
|
+
param_type_re=re.compile(
|
|
56
|
+
r"(?:const\s+)?([A-Z][A-Za-z0-9_]+)\s*(?:\*+|&)?\s+\w+"
|
|
57
|
+
),
|
|
58
|
+
basic_skip_types=frozenset({
|
|
59
|
+
"int8", "int16", "int32", "int64",
|
|
60
|
+
"uint8", "uint16", "uint32", "uint64",
|
|
61
|
+
"float", "double", "bool", "void", "int", "char", "long", "short",
|
|
62
|
+
"unsigned", "size_t", "auto", "nullptr_t",
|
|
63
|
+
}),
|
|
64
|
+
block_keyword_re=re.compile(r"\b(?:namespace|class|struct|enum)\b"),
|
|
65
|
+
lambda_re=re.compile(r"\[.*\]\s*[\(]"),
|
|
66
|
+
namespace_sig_re=re.compile(r"(?:inline\s+)?namespace\s+(\w+)?\s*$"),
|
|
67
|
+
init_list_re=re.compile(r"\)\s*:"),
|
|
68
|
+
access_spec_names=frozenset({"public:", "protected:", "private:"}),
|
|
69
|
+
view_structural_kws=("class ", "struct ", "enum ", "namespace "),
|
|
70
|
+
view_modifier_kws=("virtual ", "static ", "override", "FORCEINLINE"),
|
|
71
|
+
local_var_modifiers="const|static|mutable|constexpr|volatile",
|
|
72
|
+
verbatim_string_prefix=None,
|
|
73
|
+
raw_string_char="R",
|
|
74
|
+
range_for_re=re.compile(
|
|
75
|
+
r"for\s*\(\s*(?:const\s+)?(\w+(?:\s*<[^>]*>)?)\s*[*&]?\s+(\w+)\s*:\s*(\w+)"
|
|
76
|
+
),
|
|
77
|
+
# Comment syntax
|
|
78
|
+
line_comment="//",
|
|
79
|
+
block_comment_pair=("/*", "*/"),
|
|
80
|
+
# String syntax
|
|
81
|
+
string_delimiters=frozenset({'"', "'"}),
|
|
82
|
+
string_escape_char="\\",
|
|
83
|
+
triple_quote_strings=(),
|
|
84
|
+
# Block style
|
|
85
|
+
uses_indent_blocks=False,
|
|
86
|
+
# Preprocessor
|
|
87
|
+
preprocessor_prefix="#",
|
|
88
|
+
has_preprocessor_macros=True,
|
|
89
|
+
# Statement / block close
|
|
90
|
+
statement_terminator=";",
|
|
91
|
+
block_close_suffix="};",
|
|
92
|
+
summary_comment_prefix="//",
|
|
93
|
+
# Config-driven control flow
|
|
94
|
+
control_flow_patterns=(
|
|
95
|
+
("for", re.compile(r"^\s*for\s*\((.{1,80})\)\s*\{?\s*$")),
|
|
96
|
+
("while", re.compile(r"^\s*while\s*\((.{1,80})\)\s*\{?\s*$")),
|
|
97
|
+
("if", re.compile(r"^\s*(?:else\s+)?if\s*\((.{1,80})\)\s*\{?\s*$")),
|
|
98
|
+
("switch", re.compile(r"^\s*switch\s*\((.{1,40})\)\s*\{?\s*$")),
|
|
99
|
+
),
|
|
100
|
+
return_re=re.compile(r"^\s*return\s+(.{1,60});"),
|
|
101
|
+
# Extra syntax hints
|
|
102
|
+
type_indicator_chars="*&",
|
|
103
|
+
define_line_re=re.compile(r"#\s*define\s+(\w+)(\([^)]*\))?\s*(.*)"),
|
|
104
|
+
has_template_strings=False,
|
|
105
|
+
raw_string_style="cpp",
|
|
106
|
+
)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""C# language configuration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from ..configs import LanguageConfig
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def make_csharp_language() -> LanguageConfig:
|
|
11
|
+
"""C# language configuration."""
|
|
12
|
+
return LanguageConfig(
|
|
13
|
+
name="csharp",
|
|
14
|
+
class_re=re.compile(
|
|
15
|
+
r"(?:^|\s)(class|struct|interface|record)"
|
|
16
|
+
r"(?:\s+(?:class|struct))?"
|
|
17
|
+
r"\s+"
|
|
18
|
+
r"(\w+)"
|
|
19
|
+
r"\s*(?::\s*(\w+))?",
|
|
20
|
+
),
|
|
21
|
+
enum_re=re.compile(r"\benum\s+(\w+)"),
|
|
22
|
+
namespace_re=re.compile(r"\bnamespace\s+([\w.]+)"),
|
|
23
|
+
func_name_re=re.compile(r"(\w+)\s*\([^)]*\)\s*$"),
|
|
24
|
+
export_macro_re=re.compile(r"(?!x)x"),
|
|
25
|
+
calling_conv_re=re.compile(r"(?!x)x"),
|
|
26
|
+
attribute_re=re.compile(r"\[[^\]]*\]"),
|
|
27
|
+
template_re=re.compile(r"<[^<>]*>"),
|
|
28
|
+
dtor_re=re.compile(r"(?!x)x"),
|
|
29
|
+
control_flow_re=re.compile(r"\b(if|else\s+if|else|while|for|foreach|do|switch|catch|try|using|lock)\b"),
|
|
30
|
+
control_flow_names=frozenset({
|
|
31
|
+
"if", "else", "while", "for", "foreach", "do", "switch", "catch", "try",
|
|
32
|
+
"return", "break", "continue", "throw", "using", "lock", "yield",
|
|
33
|
+
"async", "await", "new", "this", "base", "typeof", "sizeof", "nameof",
|
|
34
|
+
"default", "checked", "unchecked", "delegate",
|
|
35
|
+
}),
|
|
36
|
+
trailing_mods_re=re.compile(r"\s*(?:override|virtual|abstract|sealed|static|async)\s*[;{]*\s*$"),
|
|
37
|
+
access_spec_re=re.compile(r"^(?!x)x"),
|
|
38
|
+
macro_like_re=re.compile(r"(?!x)x"),
|
|
39
|
+
define_re=re.compile(r"(?!x)x"),
|
|
40
|
+
extern_c_re=re.compile(r"(?!x)x"),
|
|
41
|
+
operator_re=None,
|
|
42
|
+
uses_braces=True,
|
|
43
|
+
uses_namespaces=True,
|
|
44
|
+
uses_colon_inheritance=True,
|
|
45
|
+
scope_operator=".",
|
|
46
|
+
base_keyword="base",
|
|
47
|
+
static_call_re=re.compile(r"\b([A-Z][A-Za-z0-9_]+)\.([A-Za-z_][A-Za-z0-9_]*)\s*\("),
|
|
48
|
+
super_call_re=re.compile(r"\bbase\.([A-Za-z_][A-Za-z0-9_]*)\s*\("),
|
|
49
|
+
type_re=re.compile(r"\b([A-Z][A-Za-z0-9_]+)\b"),
|
|
50
|
+
param_type_re=re.compile(r"([A-Z][A-Za-z0-9_]+)\s+\w+"),
|
|
51
|
+
basic_skip_types=frozenset({
|
|
52
|
+
"int", "uint", "long", "ulong", "short", "ushort",
|
|
53
|
+
"byte", "sbyte", "float", "double", "decimal",
|
|
54
|
+
"bool", "string", "object", "void", "char",
|
|
55
|
+
"var", "dynamic", "nint", "nuint",
|
|
56
|
+
}),
|
|
57
|
+
block_keyword_re=re.compile(r"\b(?:namespace|class|struct|interface|record|enum)\b"),
|
|
58
|
+
lambda_re=re.compile(r"(?:\w+\s*=>|delegate\s*\()"),
|
|
59
|
+
namespace_sig_re=re.compile(r"namespace\s+([\w.]+)\s*$"),
|
|
60
|
+
init_list_re=None,
|
|
61
|
+
access_spec_names=frozenset({
|
|
62
|
+
"public", "private", "protected", "internal",
|
|
63
|
+
"protected internal", "private protected",
|
|
64
|
+
}),
|
|
65
|
+
view_structural_kws=("class ", "struct ", "interface ", "record ", "enum ", "namespace "),
|
|
66
|
+
view_modifier_kws=("virtual ", "static ", "override", "abstract ", "sealed ", "async "),
|
|
67
|
+
local_var_modifiers="const|static|volatile|readonly|ref|out",
|
|
68
|
+
verbatim_string_prefix="@",
|
|
69
|
+
raw_string_char=None,
|
|
70
|
+
range_for_re=re.compile(
|
|
71
|
+
r"foreach\s*\(\s*(\w+(?:\s*<[^>]*>)?)\s+(\w+)\s+in\s+(\w+)"
|
|
72
|
+
),
|
|
73
|
+
# Comment syntax
|
|
74
|
+
line_comment="//",
|
|
75
|
+
block_comment_pair=("/*", "*/"),
|
|
76
|
+
# String syntax
|
|
77
|
+
string_delimiters=frozenset({'"'}),
|
|
78
|
+
string_escape_char="\\",
|
|
79
|
+
triple_quote_strings=(),
|
|
80
|
+
# Block style
|
|
81
|
+
uses_indent_blocks=False,
|
|
82
|
+
# Preprocessor
|
|
83
|
+
preprocessor_prefix="",
|
|
84
|
+
has_preprocessor_macros=False,
|
|
85
|
+
# Statement / block close
|
|
86
|
+
statement_terminator=";",
|
|
87
|
+
block_close_suffix="}",
|
|
88
|
+
summary_comment_prefix="//",
|
|
89
|
+
# Config-driven control flow
|
|
90
|
+
control_flow_patterns=(
|
|
91
|
+
("for", re.compile(r"^\s*for\s*\((.{1,80})\)\s*\{?\s*$")),
|
|
92
|
+
("foreach", re.compile(r"^\s*foreach\s*\((.{1,80})\)\s*\{?\s*$")),
|
|
93
|
+
("while", re.compile(r"^\s*while\s*\((.{1,80})\)\s*\{?\s*$")),
|
|
94
|
+
("if", re.compile(r"^\s*(?:else\s+)?if\s*\((.{1,80})\)\s*\{?\s*$")),
|
|
95
|
+
("switch", re.compile(r"^\s*switch\s*\((.{1,40})\)\s*\{?\s*$")),
|
|
96
|
+
),
|
|
97
|
+
return_re=re.compile(r"^\s*return\s+(.{1,60});"),
|
|
98
|
+
# Extra syntax hints
|
|
99
|
+
type_indicator_chars="",
|
|
100
|
+
define_line_re=None,
|
|
101
|
+
has_template_strings=False,
|
|
102
|
+
raw_string_style="cpp",
|
|
103
|
+
)
|