Skip to content

Commit cd274bc

Browse files
committed
Parse some C++/CLI symbols
1 parent 4fcf6aa commit cd274bc

File tree

4 files changed

+105
-6
lines changed

4 files changed

+105
-6
lines changed

msvc-demangler.mjs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export class Demangler {
3232
this.index++;
3333
return map['0-9'](+c);
3434
}
35-
return call(map.default || error);
35+
return call(map['default'] || error);
3636
};
3737
}
3838
parse_list(f) {
@@ -277,6 +277,28 @@ export class Demangler {
277277
}
278278
parse_modifiers() {
279279
const optional_modifiers = this.parse_optional_modifiers();
280+
const cli_type = this.parse("cli type")({
281+
'$': () => this.parse("cli type", '$')({
282+
'A': () => ({ cli_type: '^' }),
283+
'B': () => ({ cli_type: 'pin_ptr' }),
284+
'C': () => ({ cli_type: '%' }),
285+
default: () => {
286+
const dimension = this.input.slice(this.index, this.index + 2);
287+
const rank = +('0x' + dimension);
288+
if (rank > 0 && rank <= 32) {
289+
this.index += 2;
290+
return this.parse("cli type", '$' + dimension)({
291+
'$': () => ({ cli_type: 'array', cli_array_rank: rank }),
292+
default: () => ({ cli_type: 'array^', cli_array_rank: rank }),
293+
});
294+
}
295+
return this.parse("cli type")({
296+
default: error,
297+
});
298+
},
299+
}),
300+
default: () => ({}),
301+
});
280302
const modifiers = this.parse("type qualifier")({
281303
'A': () => ({}),
282304
'B': () => ({ cv: 'const' }),
@@ -296,7 +318,7 @@ export class Demangler {
296318
'P': () => ({ cv: 'const volatile', based: this.parse_based_modifier() }),
297319
default: error,
298320
});
299-
return { ...optional_modifiers, ...modifiers };
321+
return { ...optional_modifiers, ...cli_type, ...modifiers };
300322
}
301323
parse_member_function_type() {
302324
return { ...this.parse_modifiers(), ...this.parse_function_type() };
@@ -336,7 +358,7 @@ export class Demangler {
336358
'@': () => ({}),
337359
default: () => ({ return_type: this.parse_type() }),
338360
});
339-
const { params, variadic } = this.parse("function parameter list")({
361+
const param_list = this.parse("function parameter list")({
340362
'X': () => ({ params: [] }),
341363
default: () => this.parse_parameter_list(),
342364
});
@@ -346,7 +368,7 @@ export class Demangler {
346368
'E': () => ({ noexcept: 'noexcept' }),
347369
})
348370
});
349-
return { typekind: 'function', ...cc, ...return_type, params, variadic, ...except };
371+
return { typekind: 'function', ...cc, ...return_type, ...param_list, ...except };
350372
}
351373
parse_array_type() {
352374
const dimension = this.parse_integer();
@@ -592,6 +614,7 @@ export class Demangler {
592614
'9': error,
593615
'_': () => this.parse('type', '__')({
594616
'R': () => ({ typekind: 'builtin', typename: 'unknown-type' }),
617+
'Z': () => ({ cli_typekind: 'value class', ...this.parse_type() }),
595618
}),
596619
'$': todo,
597620
}),
@@ -693,6 +716,11 @@ export class Demangler {
693716
vtordisp: this.parse_integer(), adjustment: this.parse_integer(), ...this.parse_member_function_type()
694717
}),
695718
'$': () => this.parse("entity info", '$$')({
719+
'F': () => ({ cli_kind: 'C++ managed-IL function', ...this.parse_extra_info() }),
720+
'H': () => ({ cli_kind: 'C++ managed-IL main', ...this.parse_extra_info() }),
721+
'J': () => this.parse("entity info", '$$J')({
722+
'0': () => ({ cli_kind: 'C managed-IL function', ...this.parse_extra_info() }),
723+
}),
696724
'h': () => ({ target: 'ARM64EC', ...this.parse_extra_info() }),
697725
}),
698726
default: () => ({
@@ -875,6 +903,25 @@ function print_type(ast) {
875903
case 'pointer':
876904
case 'reference':
877905
const [left, right] = print_type(ast.pointee_type);
906+
if (ast.pointee_type.cli_type) {
907+
switch (ast.pointee_type.cli_type) {
908+
case 'pin_ptr':
909+
return [filter_join(' ')([ast.cv, `cli::pin_ptr<${left + right}>`]), ''];
910+
case 'array^':
911+
case 'array':
912+
const rank = ast.pointee_type.cli_array_rank;
913+
const args = filter_join(', ')([left + right, rank === 1 ? '' : '' + rank]);
914+
if (ast.pointee_type.cli_type == 'array^') {
915+
return [filter_join(' ')([ast.cv, `cli::array<${args}>^`]), ''];
916+
}
917+
else {
918+
return [filter_join(' ')([ast.cv, `cli::array<${args}>`]), ''];
919+
}
920+
case '^':
921+
case '%':
922+
return [filter_join(' ')([left, ast.pointee_type.cli_type, ast.cv]), right];
923+
}
924+
}
878925
const class_name = ast.pointee_type.class_name;
879926
const typename = class_name ? print_qualified_name(class_name) + '::' + ast.typename : ast.typename;
880927
if (ast.pointee_type.typekind === 'array' || ast.pointee_type.typekind === 'function')

tests/check.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ async function read_input(filename) {
3232
async function test(filename, outname) {
3333
const { options, mangled, demangled } = await read_input(filename);
3434

35-
const ls = spawn('cl', [...options, '/nologo', '/Fa'+outname, '/c', '/FoNUL', filename]);
35+
const ls = spawn('cl.exe', [...options, '/nologo', '/Fa'+outname, '/c', '/FoNUL', filename]);
3636

3737
let stdout = '';
3838

@@ -77,3 +77,4 @@ async function test(filename, outname) {
7777
test('test1.cpp', 'test1.asm');
7878
test('test2.cpp', 'test2.asm');
7979
test('test3.cpp', 'test3.asm');
80+
test('test4.cpp', 'test4.asm');

tests/test1.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ type1 type7::var5;
388388
// DEMANGLED: void type7::'dynamic atexit destructor for 'type7::var6<int>''()
389389

390390
template<class T> type1 type7::var6;
391-
int x = (false ? type7::var6<int> -> ~type1() : void(), 1);
391+
int x = (false ? ++type7::var6<int> : void(), 1);
392392

393393
// MANGLED: ??__K_a@@YAXPBD@Z
394394
// DEMANGLED: void operator""_a(const char *)

tests/test4.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// OPTIONS: /clr
2+
3+
// MANGLED: ?main@@$$HYAHXZ
4+
// DEMANGLED: int main()
5+
int main() {}
6+
7+
// MANGLED: ?f1@@$$FYAXXZ
8+
// DEMANGLED: void f1()
9+
void f1() {}
10+
11+
// MANGLED: ?f2@@YMXP$AA__ZVInt32@System@@@Z
12+
// DEMANGLED: void f2(System::Int32 ^)
13+
void f2(int^) {}
14+
15+
// MANGLED: ?f3@@YAXA$CAH@Z
16+
// DEMANGLED: void f3(int %)
17+
void f3(int%) {}
18+
19+
// MANGLED: ?f4@@YMXP$01AH@Z
20+
// DEMANGLED: void f4(cli::array<int>^)
21+
void f4(array<int>^) {}
22+
23+
template<class> void f5() {}
24+
25+
void f6() {
26+
27+
// MANGLED: ??$f5@Q$CAH@@$$FYAXXZ
28+
// DEMANGLED: void f5<int % const>()
29+
f5<const interior_ptr<int>>();
30+
31+
// MANGLED: ??$f5@R$BAH@@$$FYAXXZ
32+
// DEMANGLED: void f5<volatile cli::pin_ptr<int>>()
33+
f5<pin_ptr<int>>();
34+
35+
// MANGLED: ??$f5@S$BAH@@$$FYAXXZ
36+
// DEMANGLED: void f5<const volatile cli::pin_ptr<int>>()
37+
f5<const pin_ptr<int>>();
38+
39+
// MANGLED: ??$f5@P$20$AH@@$$FYAXXZ
40+
// DEMANGLED: void f5<cli::array<int, 32>>()
41+
f5<array<int, 32>>();
42+
43+
// MANGLED: ??$f5@Q$20$AH@@$$FYAXXZ
44+
// DEMANGLED: void f5<const cli::array<int, 32>>()
45+
f5<const array<int, 32>>();
46+
47+
// MANGLED: ??$f5@Q$20AH@@$$FYAXXZ
48+
// DEMANGLED: void f5<const cli::array<int, 32>^>()
49+
f5<const array<int, 32>^>();
50+
51+
}

0 commit comments

Comments
 (0)