mirror of
https://github.com/ryujinx-mirror/ryujinx.git
synced 2024-12-23 15:25:45 +00:00
Rewrite the C++ Demangler (#416)
* Rewrite the C++ Demangler This new Demangler provides support to almost every possible mangled symbols and should behaves like GNU c++filt. It works on 98.9% of the sdk's symbols and 99.5% of Puyo Puyo Tetris's symbols. * Fix code style * Fix noexcept enclosed expression parsing issues * fix code style issues
This commit is contained in:
parent
7542f4a65f
commit
46a11460d4
54 changed files with 5113 additions and 417 deletions
|
@ -1,416 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Diagnostics
|
|
||||||
{
|
|
||||||
static class Demangler
|
|
||||||
{
|
|
||||||
private static readonly Dictionary<string, string> BuiltinTypes = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "v", "void" },
|
|
||||||
{ "w", "wchar_t" },
|
|
||||||
{ "b", "bool" },
|
|
||||||
{ "c", "char" },
|
|
||||||
{ "a", "signed char" },
|
|
||||||
{ "h", "unsigned char" },
|
|
||||||
{ "s", "short" },
|
|
||||||
{ "t", "unsigned short" },
|
|
||||||
{ "i", "int" },
|
|
||||||
{ "j", "unsigned int" },
|
|
||||||
{ "l", "long" },
|
|
||||||
{ "m", "unsigned long" },
|
|
||||||
{ "x", "long long" },
|
|
||||||
{ "y", "unsigned long long" },
|
|
||||||
{ "n", "__int128" },
|
|
||||||
{ "o", "unsigned __int128" },
|
|
||||||
{ "f", "float" },
|
|
||||||
{ "d", "double" },
|
|
||||||
{ "e", "long double" },
|
|
||||||
{ "g", "__float128" },
|
|
||||||
{ "z", "..." },
|
|
||||||
{ "Dd", "__iec559_double" },
|
|
||||||
{ "De", "__iec559_float128" },
|
|
||||||
{ "Df", "__iec559_float" },
|
|
||||||
{ "Dh", "__iec559_float16" },
|
|
||||||
{ "Di", "char32_t" },
|
|
||||||
{ "Ds", "char16_t" },
|
|
||||||
{ "Da", "decltype(auto)" },
|
|
||||||
{ "Dn", "std::nullptr_t" },
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, string> SubstitutionExtra = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{"Sa", "std::allocator"},
|
|
||||||
{"Sb", "std::basic_string"},
|
|
||||||
{"Ss", "std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>"},
|
|
||||||
{"Si", "std::basic_istream<char, ::std::char_traits<char>>"},
|
|
||||||
{"So", "std::basic_ostream<char, ::std::char_traits<char>>"},
|
|
||||||
{"Sd", "std::basic_iostream<char, ::std::char_traits<char>>"}
|
|
||||||
};
|
|
||||||
|
|
||||||
private static int FromBase36(string encoded)
|
|
||||||
{
|
|
||||||
string base36 = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
||||||
char[] reversedEncoded = encoded.ToLower().ToCharArray().Reverse().ToArray();
|
|
||||||
int result = 0;
|
|
||||||
for (int i = 0; i < reversedEncoded.Length; i++)
|
|
||||||
{
|
|
||||||
char c = reversedEncoded[i];
|
|
||||||
int value = base36.IndexOf(c);
|
|
||||||
if (value == -1)
|
|
||||||
return -1;
|
|
||||||
result += value * (int)Math.Pow(36, i);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetCompressedValue(string compression, List<string> compressionData, out int pos)
|
|
||||||
{
|
|
||||||
string res = null;
|
|
||||||
bool canHaveUnqualifiedName = false;
|
|
||||||
pos = -1;
|
|
||||||
if (compressionData.Count == 0 || !compression.StartsWith("S"))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (compression.Length >= 2 && SubstitutionExtra.TryGetValue(compression.Substring(0, 2), out string substitutionValue))
|
|
||||||
{
|
|
||||||
pos = 1;
|
|
||||||
res = substitutionValue;
|
|
||||||
compression = compression.Substring(2);
|
|
||||||
}
|
|
||||||
else if (compression.StartsWith("St"))
|
|
||||||
{
|
|
||||||
pos = 1;
|
|
||||||
canHaveUnqualifiedName = true;
|
|
||||||
res = "std";
|
|
||||||
compression = compression.Substring(2);
|
|
||||||
}
|
|
||||||
else if (compression.StartsWith("S_"))
|
|
||||||
{
|
|
||||||
pos = 1;
|
|
||||||
res = compressionData[0];
|
|
||||||
canHaveUnqualifiedName = true;
|
|
||||||
compression = compression.Substring(2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int id = -1;
|
|
||||||
int underscorePos = compression.IndexOf('_');
|
|
||||||
if (underscorePos == -1)
|
|
||||||
return null;
|
|
||||||
string partialId = compression.Substring(1, underscorePos - 1);
|
|
||||||
|
|
||||||
id = FromBase36(partialId);
|
|
||||||
if (id == -1 || compressionData.Count <= (id + 1))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
res = compressionData[id + 1];
|
|
||||||
pos = partialId.Length + 1;
|
|
||||||
canHaveUnqualifiedName= true;
|
|
||||||
compression = compression.Substring(pos);
|
|
||||||
}
|
|
||||||
if (res != null)
|
|
||||||
{
|
|
||||||
if (canHaveUnqualifiedName)
|
|
||||||
{
|
|
||||||
List<string> type = ReadName(compression, compressionData, out int endOfNameType);
|
|
||||||
if (endOfNameType != -1 && type != null)
|
|
||||||
{
|
|
||||||
pos += endOfNameType;
|
|
||||||
res = res + "::" + type[type.Count - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<string> ReadName(string mangled, List<string> compressionData, out int pos, bool isNested = true)
|
|
||||||
{
|
|
||||||
List<string> res = new List<string>();
|
|
||||||
string charCountString = null;
|
|
||||||
int charCount = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
pos = -1;
|
|
||||||
for (i = 0; i < mangled.Length; i++)
|
|
||||||
{
|
|
||||||
char chr = mangled[i];
|
|
||||||
if (charCountString == null)
|
|
||||||
{
|
|
||||||
if (ReadCVQualifiers(chr) != null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (chr == 'S')
|
|
||||||
{
|
|
||||||
string data = GetCompressedValue(mangled.Substring(i), compressionData, out pos);
|
|
||||||
if (pos == -1)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (res.Count == 0)
|
|
||||||
res.Add(data);
|
|
||||||
else
|
|
||||||
res.Add(res[res.Count - 1] + "::" + data);
|
|
||||||
i += pos;
|
|
||||||
if (i < mangled.Length && mangled[i] == 'E')
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (chr == 'E')
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Char.IsDigit(chr))
|
|
||||||
{
|
|
||||||
charCountString += chr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!int.TryParse(charCountString, out charCount))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
string demangledPart = mangled.Substring(i, charCount);
|
|
||||||
if (res.Count == 0)
|
|
||||||
res.Add(demangledPart);
|
|
||||||
else
|
|
||||||
res.Add(res[res.Count - 1] + "::" + demangledPart);
|
|
||||||
i = i + charCount - 1;
|
|
||||||
charCount = 0;
|
|
||||||
charCountString = null;
|
|
||||||
if (!isNested)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (res.Count == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
pos = i;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReadBuiltinType(string mangledType, out int pos)
|
|
||||||
{
|
|
||||||
string res = null;
|
|
||||||
string possibleBuiltinType;
|
|
||||||
pos = -1;
|
|
||||||
possibleBuiltinType = mangledType[0].ToString();
|
|
||||||
if (!BuiltinTypes.TryGetValue(possibleBuiltinType, out res))
|
|
||||||
{
|
|
||||||
if (mangledType.Length >= 2)
|
|
||||||
{
|
|
||||||
// Try to match the first 2 chars if the first call failed
|
|
||||||
possibleBuiltinType = mangledType.Substring(0, 2);
|
|
||||||
BuiltinTypes.TryGetValue(possibleBuiltinType, out res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (res != null)
|
|
||||||
pos = possibleBuiltinType.Length;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReadCVQualifiers(char qualifier)
|
|
||||||
{
|
|
||||||
if (qualifier == 'r')
|
|
||||||
return "restricted";
|
|
||||||
else if (qualifier == 'V')
|
|
||||||
return "volatile";
|
|
||||||
else if (qualifier == 'K')
|
|
||||||
return "const";
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReadRefQualifiers(char qualifier)
|
|
||||||
{
|
|
||||||
if (qualifier == 'R')
|
|
||||||
return "&";
|
|
||||||
else if (qualifier == 'O')
|
|
||||||
return "&&";
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReadSpecialQualifiers(char qualifier)
|
|
||||||
{
|
|
||||||
if (qualifier == 'P')
|
|
||||||
return "*";
|
|
||||||
else if (qualifier == 'C')
|
|
||||||
return "complex";
|
|
||||||
else if (qualifier == 'G')
|
|
||||||
return "imaginary";
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<string> ReadParameters(string mangledParams, List<string> compressionData, out int pos)
|
|
||||||
{
|
|
||||||
List<string> res = new List<string>();
|
|
||||||
List<string> refQualifiers = new List<string>();
|
|
||||||
string parsedTypePart = null;
|
|
||||||
string currentRefQualifiers = null;
|
|
||||||
string currentBuiltinType = null;
|
|
||||||
string currentSpecialQualifiers = null;
|
|
||||||
string currentCompressedValue = null;
|
|
||||||
int i = 0;
|
|
||||||
pos = -1;
|
|
||||||
|
|
||||||
for (i = 0; i < mangledParams.Length; i++)
|
|
||||||
{
|
|
||||||
if (currentBuiltinType != null)
|
|
||||||
{
|
|
||||||
string currentCVQualifier = String.Join(" ", refQualifiers);
|
|
||||||
// Try to mimic the compression indexing
|
|
||||||
if (currentRefQualifiers != null)
|
|
||||||
{
|
|
||||||
compressionData.Add(currentBuiltinType + currentRefQualifiers);
|
|
||||||
}
|
|
||||||
if (refQualifiers.Count != 0)
|
|
||||||
{
|
|
||||||
compressionData.Add(currentBuiltinType + " " + currentCVQualifier + currentRefQualifiers);
|
|
||||||
}
|
|
||||||
if (currentSpecialQualifiers != null)
|
|
||||||
{
|
|
||||||
compressionData.Add(currentBuiltinType + " " + currentCVQualifier + currentRefQualifiers + currentSpecialQualifiers);
|
|
||||||
}
|
|
||||||
if (currentRefQualifiers == null && currentCVQualifier == null && currentSpecialQualifiers == null)
|
|
||||||
{
|
|
||||||
compressionData.Add(currentBuiltinType);
|
|
||||||
}
|
|
||||||
currentBuiltinType = null;
|
|
||||||
currentCompressedValue = null;
|
|
||||||
currentCVQualifier = null;
|
|
||||||
currentRefQualifiers = null;
|
|
||||||
refQualifiers.Clear();
|
|
||||||
currentSpecialQualifiers = null;
|
|
||||||
}
|
|
||||||
char chr = mangledParams[i];
|
|
||||||
string part = mangledParams.Substring(i);
|
|
||||||
|
|
||||||
// Try to read qualifiers
|
|
||||||
parsedTypePart = ReadCVQualifiers(chr);
|
|
||||||
if (parsedTypePart != null)
|
|
||||||
{
|
|
||||||
refQualifiers.Add(parsedTypePart);
|
|
||||||
|
|
||||||
// need more data
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedTypePart = ReadRefQualifiers(chr);
|
|
||||||
if (parsedTypePart != null)
|
|
||||||
{
|
|
||||||
currentRefQualifiers = parsedTypePart;
|
|
||||||
|
|
||||||
// need more data
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedTypePart = ReadSpecialQualifiers(chr);
|
|
||||||
if (parsedTypePart != null)
|
|
||||||
{
|
|
||||||
currentSpecialQualifiers = parsedTypePart;
|
|
||||||
|
|
||||||
// need more data
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: extended-qualifier?
|
|
||||||
|
|
||||||
if (part.StartsWith("S"))
|
|
||||||
{
|
|
||||||
parsedTypePart = GetCompressedValue(part, compressionData, out pos);
|
|
||||||
if (pos != -1 && parsedTypePart != null)
|
|
||||||
{
|
|
||||||
currentCompressedValue = parsedTypePart;
|
|
||||||
i += pos;
|
|
||||||
res.Add(currentCompressedValue + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers);
|
|
||||||
currentBuiltinType = null;
|
|
||||||
currentCompressedValue = null;
|
|
||||||
currentRefQualifiers = null;
|
|
||||||
refQualifiers.Clear();
|
|
||||||
currentSpecialQualifiers = null;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pos = -1;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else if (part.StartsWith("N"))
|
|
||||||
{
|
|
||||||
part = part.Substring(1);
|
|
||||||
List<string> name = ReadName(part, compressionData, out pos);
|
|
||||||
if (pos != -1 && name != null)
|
|
||||||
{
|
|
||||||
i += pos + 1;
|
|
||||||
res.Add(name[name.Count - 1] + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers);
|
|
||||||
currentBuiltinType = null;
|
|
||||||
currentCompressedValue = null;
|
|
||||||
currentRefQualifiers = null;
|
|
||||||
refQualifiers.Clear();
|
|
||||||
currentSpecialQualifiers = null;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try builting
|
|
||||||
parsedTypePart = ReadBuiltinType(part, out pos);
|
|
||||||
if (pos == -1)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
currentBuiltinType = parsedTypePart;
|
|
||||||
res.Add(currentBuiltinType + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers);
|
|
||||||
i = i + pos -1;
|
|
||||||
}
|
|
||||||
pos = i;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ParseFunctionName(string mangled)
|
|
||||||
{
|
|
||||||
List<string> compressionData = new List<string>();
|
|
||||||
int pos = 0;
|
|
||||||
string res;
|
|
||||||
bool isNested = mangled.StartsWith("N");
|
|
||||||
|
|
||||||
// If it's start with "N" it must be a nested function name
|
|
||||||
if (isNested)
|
|
||||||
mangled = mangled.Substring(1);
|
|
||||||
compressionData = ReadName(mangled, compressionData, out pos, isNested);
|
|
||||||
if (pos == -1)
|
|
||||||
return null;
|
|
||||||
res = compressionData[compressionData.Count - 1];
|
|
||||||
compressionData.Remove(res);
|
|
||||||
mangled = mangled.Substring(pos + 1);
|
|
||||||
|
|
||||||
// more data? maybe not a data name so...
|
|
||||||
if (mangled != String.Empty)
|
|
||||||
{
|
|
||||||
List<string> parameters = ReadParameters(mangled, compressionData, out pos);
|
|
||||||
// parameters parsing error, we return the original data to avoid information loss.
|
|
||||||
if (pos == -1)
|
|
||||||
return null;
|
|
||||||
parameters = parameters.Select(outer => outer.Trim()).ToList();
|
|
||||||
res += "(" + String.Join(", ", parameters) + ")";
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Parse(string originalMangled)
|
|
||||||
{
|
|
||||||
if (originalMangled.StartsWith("_Z"))
|
|
||||||
{
|
|
||||||
// We assume that we have a name (TOOD: support special names)
|
|
||||||
string res = ParseFunctionName(originalMangled.Substring(2));
|
|
||||||
if (res == null)
|
|
||||||
return originalMangled;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return originalMangled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class ArraySubscriptingExpression : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode LeftNode;
|
||||||
|
private BaseNode Subscript;
|
||||||
|
|
||||||
|
public ArraySubscriptingExpression(BaseNode LeftNode, BaseNode Subscript) : base(NodeType.ArraySubscriptingExpression)
|
||||||
|
{
|
||||||
|
this.LeftNode = LeftNode;
|
||||||
|
this.Subscript = Subscript;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
LeftNode.Print(Writer);
|
||||||
|
Writer.Write(")[");
|
||||||
|
Subscript.Print(Writer);
|
||||||
|
Writer.Write("]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ArrayType.cs
Normal file
59
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ArrayType.cs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class ArrayType : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode Base;
|
||||||
|
private BaseNode DimensionExpression;
|
||||||
|
private string DimensionString;
|
||||||
|
|
||||||
|
public ArrayType(BaseNode Base, BaseNode DimensionExpression = null) : base(NodeType.ArrayType)
|
||||||
|
{
|
||||||
|
this.Base = Base;
|
||||||
|
this.DimensionExpression = DimensionExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayType(BaseNode Base, string DimensionString) : base(NodeType.ArrayType)
|
||||||
|
{
|
||||||
|
this.Base = Base;
|
||||||
|
this.DimensionString = DimensionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasRightPart()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsArray()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Base.PrintLeft(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintRight(TextWriter Writer)
|
||||||
|
{
|
||||||
|
// FIXME: detect if previous char was a ].
|
||||||
|
Writer.Write(" ");
|
||||||
|
|
||||||
|
Writer.Write("[");
|
||||||
|
|
||||||
|
if (DimensionString != null)
|
||||||
|
{
|
||||||
|
Writer.Write(DimensionString);
|
||||||
|
}
|
||||||
|
else if (DimensionExpression != null)
|
||||||
|
{
|
||||||
|
DimensionExpression.Print(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write("]");
|
||||||
|
|
||||||
|
Base.PrintRight(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
113
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/BaseNode.cs
Normal file
113
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/BaseNode.cs
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public enum NodeType
|
||||||
|
{
|
||||||
|
CVQualifierType,
|
||||||
|
SimpleReferenceType,
|
||||||
|
NameType,
|
||||||
|
EncodedFunction,
|
||||||
|
NestedName,
|
||||||
|
SpecialName,
|
||||||
|
LiteralOperator,
|
||||||
|
NodeArray,
|
||||||
|
ElaboratedType,
|
||||||
|
PostfixQualifiedType,
|
||||||
|
SpecialSubstitution,
|
||||||
|
ExpandedSpecialSubstitution,
|
||||||
|
CtorDtorNameType,
|
||||||
|
EnclosedExpression,
|
||||||
|
ForwardTemplateReference,
|
||||||
|
NameTypeWithTemplateArguments,
|
||||||
|
PackedTemplateArgument,
|
||||||
|
TemplateArguments,
|
||||||
|
BooleanExpression,
|
||||||
|
CastExpression,
|
||||||
|
CallExpression,
|
||||||
|
IntegerCastExpression,
|
||||||
|
PackedTemplateParameter,
|
||||||
|
PackedTemplateParameterExpansion,
|
||||||
|
IntegerLiteral,
|
||||||
|
DeleteExpression,
|
||||||
|
MemberExpression,
|
||||||
|
ArraySubscriptingExpression,
|
||||||
|
InitListExpression,
|
||||||
|
PostfixExpression,
|
||||||
|
ConditionalExpression,
|
||||||
|
ThrowExpression,
|
||||||
|
FunctionParameter,
|
||||||
|
ConversionExpression,
|
||||||
|
BinaryExpression,
|
||||||
|
PrefixExpression,
|
||||||
|
BracedExpression,
|
||||||
|
BracedRangeExpression,
|
||||||
|
NewExpression,
|
||||||
|
QualifiedName,
|
||||||
|
StdQualifiedName,
|
||||||
|
DtOrName,
|
||||||
|
GlobalQualifiedName,
|
||||||
|
NoexceptSpec,
|
||||||
|
DynamicExceptionSpec,
|
||||||
|
FunctionType,
|
||||||
|
PointerType,
|
||||||
|
ReferenceType,
|
||||||
|
ConversionOperatorType,
|
||||||
|
LocalName,
|
||||||
|
CtorVtableSpecialName,
|
||||||
|
ArrayType
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class BaseNode
|
||||||
|
{
|
||||||
|
public NodeType Type { get; protected set; }
|
||||||
|
|
||||||
|
public BaseNode(NodeType Type)
|
||||||
|
{
|
||||||
|
this.Type = Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Print(TextWriter Writer)
|
||||||
|
{
|
||||||
|
PrintLeft(Writer);
|
||||||
|
|
||||||
|
if (HasRightPart())
|
||||||
|
{
|
||||||
|
PrintRight(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void PrintLeft(TextWriter Writer);
|
||||||
|
|
||||||
|
public virtual bool HasRightPart()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool IsArray()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool HasFunctions()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string GetName()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void PrintRight(TextWriter Writer) {}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringWriter Writer = new StringWriter();
|
||||||
|
|
||||||
|
Print(Writer);
|
||||||
|
|
||||||
|
return Writer.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class BinaryExpression : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode LeftPart;
|
||||||
|
private string Name;
|
||||||
|
private BaseNode RightPart;
|
||||||
|
|
||||||
|
public BinaryExpression(BaseNode LeftPart, string Name, BaseNode RightPart) : base(NodeType.BinaryExpression)
|
||||||
|
{
|
||||||
|
this.LeftPart = LeftPart;
|
||||||
|
this.Name = Name;
|
||||||
|
this.RightPart = RightPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (Name.Equals(">"))
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write("(");
|
||||||
|
LeftPart.Print(Writer);
|
||||||
|
Writer.Write(") ");
|
||||||
|
|
||||||
|
Writer.Write(Name);
|
||||||
|
|
||||||
|
Writer.Write(" (");
|
||||||
|
RightPart.Print(Writer);
|
||||||
|
Writer.Write(")");
|
||||||
|
|
||||||
|
if (Name.Equals(">"))
|
||||||
|
{
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class BracedExpression : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode Element;
|
||||||
|
private BaseNode Expression;
|
||||||
|
private bool IsArrayExpression;
|
||||||
|
|
||||||
|
public BracedExpression(BaseNode Element, BaseNode Expression, bool IsArrayExpression) : base(NodeType.BracedExpression)
|
||||||
|
{
|
||||||
|
this.Element = Element;
|
||||||
|
this.Expression = Expression;
|
||||||
|
this.IsArrayExpression = IsArrayExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (IsArrayExpression)
|
||||||
|
{
|
||||||
|
Writer.Write("[");
|
||||||
|
Element.Print(Writer);
|
||||||
|
Writer.Write("]");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Writer.Write(".");
|
||||||
|
Element.Print(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Expression.GetType().Equals(NodeType.BracedExpression) || !Expression.GetType().Equals(NodeType.BracedRangeExpression))
|
||||||
|
{
|
||||||
|
Writer.Write(" = ");
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class BracedRangeExpression : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode FirstNode;
|
||||||
|
private BaseNode LastNode;
|
||||||
|
private BaseNode Expression;
|
||||||
|
|
||||||
|
public BracedRangeExpression(BaseNode FirstNode, BaseNode LastNode, BaseNode Expression) : base(NodeType.BracedRangeExpression)
|
||||||
|
{
|
||||||
|
this.FirstNode = FirstNode;
|
||||||
|
this.LastNode = LastNode;
|
||||||
|
this.Expression = Expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("[");
|
||||||
|
FirstNode.Print(Writer);
|
||||||
|
Writer.Write(" ... ");
|
||||||
|
LastNode.Print(Writer);
|
||||||
|
Writer.Write("]");
|
||||||
|
|
||||||
|
if (!Expression.GetType().Equals(NodeType.BracedExpression) || !Expression.GetType().Equals(NodeType.BracedRangeExpression))
|
||||||
|
{
|
||||||
|
Writer.Write(" = ");
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/CallExpression.cs
Normal file
25
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/CallExpression.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class CallExpression : NodeArray
|
||||||
|
{
|
||||||
|
private BaseNode Callee;
|
||||||
|
|
||||||
|
public CallExpression(BaseNode Callee, List<BaseNode> Nodes) : base(Nodes, NodeType.CallExpression)
|
||||||
|
{
|
||||||
|
this.Callee = Callee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Callee.Print(Writer);
|
||||||
|
|
||||||
|
Writer.Write("(");
|
||||||
|
Writer.Write(string.Join<BaseNode>(", ", Nodes.ToArray()));
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/CasExpression.cs
Normal file
30
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/CasExpression.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class CastExpression : BaseNode
|
||||||
|
{
|
||||||
|
private string Kind;
|
||||||
|
private BaseNode To;
|
||||||
|
private BaseNode From;
|
||||||
|
|
||||||
|
public CastExpression(string Kind, BaseNode To, BaseNode From) : base(NodeType.CastExpression)
|
||||||
|
{
|
||||||
|
this.Kind = Kind;
|
||||||
|
this.To = To;
|
||||||
|
this.From = From;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write(Kind);
|
||||||
|
Writer.Write("<");
|
||||||
|
To.PrintLeft(Writer);
|
||||||
|
Writer.Write(">(");
|
||||||
|
From.PrintLeft(Writer);
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class ConditionalExpression : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode ThenNode;
|
||||||
|
private BaseNode ElseNode;
|
||||||
|
private BaseNode ConditionNode;
|
||||||
|
|
||||||
|
public ConditionalExpression(BaseNode ConditionNode, BaseNode ThenNode, BaseNode ElseNode) : base(NodeType.ConditionalExpression)
|
||||||
|
{
|
||||||
|
this.ThenNode = ThenNode;
|
||||||
|
this.ConditionNode = ConditionNode;
|
||||||
|
this.ElseNode = ElseNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
ConditionNode.Print(Writer);
|
||||||
|
Writer.Write(") ? (");
|
||||||
|
ThenNode.Print(Writer);
|
||||||
|
Writer.Write(") : (");
|
||||||
|
ElseNode.Print(Writer);
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class ConversionExpression : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode TypeNode;
|
||||||
|
private BaseNode Expressions;
|
||||||
|
|
||||||
|
public ConversionExpression(BaseNode TypeNode, BaseNode Expressions) : base(NodeType.ConversionExpression)
|
||||||
|
{
|
||||||
|
this.TypeNode = TypeNode;
|
||||||
|
this.Expressions = Expressions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
TypeNode.Print(Writer);
|
||||||
|
Writer.Write(")(");
|
||||||
|
Expressions.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class ConversionOperatorType : ParentNode
|
||||||
|
{
|
||||||
|
public ConversionOperatorType(BaseNode Child) : base(NodeType.ConversionOperatorType, Child) { }
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("operator ");
|
||||||
|
Child.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class CtorDtorNameType : ParentNode
|
||||||
|
{
|
||||||
|
private bool IsDestructor;
|
||||||
|
|
||||||
|
public CtorDtorNameType(BaseNode Name, bool IsDestructor) : base(NodeType.CtorDtorNameType, Name)
|
||||||
|
{
|
||||||
|
this.IsDestructor = IsDestructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (IsDestructor)
|
||||||
|
{
|
||||||
|
Writer.Write("~");
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write(Child.GetName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class CtorVtableSpecialName : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode FirstType;
|
||||||
|
private BaseNode SecondType;
|
||||||
|
|
||||||
|
public CtorVtableSpecialName(BaseNode FirstType, BaseNode SecondType) : base(NodeType.CtorVtableSpecialName)
|
||||||
|
{
|
||||||
|
this.FirstType = FirstType;
|
||||||
|
this.SecondType = SecondType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("construction vtable for ");
|
||||||
|
FirstType.Print(Writer);
|
||||||
|
Writer.Write("-in-");
|
||||||
|
SecondType.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class DeleteExpression : ParentNode
|
||||||
|
{
|
||||||
|
private bool IsGlobal;
|
||||||
|
private bool IsArrayExpression;
|
||||||
|
|
||||||
|
public DeleteExpression(BaseNode Child, bool IsGlobal, bool IsArrayExpression) : base(NodeType.DeleteExpression, Child)
|
||||||
|
{
|
||||||
|
this.IsGlobal = IsGlobal;
|
||||||
|
this.IsArrayExpression = IsArrayExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (IsGlobal)
|
||||||
|
{
|
||||||
|
Writer.Write("::");
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write("delete");
|
||||||
|
|
||||||
|
if (IsArrayExpression)
|
||||||
|
{
|
||||||
|
Writer.Write("[] ");
|
||||||
|
}
|
||||||
|
|
||||||
|
Child.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/DtorName.cs
Normal file
15
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/DtorName.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class DtorName : ParentNode
|
||||||
|
{
|
||||||
|
public DtorName(BaseNode Name) : base(NodeType.DtOrName, Name) { }
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("~");
|
||||||
|
Child.PrintLeft(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class DynamicExceptionSpec : ParentNode
|
||||||
|
{
|
||||||
|
public DynamicExceptionSpec(BaseNode Child) : base(NodeType.DynamicExceptionSpec, Child) { }
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("throw(");
|
||||||
|
Child.Print(Writer);
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ElaboratedType.cs
Normal file
21
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ElaboratedType.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class ElaboratedType : ParentNode
|
||||||
|
{
|
||||||
|
private string Elaborated;
|
||||||
|
|
||||||
|
public ElaboratedType(string Elaborated, BaseNode Type) : base(NodeType.ElaboratedType, Type)
|
||||||
|
{
|
||||||
|
this.Elaborated = Elaborated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write(Elaborated);
|
||||||
|
Writer.Write(" ");
|
||||||
|
Child.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class EnclosedExpression : BaseNode
|
||||||
|
{
|
||||||
|
private string Prefix;
|
||||||
|
private BaseNode Expression;
|
||||||
|
private string Postfix;
|
||||||
|
|
||||||
|
public EnclosedExpression(string Prefix, BaseNode Expression, string Postfix) : base(NodeType.EnclosedExpression)
|
||||||
|
{
|
||||||
|
this.Prefix = Prefix;
|
||||||
|
this.Expression = Expression;
|
||||||
|
this.Postfix = Postfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write(Prefix);
|
||||||
|
Expression.Print(Writer);
|
||||||
|
Writer.Write(Postfix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/EncodedFunction.cs
Normal file
77
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/EncodedFunction.cs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class EncodedFunction : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode Name;
|
||||||
|
private BaseNode Params;
|
||||||
|
private BaseNode CV;
|
||||||
|
private BaseNode Ref;
|
||||||
|
private BaseNode Attrs;
|
||||||
|
private BaseNode Ret;
|
||||||
|
|
||||||
|
public EncodedFunction(BaseNode Name, BaseNode Params, BaseNode CV, BaseNode Ref, BaseNode Attrs, BaseNode Ret) : base(NodeType.NameType)
|
||||||
|
{
|
||||||
|
this.Name = Name;
|
||||||
|
this.Params = Params;
|
||||||
|
this.CV = CV;
|
||||||
|
this.Ref = Ref;
|
||||||
|
this.Attrs = Attrs;
|
||||||
|
this.Ret = Ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (Ret != null)
|
||||||
|
{
|
||||||
|
Ret.PrintLeft(Writer);
|
||||||
|
|
||||||
|
if (!Ret.HasRightPart())
|
||||||
|
{
|
||||||
|
Writer.Write(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Name.Print(Writer);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasRightPart()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintRight(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
|
||||||
|
if (Params != null)
|
||||||
|
{
|
||||||
|
Params.Print(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write(")");
|
||||||
|
|
||||||
|
if (Ret != null)
|
||||||
|
{
|
||||||
|
Ret.PrintRight(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CV != null)
|
||||||
|
{
|
||||||
|
CV.Print(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Ref != null)
|
||||||
|
{
|
||||||
|
Ref.Print(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Attrs != null)
|
||||||
|
{
|
||||||
|
Attrs.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/FoldExpression.cs
Normal file
48
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/FoldExpression.cs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class FoldExpression : BaseNode
|
||||||
|
{
|
||||||
|
private bool IsLeftFold;
|
||||||
|
private string OperatorName;
|
||||||
|
private BaseNode Expression;
|
||||||
|
private BaseNode Initializer;
|
||||||
|
|
||||||
|
public FoldExpression(bool IsLeftFold, string OperatorName, BaseNode Expression, BaseNode Initializer) : base(NodeType.FunctionParameter)
|
||||||
|
{
|
||||||
|
this.IsLeftFold = IsLeftFold;
|
||||||
|
this.OperatorName = OperatorName;
|
||||||
|
this.Expression = Expression;
|
||||||
|
this.Initializer = Initializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
|
||||||
|
if (IsLeftFold && Initializer != null)
|
||||||
|
{
|
||||||
|
Initializer.Print(Writer);
|
||||||
|
Writer.Write(" ");
|
||||||
|
Writer.Write(OperatorName);
|
||||||
|
Writer.Write(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write(IsLeftFold ? "... " : " ");
|
||||||
|
Writer.Write(OperatorName);
|
||||||
|
Writer.Write(!IsLeftFold ? " ..." : " ");
|
||||||
|
Expression.Print(Writer);
|
||||||
|
|
||||||
|
if (!IsLeftFold && Initializer != null)
|
||||||
|
{
|
||||||
|
Initializer.Print(Writer);
|
||||||
|
Writer.Write(" ");
|
||||||
|
Writer.Write(OperatorName);
|
||||||
|
Writer.Write(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class ForwardTemplateReference : BaseNode
|
||||||
|
{
|
||||||
|
// TODO: Compute inside the Demangler
|
||||||
|
public BaseNode Reference;
|
||||||
|
private int Index;
|
||||||
|
|
||||||
|
public ForwardTemplateReference(int Index) : base(NodeType.ForwardTemplateReference)
|
||||||
|
{
|
||||||
|
this.Index = Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetName()
|
||||||
|
{
|
||||||
|
return Reference.GetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Reference.PrintLeft(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintRight(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Reference.PrintRight(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasRightPart()
|
||||||
|
{
|
||||||
|
return Reference.HasRightPart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class FunctionParameter : BaseNode
|
||||||
|
{
|
||||||
|
private string Number;
|
||||||
|
|
||||||
|
public FunctionParameter(string Number) : base(NodeType.FunctionParameter)
|
||||||
|
{
|
||||||
|
this.Number = Number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("fp ");
|
||||||
|
|
||||||
|
if (Number != null)
|
||||||
|
{
|
||||||
|
Writer.Write(Number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/FunctionType.cs
Normal file
61
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/FunctionType.cs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class FunctionType : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode ReturnType;
|
||||||
|
private BaseNode Params;
|
||||||
|
private BaseNode CVQualifier;
|
||||||
|
private SimpleReferenceType ReferenceQualifier;
|
||||||
|
private BaseNode ExceptionSpec;
|
||||||
|
|
||||||
|
public FunctionType(BaseNode ReturnType, BaseNode Params, BaseNode CVQualifier, SimpleReferenceType ReferenceQualifier, BaseNode ExceptionSpec) : base(NodeType.FunctionType)
|
||||||
|
{
|
||||||
|
this.ReturnType = ReturnType;
|
||||||
|
this.Params = Params;
|
||||||
|
this.CVQualifier = CVQualifier;
|
||||||
|
this.ReferenceQualifier = ReferenceQualifier;
|
||||||
|
this.ExceptionSpec = ExceptionSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
ReturnType.PrintLeft(Writer);
|
||||||
|
Writer.Write(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintRight(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
Params.Print(Writer);
|
||||||
|
Writer.Write(")");
|
||||||
|
|
||||||
|
ReturnType.PrintRight(Writer);
|
||||||
|
|
||||||
|
CVQualifier.Print(Writer);
|
||||||
|
|
||||||
|
if (ReferenceQualifier.Qualifier != Reference.None)
|
||||||
|
{
|
||||||
|
Writer.Write(" ");
|
||||||
|
ReferenceQualifier.PrintQualifier(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExceptionSpec != null)
|
||||||
|
{
|
||||||
|
Writer.Write(" ");
|
||||||
|
ExceptionSpec.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasRightPart()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasFunctions()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class GlobalQualifiedName : ParentNode
|
||||||
|
{
|
||||||
|
public GlobalQualifiedName(BaseNode Child) : base(NodeType.GlobalQualifiedName, Child) { }
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("::");
|
||||||
|
Child.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class InitListExpression : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode TypeNode;
|
||||||
|
private List<BaseNode> Nodes;
|
||||||
|
|
||||||
|
public InitListExpression(BaseNode TypeNode, List<BaseNode> Nodes) : base(NodeType.InitListExpression)
|
||||||
|
{
|
||||||
|
this.TypeNode = TypeNode;
|
||||||
|
this.Nodes = Nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (TypeNode != null)
|
||||||
|
{
|
||||||
|
TypeNode.Print(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write("{");
|
||||||
|
Writer.Write(string.Join<BaseNode>(", ", Nodes.ToArray()));
|
||||||
|
Writer.Write("}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class IntegerCastExpression : ParentNode
|
||||||
|
{
|
||||||
|
private string Number;
|
||||||
|
|
||||||
|
public IntegerCastExpression(BaseNode Type, string Number) : base(NodeType.IntegerCastExpression, Type)
|
||||||
|
{
|
||||||
|
this.Number = Number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
Child.Print(Writer);
|
||||||
|
Writer.Write(")");
|
||||||
|
Writer.Write(Number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/IntegerLiteral.cs
Normal file
41
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/IntegerLiteral.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class IntegerLiteral : BaseNode
|
||||||
|
{
|
||||||
|
private string LitteralName;
|
||||||
|
private string LitteralValue;
|
||||||
|
|
||||||
|
public IntegerLiteral(string LitteralName, string LitteralValue) : base(NodeType.IntegerLiteral)
|
||||||
|
{
|
||||||
|
this.LitteralValue = LitteralValue;
|
||||||
|
this.LitteralName = LitteralName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (LitteralName.Length > 3)
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
Writer.Write(LitteralName);
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LitteralValue[0] == 'n')
|
||||||
|
{
|
||||||
|
Writer.Write("-");
|
||||||
|
Writer.Write(LitteralValue.Substring(1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Writer.Write(LitteralValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LitteralName.Length <= 3)
|
||||||
|
{
|
||||||
|
Writer.Write(LitteralName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/LiteralOperator.cs
Normal file
16
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/LiteralOperator.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class LiteralOperator : ParentNode
|
||||||
|
{
|
||||||
|
public LiteralOperator(BaseNode Child) : base(NodeType.LiteralOperator, Child) { }
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("operator \"");
|
||||||
|
Child.PrintLeft(Writer);
|
||||||
|
Writer.Write("\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/LocalName.cs
Normal file
23
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/LocalName.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class LocalName : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode Encoding;
|
||||||
|
private BaseNode Entity;
|
||||||
|
|
||||||
|
public LocalName(BaseNode Encoding, BaseNode Entity) : base(NodeType.LocalName)
|
||||||
|
{
|
||||||
|
this.Encoding = Encoding;
|
||||||
|
this.Entity = Entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Encoding.Print(Writer);
|
||||||
|
Writer.Write("::");
|
||||||
|
Entity.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class MemberExpression : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode LeftNode;
|
||||||
|
private string Kind;
|
||||||
|
private BaseNode RightNode;
|
||||||
|
|
||||||
|
public MemberExpression(BaseNode LeftNode, string Kind, BaseNode RightNode) : base(NodeType.MemberExpression)
|
||||||
|
{
|
||||||
|
this.LeftNode = LeftNode;
|
||||||
|
this.Kind = Kind;
|
||||||
|
this.RightNode = RightNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
LeftNode.Print(Writer);
|
||||||
|
Writer.Write(Kind);
|
||||||
|
RightNode.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NameType.cs
Normal file
29
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NameType.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class NameType : BaseNode
|
||||||
|
{
|
||||||
|
private string NameValue;
|
||||||
|
|
||||||
|
public NameType(string NameValue, NodeType Type) : base(Type)
|
||||||
|
{
|
||||||
|
this.NameValue = NameValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NameType(string NameValue) : base(NodeType.NameType)
|
||||||
|
{
|
||||||
|
this.NameValue = NameValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetName()
|
||||||
|
{
|
||||||
|
return NameValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write(NameValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class NameTypeWithTemplateArguments : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode Prev;
|
||||||
|
private BaseNode TemplateArgument;
|
||||||
|
|
||||||
|
public NameTypeWithTemplateArguments(BaseNode Prev, BaseNode TemplateArgument) : base(NodeType.NameTypeWithTemplateArguments)
|
||||||
|
{
|
||||||
|
this.Prev = Prev;
|
||||||
|
this.TemplateArgument = TemplateArgument;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetName()
|
||||||
|
{
|
||||||
|
return Prev.GetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Prev.Print(Writer);
|
||||||
|
TemplateArgument.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NestedName.cs
Normal file
26
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NestedName.cs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class NestedName : ParentNode
|
||||||
|
{
|
||||||
|
private BaseNode Name;
|
||||||
|
|
||||||
|
public NestedName(BaseNode Name, BaseNode Type) : base(NodeType.NestedName, Type)
|
||||||
|
{
|
||||||
|
this.Name = Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetName()
|
||||||
|
{
|
||||||
|
return Name.GetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Child.Print(Writer);
|
||||||
|
Writer.Write("::");
|
||||||
|
Name.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NewExpression.cs
Normal file
55
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NewExpression.cs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class NewExpression : BaseNode
|
||||||
|
{
|
||||||
|
private NodeArray Expressions;
|
||||||
|
private BaseNode TypeNode;
|
||||||
|
private NodeArray Initializers;
|
||||||
|
|
||||||
|
private bool IsGlobal;
|
||||||
|
private bool IsArrayExpression;
|
||||||
|
|
||||||
|
public NewExpression(NodeArray Expressions, BaseNode TypeNode, NodeArray Initializers, bool IsGlobal, bool IsArrayExpression) : base(NodeType.NewExpression)
|
||||||
|
{
|
||||||
|
this.Expressions = Expressions;
|
||||||
|
this.TypeNode = TypeNode;
|
||||||
|
this.Initializers = Initializers;
|
||||||
|
|
||||||
|
this.IsGlobal = IsGlobal;
|
||||||
|
this.IsArrayExpression = IsArrayExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (IsGlobal)
|
||||||
|
{
|
||||||
|
Writer.Write("::operator ");
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write("new ");
|
||||||
|
|
||||||
|
if (IsArrayExpression)
|
||||||
|
{
|
||||||
|
Writer.Write("[] ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Expressions.Nodes.Count != 0)
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
Expressions.Print(Writer);
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeNode.Print(Writer);
|
||||||
|
|
||||||
|
if (Initializers.Nodes.Count != 0)
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
Initializers.Print(Writer);
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NodeArray.cs
Normal file
31
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NodeArray.cs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class NodeArray : BaseNode
|
||||||
|
{
|
||||||
|
public List<BaseNode> Nodes { get; protected set; }
|
||||||
|
|
||||||
|
public NodeArray(List<BaseNode> Nodes) : base(NodeType.NodeArray)
|
||||||
|
{
|
||||||
|
this.Nodes = Nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NodeArray(List<BaseNode> Nodes, NodeType Type) : base(Type)
|
||||||
|
{
|
||||||
|
this.Nodes = Nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsArray()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write(string.Join<BaseNode>(", ", Nodes.ToArray()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NoexceptSpec.cs
Normal file
16
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/NoexceptSpec.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class NoexceptSpec : ParentNode
|
||||||
|
{
|
||||||
|
public NoexceptSpec(BaseNode Child) : base(NodeType.NoexceptSpec, Child) { }
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("noexcept(");
|
||||||
|
Child.Print(Writer);
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class PackedTemplateParameter : NodeArray
|
||||||
|
{
|
||||||
|
public PackedTemplateParameter(List<BaseNode> Nodes) : base(Nodes, NodeType.PackedTemplateParameter) { }
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
foreach (BaseNode Node in Nodes)
|
||||||
|
{
|
||||||
|
Node.PrintLeft(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintRight(TextWriter Writer)
|
||||||
|
{
|
||||||
|
foreach (BaseNode Node in Nodes)
|
||||||
|
{
|
||||||
|
Node.PrintLeft(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasRightPart()
|
||||||
|
{
|
||||||
|
foreach (BaseNode Node in Nodes)
|
||||||
|
{
|
||||||
|
if (Node.HasRightPart())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class PackedTemplateParameterExpansion : ParentNode
|
||||||
|
{
|
||||||
|
public PackedTemplateParameterExpansion(BaseNode Child) : base(NodeType.PackedTemplateParameterExpansion, Child) {}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (Child is PackedTemplateParameter)
|
||||||
|
{
|
||||||
|
if (((PackedTemplateParameter)Child).Nodes.Count != 0)
|
||||||
|
{
|
||||||
|
Child.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Writer.Write("...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ParentNode.cs
Normal file
17
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ParentNode.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public abstract class ParentNode : BaseNode
|
||||||
|
{
|
||||||
|
public BaseNode Child { get; private set; }
|
||||||
|
|
||||||
|
public ParentNode(NodeType Type, BaseNode Child) : base(Type)
|
||||||
|
{
|
||||||
|
this.Child = Child;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetName()
|
||||||
|
{
|
||||||
|
return Child.GetName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/PointerType.cs
Normal file
45
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/PointerType.cs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class PointerType : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode Child;
|
||||||
|
|
||||||
|
public PointerType(BaseNode Child) : base(NodeType.PointerType)
|
||||||
|
{
|
||||||
|
this.Child = Child;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasRightPart()
|
||||||
|
{
|
||||||
|
return Child.HasRightPart();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Child.PrintLeft(Writer);
|
||||||
|
if (Child.IsArray())
|
||||||
|
{
|
||||||
|
Writer.Write(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Child.IsArray() || Child.HasFunctions())
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write("*");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintRight(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (Child.IsArray() || Child.HasFunctions())
|
||||||
|
{
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
Child.PrintRight(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class PostfixExpression : ParentNode
|
||||||
|
{
|
||||||
|
private string Operator;
|
||||||
|
|
||||||
|
public PostfixExpression(BaseNode Type, string Operator) : base(NodeType.PostfixExpression, Type)
|
||||||
|
{
|
||||||
|
this.Operator = Operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
Child.Print(Writer);
|
||||||
|
Writer.Write(")");
|
||||||
|
Writer.Write(Operator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class PostfixQualifiedType : ParentNode
|
||||||
|
{
|
||||||
|
private string PostfixQualifier;
|
||||||
|
|
||||||
|
public PostfixQualifiedType(string PostfixQualifier, BaseNode Type) : base(NodeType.PostfixQualifiedType, Type)
|
||||||
|
{
|
||||||
|
this.PostfixQualifier = PostfixQualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Child.Print(Writer);
|
||||||
|
Writer.Write(PostfixQualifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class PrefixExpression : ParentNode
|
||||||
|
{
|
||||||
|
private string Prefix;
|
||||||
|
|
||||||
|
public PrefixExpression(string Prefix, BaseNode Child) : base(NodeType.PrefixExpression, Child)
|
||||||
|
{
|
||||||
|
this.Prefix = Prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write(Prefix);
|
||||||
|
Writer.Write("(");
|
||||||
|
Child.Print(Writer);
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/QualifiedName.cs
Normal file
23
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/QualifiedName.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class QualifiedName : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode Qualifier;
|
||||||
|
private BaseNode Name;
|
||||||
|
|
||||||
|
public QualifiedName(BaseNode Qualifier, BaseNode Name) : base(NodeType.QualifiedName)
|
||||||
|
{
|
||||||
|
this.Qualifier = Qualifier;
|
||||||
|
this.Name = Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Qualifier.Print(Writer);
|
||||||
|
Writer.Write("::");
|
||||||
|
Name.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/Qualifier.cs
Normal file
120
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/Qualifier.cs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public enum CV
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Const,
|
||||||
|
Volatile,
|
||||||
|
Restricted = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Reference
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
RValue,
|
||||||
|
LValue
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CVType : ParentNode
|
||||||
|
{
|
||||||
|
public CV Qualifier;
|
||||||
|
|
||||||
|
public CVType(CV Qualifier, BaseNode Child) : base(NodeType.CVQualifierType, Child)
|
||||||
|
{
|
||||||
|
this.Qualifier = Qualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PrintQualifier(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if ((Qualifier & CV.Const) != 0)
|
||||||
|
{
|
||||||
|
Writer.Write(" const");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Qualifier & CV.Volatile) != 0)
|
||||||
|
{
|
||||||
|
Writer.Write(" volatile");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Qualifier & CV.Restricted) != 0)
|
||||||
|
{
|
||||||
|
Writer.Write(" restrict");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (Child != null)
|
||||||
|
{
|
||||||
|
Child.PrintLeft(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintQualifier(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasRightPart()
|
||||||
|
{
|
||||||
|
return Child != null && Child.HasRightPart();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintRight(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (Child != null)
|
||||||
|
{
|
||||||
|
Child.PrintRight(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SimpleReferenceType : ParentNode
|
||||||
|
{
|
||||||
|
public Reference Qualifier;
|
||||||
|
|
||||||
|
public SimpleReferenceType(Reference Qualifier, BaseNode Child) : base(NodeType.SimpleReferenceType, Child)
|
||||||
|
{
|
||||||
|
this.Qualifier = Qualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PrintQualifier(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if ((Qualifier & Reference.LValue) != 0)
|
||||||
|
{
|
||||||
|
Writer.Write("&");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Qualifier & Reference.RValue) != 0)
|
||||||
|
{
|
||||||
|
Writer.Write("&&");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (Child != null)
|
||||||
|
{
|
||||||
|
Child.PrintLeft(Writer);
|
||||||
|
}
|
||||||
|
else if (Qualifier != Reference.None)
|
||||||
|
{
|
||||||
|
Writer.Write(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintQualifier(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasRightPart()
|
||||||
|
{
|
||||||
|
return Child != null && Child.HasRightPart();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintRight(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (Child != null)
|
||||||
|
{
|
||||||
|
Child.PrintRight(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ReferenceType.cs
Normal file
47
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ReferenceType.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class ReferenceType : BaseNode
|
||||||
|
{
|
||||||
|
private string Reference;
|
||||||
|
private BaseNode Child;
|
||||||
|
|
||||||
|
public ReferenceType(string Reference, BaseNode Child) : base(NodeType.ReferenceType)
|
||||||
|
{
|
||||||
|
this.Reference = Reference;
|
||||||
|
this.Child = Child;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasRightPart()
|
||||||
|
{
|
||||||
|
return Child.HasRightPart();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Child.PrintLeft(Writer);
|
||||||
|
|
||||||
|
if (Child.IsArray())
|
||||||
|
{
|
||||||
|
Writer.Write(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Child.IsArray() || Child.HasFunctions())
|
||||||
|
{
|
||||||
|
Writer.Write("(");
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write(Reference);
|
||||||
|
}
|
||||||
|
public override void PrintRight(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (Child.IsArray() || Child.HasFunctions())
|
||||||
|
{
|
||||||
|
Writer.Write(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
Child.PrintRight(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/SpecialName.cs
Normal file
20
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/SpecialName.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class SpecialName : ParentNode
|
||||||
|
{
|
||||||
|
private string SpecialValue;
|
||||||
|
|
||||||
|
public SpecialName(string SpecialValue, BaseNode Type) : base(NodeType.SpecialName, Type)
|
||||||
|
{
|
||||||
|
this.SpecialValue = SpecialValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write(SpecialValue);
|
||||||
|
Child.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class SpecialSubstitution : BaseNode
|
||||||
|
{
|
||||||
|
public enum SpecialType
|
||||||
|
{
|
||||||
|
Allocator,
|
||||||
|
BasicString,
|
||||||
|
String,
|
||||||
|
IStream,
|
||||||
|
OStream,
|
||||||
|
IOStream,
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpecialType SpecialSubstitutionKey;
|
||||||
|
|
||||||
|
public SpecialSubstitution(SpecialType SpecialSubstitutionKey) : base(NodeType.SpecialSubstitution)
|
||||||
|
{
|
||||||
|
this.SpecialSubstitutionKey = SpecialSubstitutionKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetExtended()
|
||||||
|
{
|
||||||
|
Type = NodeType.ExpandedSpecialSubstitution;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetName()
|
||||||
|
{
|
||||||
|
switch (SpecialSubstitutionKey)
|
||||||
|
{
|
||||||
|
case SpecialType.Allocator:
|
||||||
|
return "allocator";
|
||||||
|
case SpecialType.BasicString:
|
||||||
|
return "basic_string";
|
||||||
|
case SpecialType.String:
|
||||||
|
if (Type == NodeType.ExpandedSpecialSubstitution)
|
||||||
|
{
|
||||||
|
return "basic_string";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "string";
|
||||||
|
case SpecialType.IStream:
|
||||||
|
return "istream";
|
||||||
|
case SpecialType.OStream:
|
||||||
|
return "ostream";
|
||||||
|
case SpecialType.IOStream:
|
||||||
|
return "iostream";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetExtendedName()
|
||||||
|
{
|
||||||
|
switch (SpecialSubstitutionKey)
|
||||||
|
{
|
||||||
|
case SpecialType.Allocator:
|
||||||
|
return "std::allocator";
|
||||||
|
case SpecialType.BasicString:
|
||||||
|
return "std::basic_string";
|
||||||
|
case SpecialType.String:
|
||||||
|
return "std::basic_string<char, std::char_traits<char>, std::allocator<char> >";
|
||||||
|
case SpecialType.IStream:
|
||||||
|
return "std::basic_istream<char, std::char_traits<char> >";
|
||||||
|
case SpecialType.OStream:
|
||||||
|
return "std::basic_ostream<char, std::char_traits<char> >";
|
||||||
|
case SpecialType.IOStream:
|
||||||
|
return "std::basic_iostream<char, std::char_traits<char> >";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
if (Type == NodeType.ExpandedSpecialSubstitution)
|
||||||
|
{
|
||||||
|
Writer.Write(GetExtendedName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Writer.Write("std::");
|
||||||
|
Writer.Write(GetName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class StdQualifiedName : ParentNode
|
||||||
|
{
|
||||||
|
public StdQualifiedName(BaseNode Child) : base(NodeType.StdQualifiedName, Child) { }
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("std::");
|
||||||
|
Child.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class TemplateArguments : NodeArray
|
||||||
|
{
|
||||||
|
public TemplateArguments(List<BaseNode> Nodes) : base(Nodes, NodeType.TemplateArguments) { }
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
string Params = string.Join<BaseNode>(", ", Nodes.ToArray());
|
||||||
|
|
||||||
|
Writer.Write("<");
|
||||||
|
|
||||||
|
Writer.Write(Params);
|
||||||
|
|
||||||
|
if (Params.EndsWith(">"))
|
||||||
|
{
|
||||||
|
Writer.Write(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer.Write(">");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ThrowExpression.cs
Normal file
20
Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/ThrowExpression.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||||
|
{
|
||||||
|
public class ThrowExpression : BaseNode
|
||||||
|
{
|
||||||
|
private BaseNode Expression;
|
||||||
|
|
||||||
|
public ThrowExpression(BaseNode Expression) : base(NodeType.ThrowExpression)
|
||||||
|
{
|
||||||
|
this.Expression = Expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrintLeft(TextWriter Writer)
|
||||||
|
{
|
||||||
|
Writer.Write("throw ");
|
||||||
|
Expression.Print(Writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3367
Ryujinx.HLE/HOS/Diagnostics/Demangler/Demangler.cs
Normal file
3367
Ryujinx.HLE/HOS/Diagnostics/Demangler/Demangler.cs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,7 @@ using ChocolArm64.Events;
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using Ryujinx.HLE.Exceptions;
|
using Ryujinx.HLE.Exceptions;
|
||||||
using Ryujinx.HLE.HOS.Diagnostics;
|
using Ryujinx.HLE.HOS.Diagnostics.Demangler;
|
||||||
using Ryujinx.HLE.HOS.Kernel;
|
using Ryujinx.HLE.HOS.Kernel;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv;
|
using Ryujinx.HLE.HOS.Services.Nv;
|
||||||
using Ryujinx.HLE.HOS.SystemState;
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
|
|
Loading…
Reference in a new issue