|
|
@@ -0,0 +1,3367 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.IO;
|
|
|
+using System.Linq;
|
|
|
+using Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast;
|
|
|
+
|
|
|
+namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
|
|
+{
|
|
|
+ class Demangler
|
|
|
+ {
|
|
|
+ private static readonly string BASE_36 = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
|
+ private List<BaseNode> SubstitutionList = new List<BaseNode>();
|
|
|
+ private List<BaseNode> TemplateParamList = new List<BaseNode>();
|
|
|
+
|
|
|
+ private List<ForwardTemplateReference> ForwardTemplateReferenceList = new List<ForwardTemplateReference>();
|
|
|
+
|
|
|
+ public string Mangled { get; private set; }
|
|
|
+
|
|
|
+ private int Position;
|
|
|
+ private int Length;
|
|
|
+
|
|
|
+ private bool CanForwardTemplateReference;
|
|
|
+ private bool CanParseTemplateArgs;
|
|
|
+
|
|
|
+ public Demangler(string Mangled)
|
|
|
+ {
|
|
|
+ this.Mangled = Mangled;
|
|
|
+ Position = 0;
|
|
|
+ Length = Mangled.Length;
|
|
|
+ CanParseTemplateArgs = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool ConsumeIf(string ToConsume)
|
|
|
+ {
|
|
|
+ string MangledPart = Mangled.Substring(Position);
|
|
|
+
|
|
|
+ if (MangledPart.StartsWith(ToConsume))
|
|
|
+ {
|
|
|
+ Position += ToConsume.Length;
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private string PeekString(int Offset = 0, int Length = 1)
|
|
|
+ {
|
|
|
+ if (Position + Offset >= Length)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return Mangled.Substring(Position + Offset, Length);
|
|
|
+ }
|
|
|
+
|
|
|
+ private char Peek(int Offset = 0)
|
|
|
+ {
|
|
|
+ if (Position + Offset >= Length)
|
|
|
+ {
|
|
|
+ return '\0';
|
|
|
+ }
|
|
|
+
|
|
|
+ return Mangled[Position + Offset];
|
|
|
+ }
|
|
|
+
|
|
|
+ private char Consume()
|
|
|
+ {
|
|
|
+ if (Position < Length)
|
|
|
+ {
|
|
|
+ return Mangled[Position++];
|
|
|
+ }
|
|
|
+
|
|
|
+ return '\0';
|
|
|
+ }
|
|
|
+
|
|
|
+ private int Count()
|
|
|
+ {
|
|
|
+ return Length - Position;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static int FromBase36(string Encoded)
|
|
|
+ {
|
|
|
+ char[] ReversedEncoded = Encoded.ToLower().ToCharArray().Reverse().ToArray();
|
|
|
+
|
|
|
+ int Result = 0;
|
|
|
+
|
|
|
+ for (int i = 0; i < ReversedEncoded.Length; i++)
|
|
|
+ {
|
|
|
+ int Value = BASE_36.IndexOf(ReversedEncoded[i]);
|
|
|
+ if (Value == -1)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result += Value * (int)Math.Pow(36, i);
|
|
|
+ }
|
|
|
+
|
|
|
+ return Result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int ParseSeqId()
|
|
|
+ {
|
|
|
+ string Part = Mangled.Substring(Position);
|
|
|
+ int SeqIdLen = 0;
|
|
|
+
|
|
|
+ for (; SeqIdLen < Part.Length; SeqIdLen++)
|
|
|
+ {
|
|
|
+ if (!char.IsLetterOrDigit(Part[SeqIdLen]))
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Position += SeqIdLen;
|
|
|
+
|
|
|
+ return FromBase36(Part.Substring(0, SeqIdLen));
|
|
|
+ }
|
|
|
+
|
|
|
+ // <substitution> ::= S <seq-id> _
|
|
|
+ // ::= S_
|
|
|
+ // ::= St # std::
|
|
|
+ // ::= 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 BaseNode ParseSubstitution()
|
|
|
+ {
|
|
|
+ if (!ConsumeIf("S"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ char SubstitutionSecondChar = Peek();
|
|
|
+ if (char.IsLower(SubstitutionSecondChar))
|
|
|
+ {
|
|
|
+ switch (SubstitutionSecondChar)
|
|
|
+ {
|
|
|
+ case 'a':
|
|
|
+ Position++;
|
|
|
+ return new SpecialSubstitution(SpecialSubstitution.SpecialType.Allocator);
|
|
|
+ case 'b':
|
|
|
+ Position++;
|
|
|
+ return new SpecialSubstitution(SpecialSubstitution.SpecialType.BasicString);
|
|
|
+ case 's':
|
|
|
+ Position++;
|
|
|
+ return new SpecialSubstitution(SpecialSubstitution.SpecialType.String);
|
|
|
+ case 'i':
|
|
|
+ Position++;
|
|
|
+ return new SpecialSubstitution(SpecialSubstitution.SpecialType.IStream);
|
|
|
+ case 'o':
|
|
|
+ Position++;
|
|
|
+ return new SpecialSubstitution(SpecialSubstitution.SpecialType.OStream);
|
|
|
+ case 'd':
|
|
|
+ Position++;
|
|
|
+ return new SpecialSubstitution(SpecialSubstitution.SpecialType.IOStream);
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // ::= S_
|
|
|
+ if (ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ if (SubstitutionList.Count != 0)
|
|
|
+ {
|
|
|
+ return SubstitutionList[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ::= S <seq-id> _
|
|
|
+ int SeqId = ParseSeqId();
|
|
|
+ if (SeqId < 0)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ SeqId++;
|
|
|
+
|
|
|
+ if (!ConsumeIf("_") || SeqId >= SubstitutionList.Count)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return SubstitutionList[SeqId];
|
|
|
+ }
|
|
|
+
|
|
|
+ // NOTE: thoses data aren't used in the output
|
|
|
+ // <call-offset> ::= h <nv-offset> _
|
|
|
+ // ::= v <v-offset> _
|
|
|
+ // <nv-offset> ::= <offset number>
|
|
|
+ // # non-virtual base override
|
|
|
+ // <v-offset> ::= <offset number> _ <virtual offset number>
|
|
|
+ // # virtual base override, with vcall offset
|
|
|
+ private bool ParseCallOffset()
|
|
|
+ {
|
|
|
+ if (ConsumeIf("h"))
|
|
|
+ {
|
|
|
+ return ParseNumber(true).Length == 0 || !ConsumeIf("_");
|
|
|
+ }
|
|
|
+ else if (ConsumeIf("v"))
|
|
|
+ {
|
|
|
+ return ParseNumber(true).Length == 0 || !ConsumeIf("_") || ParseNumber(true).Length == 0 || !ConsumeIf("_");
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // <class-enum-type> ::= <name> # non-dependent type name, dependent type name, or dependent typename-specifier
|
|
|
+ // ::= Ts <name> # dependent elaborated type specifier using 'struct' or 'class'
|
|
|
+ // ::= Tu <name> # dependent elaborated type specifier using 'union'
|
|
|
+ // ::= Te <name> # dependent elaborated type specifier using 'enum'
|
|
|
+ private BaseNode ParseClassEnumType()
|
|
|
+ {
|
|
|
+ string ElaboratedType = null;
|
|
|
+
|
|
|
+ if (ConsumeIf("Ts"))
|
|
|
+ {
|
|
|
+ ElaboratedType = "struct";
|
|
|
+ }
|
|
|
+ else if (ConsumeIf("Tu"))
|
|
|
+ {
|
|
|
+ ElaboratedType = "union";
|
|
|
+ }
|
|
|
+ else if (ConsumeIf("Te"))
|
|
|
+ {
|
|
|
+ ElaboratedType = "enum";
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode Name = ParseName();
|
|
|
+ if (Name == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ElaboratedType == null)
|
|
|
+ {
|
|
|
+ return Name;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new ElaboratedType(ElaboratedType, Name);
|
|
|
+ }
|
|
|
+
|
|
|
+ // <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E
|
|
|
+ // <bare-function-type> ::= <signature type>+
|
|
|
+ // # types are possible return type, then parameter types
|
|
|
+ // <exception-spec> ::= Do # non-throwing exception-specification (e.g., noexcept, throw())
|
|
|
+ // ::= DO <expression> E # computed (instantiation-dependent) noexcept
|
|
|
+ // ::= Dw <type>+ E # dynamic exception specification with instantiation-dependent types
|
|
|
+ private BaseNode ParseFunctionType()
|
|
|
+ {
|
|
|
+ CV CVQualifiers = ParseCVQualifiers();
|
|
|
+
|
|
|
+ BaseNode ExceptionSpec = null;
|
|
|
+
|
|
|
+ if (ConsumeIf("Do"))
|
|
|
+ {
|
|
|
+ ExceptionSpec = new NameType("noexcept");
|
|
|
+ }
|
|
|
+ else if (ConsumeIf("DO"))
|
|
|
+ {
|
|
|
+ BaseNode Expression = ParseExpression();
|
|
|
+ if (Expression == null || !ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ ExceptionSpec = new NoexceptSpec(Expression);
|
|
|
+ }
|
|
|
+ else if (ConsumeIf("Dw"))
|
|
|
+ {
|
|
|
+ List<BaseNode> Types = new List<BaseNode>();
|
|
|
+
|
|
|
+ while (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ BaseNode Type = ParseType();
|
|
|
+ if (Type == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Types.Add(Type);
|
|
|
+ }
|
|
|
+
|
|
|
+ ExceptionSpec = new DynamicExceptionSpec(new NodeArray(Types));
|
|
|
+ }
|
|
|
+
|
|
|
+ // We don't need the transaction
|
|
|
+ ConsumeIf("Dx");
|
|
|
+
|
|
|
+ if (!ConsumeIf("F"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // extern "C"
|
|
|
+ ConsumeIf("Y");
|
|
|
+
|
|
|
+ BaseNode ReturnType = ParseType();
|
|
|
+ if (ReturnType == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Reference ReferenceQualifier = Reference.None;
|
|
|
+ List<BaseNode> Params = new List<BaseNode>();
|
|
|
+
|
|
|
+ while (true)
|
|
|
+ {
|
|
|
+ if (ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ConsumeIf("v"))
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ConsumeIf("RE"))
|
|
|
+ {
|
|
|
+ ReferenceQualifier = Reference.LValue;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ else if (ConsumeIf("OE"))
|
|
|
+ {
|
|
|
+ ReferenceQualifier = Reference.RValue;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode Type = ParseType();
|
|
|
+ if (Type == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Params.Add(Type);
|
|
|
+ }
|
|
|
+
|
|
|
+ return new FunctionType(ReturnType, new NodeArray(Params), new CVType(CVQualifiers, null), new SimpleReferenceType(ReferenceQualifier, null), ExceptionSpec);
|
|
|
+ }
|
|
|
+
|
|
|
+ // <array-type> ::= A <positive dimension number> _ <element type>
|
|
|
+ // ::= A [<dimension expression>] _ <element type>
|
|
|
+ private BaseNode ParseArrayType()
|
|
|
+ {
|
|
|
+ if (!ConsumeIf("A"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode ElementType;
|
|
|
+ if (char.IsDigit(Peek()))
|
|
|
+ {
|
|
|
+ string Dimension = ParseNumber();
|
|
|
+ if (Dimension.Length == 0 || !ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ ElementType = ParseType();
|
|
|
+ if (ElementType == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new ArrayType(ElementType, Dimension);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ BaseNode DimensionExpression = ParseExpression();
|
|
|
+ if (DimensionExpression == null || !ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ ElementType = ParseType();
|
|
|
+ if (ElementType == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new ArrayType(ElementType, DimensionExpression);
|
|
|
+ }
|
|
|
+
|
|
|
+ ElementType = ParseType();
|
|
|
+ if (ElementType == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new ArrayType(ElementType);
|
|
|
+ }
|
|
|
+
|
|
|
+ // <type> ::= <builtin-type>
|
|
|
+ // ::= <qualified-type> (PARTIAL)
|
|
|
+ // ::= <function-type>
|
|
|
+ // ::= <class-enum-type>
|
|
|
+ // ::= <array-type> (TODO)
|
|
|
+ // ::= <pointer-to-member-type> (TODO)
|
|
|
+ // ::= <template-param>
|
|
|
+ // ::= <template-template-param> <template-args>
|
|
|
+ // ::= <decltype>
|
|
|
+ // ::= P <type> # pointer
|
|
|
+ // ::= R <type> # l-value reference
|
|
|
+ // ::= O <type> # r-value reference (C++11)
|
|
|
+ // ::= C <type> # complex pair (C99)
|
|
|
+ // ::= G <type> # imaginary (C99)
|
|
|
+ // ::= <substitution> # See Compression below
|
|
|
+ private BaseNode ParseType(NameParserContext Context = null)
|
|
|
+ {
|
|
|
+ // Temporary context
|
|
|
+ if (Context == null)
|
|
|
+ {
|
|
|
+ Context = new NameParserContext();
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode Result = null;
|
|
|
+ switch (Peek())
|
|
|
+ {
|
|
|
+ case 'r':
|
|
|
+ case 'V':
|
|
|
+ case 'K':
|
|
|
+ int TypePos = 0;
|
|
|
+
|
|
|
+ if (Peek(TypePos) == 'r')
|
|
|
+ {
|
|
|
+ TypePos++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Peek(TypePos) == 'V')
|
|
|
+ {
|
|
|
+ TypePos++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Peek(TypePos) == 'K')
|
|
|
+ {
|
|
|
+ TypePos++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Peek(TypePos) == 'F' || (Peek(TypePos) == 'D' && (Peek(TypePos + 1) == 'o' || Peek(TypePos + 1) == 'O' || Peek(TypePos + 1) == 'w' || Peek(TypePos + 1) == 'x')))
|
|
|
+ {
|
|
|
+ Result = ParseFunctionType();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ CV CV = ParseCVQualifiers();
|
|
|
+
|
|
|
+ Result = ParseType(Context);
|
|
|
+
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new CVType(CV, Result);
|
|
|
+ break;
|
|
|
+ case 'U':
|
|
|
+ // TODO: <extended-qualifier>
|
|
|
+ return null;
|
|
|
+ case 'v':
|
|
|
+ Position++;
|
|
|
+ return new NameType("void");
|
|
|
+ case 'w':
|
|
|
+ Position++;
|
|
|
+ return new NameType("wchar_t");
|
|
|
+ case 'b':
|
|
|
+ Position++;
|
|
|
+ return new NameType("bool");
|
|
|
+ case 'c':
|
|
|
+ Position++;
|
|
|
+ return new NameType("char");
|
|
|
+ case 'a':
|
|
|
+ Position++;
|
|
|
+ return new NameType("signed char");
|
|
|
+ case 'h':
|
|
|
+ Position++;
|
|
|
+ return new NameType("unsigned char");
|
|
|
+ case 's':
|
|
|
+ Position++;
|
|
|
+ return new NameType("short");
|
|
|
+ case 't':
|
|
|
+ Position++;
|
|
|
+ return new NameType("unsigned short");
|
|
|
+ case 'i':
|
|
|
+ Position++;
|
|
|
+ return new NameType("int");
|
|
|
+ case 'j':
|
|
|
+ Position++;
|
|
|
+ return new NameType("unsigned int");
|
|
|
+ case 'l':
|
|
|
+ Position++;
|
|
|
+ return new NameType("long");
|
|
|
+ case 'm':
|
|
|
+ Position++;
|
|
|
+ return new NameType("unsigned long");
|
|
|
+ case 'x':
|
|
|
+ Position++;
|
|
|
+ return new NameType("long long");
|
|
|
+ case 'y':
|
|
|
+ Position++;
|
|
|
+ return new NameType("unsigned long long");
|
|
|
+ case 'n':
|
|
|
+ Position++;
|
|
|
+ return new NameType("__int128");
|
|
|
+ case 'o':
|
|
|
+ Position++;
|
|
|
+ return new NameType("unsigned __int128");
|
|
|
+ case 'f':
|
|
|
+ Position++;
|
|
|
+ return new NameType("float");
|
|
|
+ case 'd':
|
|
|
+ Position++;
|
|
|
+ return new NameType("double");
|
|
|
+ case 'e':
|
|
|
+ Position++;
|
|
|
+ return new NameType("long double");
|
|
|
+ case 'g':
|
|
|
+ Position++;
|
|
|
+ return new NameType("__float128");
|
|
|
+ case 'z':
|
|
|
+ Position++;
|
|
|
+ return new NameType("...");
|
|
|
+ case 'u':
|
|
|
+ Position++;
|
|
|
+ return ParseSourceName();
|
|
|
+ case 'D':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'd':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("decimal64");
|
|
|
+ case 'e':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("decimal128");
|
|
|
+ case 'f':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("decimal32");
|
|
|
+ case 'h':
|
|
|
+ Position += 2;
|
|
|
+ // FIXME: GNU c++flit returns this but that is not what is supposed to be returned.
|
|
|
+ return new NameType("half");
|
|
|
+ //return new NameType("decimal16");
|
|
|
+ case 'i':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("char32_t");
|
|
|
+ case 's':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("char16_t");
|
|
|
+ case 'a':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("decltype(auto)");
|
|
|
+ case 'n':
|
|
|
+ Position += 2;
|
|
|
+ // FIXME: GNU c++flit returns this but that is not what is supposed to be returned.
|
|
|
+ return new NameType("decltype(nullptr)");
|
|
|
+ //return new NameType("std::nullptr_t");
|
|
|
+ case 't':
|
|
|
+ case 'T':
|
|
|
+ Position += 2;
|
|
|
+ Result = ParseDecltype();
|
|
|
+ break;
|
|
|
+ case 'o':
|
|
|
+ case 'O':
|
|
|
+ case 'w':
|
|
|
+ case 'x':
|
|
|
+ Result = ParseFunctionType();
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'F':
|
|
|
+ Result = ParseFunctionType();
|
|
|
+ break;
|
|
|
+ case 'A':
|
|
|
+ return ParseArrayType();
|
|
|
+ case 'M':
|
|
|
+ // TODO: <pointer-to-member-type>
|
|
|
+ Position++;
|
|
|
+ return null;
|
|
|
+ case 'T':
|
|
|
+ // might just be a class enum type
|
|
|
+ if (Peek(1) == 's' || Peek(1) == 'u' || Peek(1) == 'e')
|
|
|
+ {
|
|
|
+ Result = ParseClassEnumType();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = ParseTemplateParam();
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (CanParseTemplateArgs && Peek() == 'I')
|
|
|
+ {
|
|
|
+ BaseNode TemplateArguments = ParseTemplateArguments();
|
|
|
+ if (TemplateArguments == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new NameTypeWithTemplateArguments(Result, TemplateArguments);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'P':
|
|
|
+ Position++;
|
|
|
+ Result = ParseType(Context);
|
|
|
+
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new PointerType(Result);
|
|
|
+ break;
|
|
|
+ case 'R':
|
|
|
+ Position++;
|
|
|
+ Result = ParseType(Context);
|
|
|
+
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new ReferenceType("&", Result);
|
|
|
+ break;
|
|
|
+ case 'O':
|
|
|
+ Position++;
|
|
|
+ Result = ParseType(Context);
|
|
|
+
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new ReferenceType("&&", Result);
|
|
|
+ break;
|
|
|
+ case 'C':
|
|
|
+ Position++;
|
|
|
+ Result = ParseType(Context);
|
|
|
+
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new PostfixQualifiedType(" complex", Result);
|
|
|
+ break;
|
|
|
+ case 'G':
|
|
|
+ Position++;
|
|
|
+ Result = ParseType(Context);
|
|
|
+
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new PostfixQualifiedType(" imaginary", Result);
|
|
|
+ break;
|
|
|
+ case 'S':
|
|
|
+ if (Peek(1) != 't')
|
|
|
+ {
|
|
|
+ BaseNode Substitution = ParseSubstitution();
|
|
|
+ if (Substitution == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (CanParseTemplateArgs && Peek() == 'I')
|
|
|
+ {
|
|
|
+ BaseNode TemplateArgument = ParseTemplateArgument();
|
|
|
+ if (TemplateArgument == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new NameTypeWithTemplateArguments(Substitution, TemplateArgument);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return Substitution;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Result = ParseClassEnumType();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ Result = ParseClassEnumType();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (Result != null)
|
|
|
+ {
|
|
|
+ SubstitutionList.Add(Result);
|
|
|
+ }
|
|
|
+
|
|
|
+ return Result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // <special-name> ::= TV <type> # virtual table
|
|
|
+ // ::= TT <type> # VTT structure (construction vtable index)
|
|
|
+ // ::= TI <type> # typeinfo structure
|
|
|
+ // ::= TS <type> # typeinfo name (null-terminated byte string)
|
|
|
+ // ::= Tc <call-offset> <call-offset> <base encoding>
|
|
|
+ // ::= TW <object name> # Thread-local wrapper
|
|
|
+ // ::= TH <object name> # Thread-local initialization
|
|
|
+ // ::= T <call-offset> <base encoding>
|
|
|
+ // # base is the nominal target function of thunk
|
|
|
+ // ::= GV <object name> # Guard variable for one-time initialization
|
|
|
+ private BaseNode ParseSpecialName(NameParserContext Context = null)
|
|
|
+ {
|
|
|
+ if (Peek() != 'T')
|
|
|
+ {
|
|
|
+ if (ConsumeIf("GV"))
|
|
|
+ {
|
|
|
+ BaseNode Name = ParseName();
|
|
|
+ if (Name == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new SpecialName("guard variable for ", Name);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode Node;
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ // ::= TV <type> # virtual table
|
|
|
+ case 'V':
|
|
|
+ Position += 2;
|
|
|
+ Node = ParseType(Context);
|
|
|
+ if (Node == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new SpecialName("vtable for ", Node);
|
|
|
+ // ::= TT <type> # VTT structure (construction vtable index)
|
|
|
+ case 'T':
|
|
|
+ Position += 2;
|
|
|
+ Node = ParseType(Context);
|
|
|
+ if (Node == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new SpecialName("VTT for ", Node);
|
|
|
+ // ::= TI <type> # typeinfo structure
|
|
|
+ case 'I':
|
|
|
+ Position += 2;
|
|
|
+ Node = ParseType(Context);
|
|
|
+ if (Node == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new SpecialName("typeinfo for ", Node);
|
|
|
+ // ::= TS <type> # typeinfo name (null-terminated byte string)
|
|
|
+ case 'S':
|
|
|
+ Position += 2;
|
|
|
+ Node = ParseType(Context);
|
|
|
+ if (Node == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new SpecialName("typeinfo name for ", Node);
|
|
|
+ // ::= Tc <call-offset> <call-offset> <base encoding>
|
|
|
+ case 'c':
|
|
|
+ Position += 2;
|
|
|
+ if (ParseCallOffset() || ParseCallOffset())
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Node = ParseEncoding();
|
|
|
+ if (Node == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new SpecialName("covariant return thunk to ", Node);
|
|
|
+ // extension ::= TC <first type> <number> _ <second type>
|
|
|
+ case 'C':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode FirstType = ParseType();
|
|
|
+ if (FirstType == null || ParseNumber(true).Length == 0 || !ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode SecondType = ParseType();
|
|
|
+
|
|
|
+ return new CtorVtableSpecialName(SecondType, FirstType);
|
|
|
+ // ::= TH <object name> # Thread-local initialization
|
|
|
+ case 'H':
|
|
|
+ Position += 2;
|
|
|
+ Node = ParseName();
|
|
|
+ if (Node == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new SpecialName("thread-local initialization routine for ", Node);
|
|
|
+ // ::= TW <object name> # Thread-local wrapper
|
|
|
+ case 'W':
|
|
|
+ Position += 2;
|
|
|
+ Node = ParseName();
|
|
|
+ if (Node == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new SpecialName("thread-local wrapper routine for ", Node);
|
|
|
+ default:
|
|
|
+ Position++;
|
|
|
+ bool IsVirtual = Peek() == 'v';
|
|
|
+ if (ParseCallOffset())
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Node = ParseEncoding();
|
|
|
+ if (Node == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (IsVirtual)
|
|
|
+ {
|
|
|
+ return new SpecialName("virtual thunk to ", Node);
|
|
|
+ }
|
|
|
+
|
|
|
+ return new SpecialName("non-virtual thunk to ", Node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const
|
|
|
+ private CV ParseCVQualifiers()
|
|
|
+ {
|
|
|
+ CV Qualifiers = CV.None;
|
|
|
+
|
|
|
+ if (ConsumeIf("r"))
|
|
|
+ {
|
|
|
+ Qualifiers |= CV.Restricted;
|
|
|
+ }
|
|
|
+ if (ConsumeIf("V"))
|
|
|
+ {
|
|
|
+ Qualifiers |= CV.Volatile;
|
|
|
+ }
|
|
|
+ if (ConsumeIf("K"))
|
|
|
+ {
|
|
|
+ Qualifiers |= CV.Const;
|
|
|
+ }
|
|
|
+
|
|
|
+ return Qualifiers;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // <ref-qualifier> ::= R # & ref-qualifier
|
|
|
+ // <ref-qualifier> ::= O # && ref-qualifier
|
|
|
+ private SimpleReferenceType ParseRefQualifiers()
|
|
|
+ {
|
|
|
+ Reference Result = Reference.None;
|
|
|
+ if (ConsumeIf("O"))
|
|
|
+ {
|
|
|
+ Result = Reference.RValue;
|
|
|
+ }
|
|
|
+ else if (ConsumeIf("R"))
|
|
|
+ {
|
|
|
+ Result = Reference.LValue;
|
|
|
+ }
|
|
|
+ return new SimpleReferenceType(Result, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ private BaseNode CreateNameNode(BaseNode Prev, BaseNode Name, NameParserContext Context)
|
|
|
+ {
|
|
|
+ BaseNode Result = Name;
|
|
|
+ if (Prev != null)
|
|
|
+ {
|
|
|
+ Result = new NestedName(Name, Prev);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Context != null)
|
|
|
+ {
|
|
|
+ Context.FinishWithTemplateArguments = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return Result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int ParsePositiveNumber()
|
|
|
+ {
|
|
|
+ string Part = Mangled.Substring(Position);
|
|
|
+ int NumberLength = 0;
|
|
|
+
|
|
|
+ for (; NumberLength < Part.Length; NumberLength++)
|
|
|
+ {
|
|
|
+ if (!char.IsDigit(Part[NumberLength]))
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Position += NumberLength;
|
|
|
+
|
|
|
+ if (NumberLength == 0)
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return int.Parse(Part.Substring(0, NumberLength));
|
|
|
+ }
|
|
|
+
|
|
|
+ private string ParseNumber(bool IsSigned = false)
|
|
|
+ {
|
|
|
+ if (IsSigned)
|
|
|
+ {
|
|
|
+ ConsumeIf("n");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Count() == 0 || !char.IsDigit(Mangled[Position]))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ string Part = Mangled.Substring(Position);
|
|
|
+ int NumberLength = 0;
|
|
|
+
|
|
|
+ for (; NumberLength < Part.Length; NumberLength++)
|
|
|
+ {
|
|
|
+ if (!char.IsDigit(Part[NumberLength]))
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Position += NumberLength;
|
|
|
+
|
|
|
+ return Part.Substring(0, NumberLength);
|
|
|
+ }
|
|
|
+
|
|
|
+ // <source-name> ::= <positive length number> <identifier>
|
|
|
+ private BaseNode ParseSourceName()
|
|
|
+ {
|
|
|
+ int Length = ParsePositiveNumber();
|
|
|
+ if (Count() < Length || Length <= 0)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ string Name = Mangled.Substring(Position, Length);
|
|
|
+ Position += Length;
|
|
|
+ if (Name.StartsWith("_GLOBAL__N"))
|
|
|
+ {
|
|
|
+ return new NameType("(anonymous namespace)");
|
|
|
+ }
|
|
|
+
|
|
|
+ return new NameType(Name);
|
|
|
+ }
|
|
|
+
|
|
|
+ // <operator-name> ::= nw # new
|
|
|
+ // ::= na # new[]
|
|
|
+ // ::= dl # delete
|
|
|
+ // ::= da # delete[]
|
|
|
+ // ::= ps # + (unary)
|
|
|
+ // ::= ng # - (unary)
|
|
|
+ // ::= ad # & (unary)
|
|
|
+ // ::= de # * (unary)
|
|
|
+ // ::= co # ~
|
|
|
+ // ::= pl # +
|
|
|
+ // ::= mi # -
|
|
|
+ // ::= ml # *
|
|
|
+ // ::= dv # /
|
|
|
+ // ::= rm # %
|
|
|
+ // ::= an # &
|
|
|
+ // ::= or # |
|
|
|
+ // ::= eo # ^
|
|
|
+ // ::= aS # =
|
|
|
+ // ::= pL # +=
|
|
|
+ // ::= mI # -=
|
|
|
+ // ::= mL # *=
|
|
|
+ // ::= dV # /=
|
|
|
+ // ::= rM # %=
|
|
|
+ // ::= aN # &=
|
|
|
+ // ::= oR # |=
|
|
|
+ // ::= eO # ^=
|
|
|
+ // ::= ls # <<
|
|
|
+ // ::= rs # >>
|
|
|
+ // ::= lS # <<=
|
|
|
+ // ::= rS # >>=
|
|
|
+ // ::= eq # ==
|
|
|
+ // ::= ne # !=
|
|
|
+ // ::= lt # <
|
|
|
+ // ::= gt # >
|
|
|
+ // ::= le # <=
|
|
|
+ // ::= ge # >=
|
|
|
+ // ::= ss # <=>
|
|
|
+ // ::= nt # !
|
|
|
+ // ::= aa # &&
|
|
|
+ // ::= oo # ||
|
|
|
+ // ::= pp # ++ (postfix in <expression> context)
|
|
|
+ // ::= mm # -- (postfix in <expression> context)
|
|
|
+ // ::= cm # ,
|
|
|
+ // ::= pm # ->*
|
|
|
+ // ::= pt # ->
|
|
|
+ // ::= cl # ()
|
|
|
+ // ::= ix # []
|
|
|
+ // ::= qu # ?
|
|
|
+ // ::= cv <type> # (cast) (TODO)
|
|
|
+ // ::= li <source-name> # operator ""
|
|
|
+ // ::= v <digit> <source-name> # vendor extended operator (TODO)
|
|
|
+ private BaseNode ParseOperatorName(NameParserContext Context)
|
|
|
+ {
|
|
|
+ switch (Peek())
|
|
|
+ {
|
|
|
+ case 'a':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'a':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator&&");
|
|
|
+ case 'd':
|
|
|
+ case 'n':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator&");
|
|
|
+ case 'N':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator&=");
|
|
|
+ case 'S':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator=");
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ case 'c':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'l':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator()");
|
|
|
+ case 'm':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator,");
|
|
|
+ case 'o':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator~");
|
|
|
+ case 'v':
|
|
|
+ Position += 2;
|
|
|
+
|
|
|
+ bool CanParseTemplateArgsBackup = CanParseTemplateArgs;
|
|
|
+ bool CanForwardTemplateReferenceBackup = CanForwardTemplateReference;
|
|
|
+
|
|
|
+ CanParseTemplateArgs = false;
|
|
|
+ CanForwardTemplateReference = CanForwardTemplateReferenceBackup || Context != null;
|
|
|
+
|
|
|
+ BaseNode Type = ParseType();
|
|
|
+
|
|
|
+ CanParseTemplateArgs = CanParseTemplateArgsBackup;
|
|
|
+ CanForwardTemplateReference = CanForwardTemplateReferenceBackup;
|
|
|
+
|
|
|
+ if (Type == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Context != null)
|
|
|
+ {
|
|
|
+ Context.CtorDtorConversion = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new ConversionOperatorType(Type);
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ case 'd':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'a':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator delete[]");
|
|
|
+ case 'e':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator*");
|
|
|
+ case 'l':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator delete");
|
|
|
+ case 'v':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator/");
|
|
|
+ case 'V':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator/=");
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ case 'e':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'o':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator^");
|
|
|
+ case 'O':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator^=");
|
|
|
+ case 'q':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator==");
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ case 'g':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'e':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator>=");
|
|
|
+ case 't':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator>");
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ case 'i':
|
|
|
+ if (Peek(1) == 'x')
|
|
|
+ {
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator[]");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'l':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'e':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator<=");
|
|
|
+ case 'i':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode SourceName = ParseSourceName();
|
|
|
+ if (SourceName == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new LiteralOperator(SourceName);
|
|
|
+ case 's':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator<<");
|
|
|
+ case 'S':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator<<=");
|
|
|
+ case 't':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator<");
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ case 'm':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'i':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator-");
|
|
|
+ case 'I':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator-=");
|
|
|
+ case 'l':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator*");
|
|
|
+ case 'L':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator*=");
|
|
|
+ case 'm':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator--");
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ case 'n':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'a':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator new[]");
|
|
|
+ case 'e':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator!=");
|
|
|
+ case 'g':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator-");
|
|
|
+ case 't':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator!");
|
|
|
+ case 'w':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator new");
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ case 'o':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'o':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator||");
|
|
|
+ case 'r':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator|");
|
|
|
+ case 'R':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator|=");
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ case 'p':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'm':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator->*");
|
|
|
+ case 's':
|
|
|
+ case 'l':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator+");
|
|
|
+ case 'L':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator+=");
|
|
|
+ case 'p':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator++");
|
|
|
+ case 't':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator->");
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ case 'q':
|
|
|
+ if (Peek(1) == 'u')
|
|
|
+ {
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator?");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'r':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'm':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator%");
|
|
|
+ case 'M':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator%=");
|
|
|
+ case 's':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator>>");
|
|
|
+ case 'S':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator>>=");
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ case 's':
|
|
|
+ if (Peek(1) == 's')
|
|
|
+ {
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("operator<=>");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'v':
|
|
|
+ // TODO: ::= v <digit> <source-name> # vendor extended operator
|
|
|
+ return null;
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // <unqualified-name> ::= <operator-name> [<abi-tags> (TODO)]
|
|
|
+ // ::= <ctor-dtor-name> (TODO)
|
|
|
+ // ::= <source-name>
|
|
|
+ // ::= <unnamed-type-name> (TODO)
|
|
|
+ // ::= DC <source-name>+ E # structured binding declaration (TODO)
|
|
|
+ private BaseNode ParseUnqualifiedName(NameParserContext Context)
|
|
|
+ {
|
|
|
+ BaseNode Result = null;
|
|
|
+ char C = Peek();
|
|
|
+ if (C == 'U')
|
|
|
+ {
|
|
|
+ // TODO: Unnamed Type Name
|
|
|
+ // throw new Exception("Unnamed Type Name not implemented");
|
|
|
+ }
|
|
|
+ else if (char.IsDigit(C))
|
|
|
+ {
|
|
|
+ Result = ParseSourceName();
|
|
|
+ }
|
|
|
+ else if (ConsumeIf("DC"))
|
|
|
+ {
|
|
|
+ // TODO: Structured Binding Declaration
|
|
|
+ // throw new Exception("Structured Binding Declaration not implemented");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Result = ParseOperatorName(Context);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Result != null)
|
|
|
+ {
|
|
|
+ // TODO: ABI Tags
|
|
|
+ //throw new Exception("ABI Tags not implemented");
|
|
|
+ }
|
|
|
+ return Result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // <ctor-dtor-name> ::= C1 # complete object constructor
|
|
|
+ // ::= C2 # base object constructor
|
|
|
+ // ::= C3 # complete object allocating constructor
|
|
|
+ // ::= D0 # deleting destructor
|
|
|
+ // ::= D1 # complete object destructor
|
|
|
+ // ::= D2 # base object destructor
|
|
|
+ private BaseNode ParseCtorDtorName(NameParserContext Context, BaseNode Prev)
|
|
|
+ {
|
|
|
+ if (Prev.Type == NodeType.SpecialSubstitution && Prev is SpecialSubstitution)
|
|
|
+ {
|
|
|
+ ((SpecialSubstitution)Prev).SetExtended();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ConsumeIf("C"))
|
|
|
+ {
|
|
|
+ bool IsInherited = ConsumeIf("I");
|
|
|
+
|
|
|
+ char CtorDtorType = Peek();
|
|
|
+ if (CtorDtorType != '1' && CtorDtorType != '2' && CtorDtorType != '3')
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Position++;
|
|
|
+
|
|
|
+ if (Context != null)
|
|
|
+ {
|
|
|
+ Context.CtorDtorConversion = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (IsInherited && ParseName(Context) == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new CtorDtorNameType(Prev, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ConsumeIf("D"))
|
|
|
+ {
|
|
|
+ char C = Peek();
|
|
|
+ if (C != '0' && C != '1' && C != '2')
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Position++;
|
|
|
+
|
|
|
+ if (Context != null)
|
|
|
+ {
|
|
|
+ Context.CtorDtorConversion = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new CtorDtorNameType(Prev, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter
|
|
|
+ // ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
|
|
|
+ // ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter
|
|
|
+ // ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
|
|
|
+ private BaseNode ParseFunctionParameter()
|
|
|
+ {
|
|
|
+ if (ConsumeIf("fp"))
|
|
|
+ {
|
|
|
+ // ignored
|
|
|
+ ParseCVQualifiers();
|
|
|
+
|
|
|
+ if (!ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new FunctionParameter(ParseNumber());
|
|
|
+ }
|
|
|
+ else if (ConsumeIf("fL"))
|
|
|
+ {
|
|
|
+ string L1Number = ParseNumber();
|
|
|
+ if (L1Number == null || L1Number.Length == 0)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ConsumeIf("p"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ignored
|
|
|
+ ParseCVQualifiers();
|
|
|
+
|
|
|
+ if (!ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new FunctionParameter(ParseNumber());
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // <fold-expr> ::= fL <binary-operator-name> <expression> <expression>
|
|
|
+ // ::= fR <binary-operator-name> <expression> <expression>
|
|
|
+ // ::= fl <binary-operator-name> <expression>
|
|
|
+ // ::= fr <binary-operator-name> <expression>
|
|
|
+ private BaseNode ParseFoldExpression()
|
|
|
+ {
|
|
|
+ if (!ConsumeIf("f"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ char FoldKind = Peek();
|
|
|
+ bool HasInitializer = FoldKind == 'L' || FoldKind == 'R';
|
|
|
+ bool IsLeftFold = FoldKind == 'l' || FoldKind == 'L';
|
|
|
+
|
|
|
+ if (!IsLeftFold && !(FoldKind == 'r' || FoldKind == 'R'))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Position++;
|
|
|
+
|
|
|
+ string OperatorName = null;
|
|
|
+
|
|
|
+ switch (PeekString(0, 2))
|
|
|
+ {
|
|
|
+ case "aa":
|
|
|
+ OperatorName = "&&";
|
|
|
+ break;
|
|
|
+ case "an":
|
|
|
+ OperatorName = "&";
|
|
|
+ break;
|
|
|
+ case "aN":
|
|
|
+ OperatorName = "&=";
|
|
|
+ break;
|
|
|
+ case "aS":
|
|
|
+ OperatorName = "=";
|
|
|
+ break;
|
|
|
+ case "cm":
|
|
|
+ OperatorName = ",";
|
|
|
+ break;
|
|
|
+ case "ds":
|
|
|
+ OperatorName = ".*";
|
|
|
+ break;
|
|
|
+ case "dv":
|
|
|
+ OperatorName = "/";
|
|
|
+ break;
|
|
|
+ case "dV":
|
|
|
+ OperatorName = "/=";
|
|
|
+ break;
|
|
|
+ case "eo":
|
|
|
+ OperatorName = "^";
|
|
|
+ break;
|
|
|
+ case "eO":
|
|
|
+ OperatorName = "^=";
|
|
|
+ break;
|
|
|
+ case "eq":
|
|
|
+ OperatorName = "==";
|
|
|
+ break;
|
|
|
+ case "ge":
|
|
|
+ OperatorName = ">=";
|
|
|
+ break;
|
|
|
+ case "gt":
|
|
|
+ OperatorName = ">";
|
|
|
+ break;
|
|
|
+ case "le":
|
|
|
+ OperatorName = "<=";
|
|
|
+ break;
|
|
|
+ case "ls":
|
|
|
+ OperatorName = "<<";
|
|
|
+ break;
|
|
|
+ case "lS":
|
|
|
+ OperatorName = "<<=";
|
|
|
+ break;
|
|
|
+ case "lt":
|
|
|
+ OperatorName = "<";
|
|
|
+ break;
|
|
|
+ case "mi":
|
|
|
+ OperatorName = "-";
|
|
|
+ break;
|
|
|
+ case "mI":
|
|
|
+ OperatorName = "-=";
|
|
|
+ break;
|
|
|
+ case "ml":
|
|
|
+ OperatorName = "*";
|
|
|
+ break;
|
|
|
+ case "mL":
|
|
|
+ OperatorName = "*=";
|
|
|
+ break;
|
|
|
+ case "ne":
|
|
|
+ OperatorName = "!=";
|
|
|
+ break;
|
|
|
+ case "oo":
|
|
|
+ OperatorName = "||";
|
|
|
+ break;
|
|
|
+ case "or":
|
|
|
+ OperatorName = "|";
|
|
|
+ break;
|
|
|
+ case "oR":
|
|
|
+ OperatorName = "|=";
|
|
|
+ break;
|
|
|
+ case "pl":
|
|
|
+ OperatorName = "+";
|
|
|
+ break;
|
|
|
+ case "pL":
|
|
|
+ OperatorName = "+=";
|
|
|
+ break;
|
|
|
+ case "rm":
|
|
|
+ OperatorName = "%";
|
|
|
+ break;
|
|
|
+ case "rM":
|
|
|
+ OperatorName = "%=";
|
|
|
+ break;
|
|
|
+ case "rs":
|
|
|
+ OperatorName = ">>";
|
|
|
+ break;
|
|
|
+ case "rS":
|
|
|
+ OperatorName = ">>=";
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Position += 2;
|
|
|
+
|
|
|
+ BaseNode Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode Initializer = null;
|
|
|
+
|
|
|
+ if (HasInitializer)
|
|
|
+ {
|
|
|
+ Initializer = ParseExpression();
|
|
|
+ if (Initializer == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (IsLeftFold && Initializer != null)
|
|
|
+ {
|
|
|
+ BaseNode Temp = Expression;
|
|
|
+ Expression = Initializer;
|
|
|
+ Initializer = Temp;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new FoldExpression(IsLeftFold, OperatorName, new PackedTemplateParameterExpansion(Expression), Initializer);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // ::= cv <type> <expression> # type (expression), conversion with one argument
|
|
|
+ // ::= cv <type> _ <expression>* E # type (expr-list), conversion with other than one argument
|
|
|
+ private BaseNode ParseConversionExpression()
|
|
|
+ {
|
|
|
+ if (!ConsumeIf("cv"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool CanParseTemplateArgsBackup = CanParseTemplateArgs;
|
|
|
+ CanParseTemplateArgs = false;
|
|
|
+ BaseNode Type = ParseType();
|
|
|
+ CanParseTemplateArgs = CanParseTemplateArgsBackup;
|
|
|
+
|
|
|
+ if (Type == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<BaseNode> Expressions = new List<BaseNode>();
|
|
|
+ if (ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ while (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ BaseNode Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Expressions.Add(Expression);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ BaseNode Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Expressions.Add(Expression);
|
|
|
+ }
|
|
|
+
|
|
|
+ return new ConversionExpression(Type, new NodeArray(Expressions));
|
|
|
+ }
|
|
|
+
|
|
|
+ private BaseNode ParseBinaryExpression(string Name)
|
|
|
+ {
|
|
|
+ BaseNode LeftPart = ParseExpression();
|
|
|
+ if (LeftPart == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode RightPart = ParseExpression();
|
|
|
+ if (RightPart == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new BinaryExpression(LeftPart, Name, RightPart);
|
|
|
+ }
|
|
|
+
|
|
|
+ private BaseNode ParsePrefixExpression(string Name)
|
|
|
+ {
|
|
|
+ BaseNode Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new PrefixExpression(Name, Expression);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // <braced-expression> ::= <expression>
|
|
|
+ // ::= di <field source-name> <braced-expression> # .name = expr
|
|
|
+ // ::= dx <index expression> <braced-expression> # [expr] = expr
|
|
|
+ // ::= dX <range begin expression> <range end expression> <braced-expression>
|
|
|
+ // # [expr ... expr] = expr
|
|
|
+ private BaseNode ParseBracedExpression()
|
|
|
+ {
|
|
|
+ if (Peek() == 'd')
|
|
|
+ {
|
|
|
+ BaseNode BracedExpressionNode;
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'i':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode Field = ParseSourceName();
|
|
|
+ if (Field == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BracedExpressionNode = ParseBracedExpression();
|
|
|
+ if (BracedExpressionNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new BracedExpression(Field, BracedExpressionNode, false);
|
|
|
+ case 'x':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode Index = ParseExpression();
|
|
|
+ if (Index == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BracedExpressionNode = ParseBracedExpression();
|
|
|
+ if (BracedExpressionNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new BracedExpression(Index, BracedExpressionNode, true);
|
|
|
+ case 'X':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode RangeBeginExpression = ParseExpression();
|
|
|
+ if (RangeBeginExpression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode RangeEndExpression = ParseExpression();
|
|
|
+ if (RangeEndExpression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BracedExpressionNode = ParseBracedExpression();
|
|
|
+ if (BracedExpressionNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new BracedRangeExpression(RangeBeginExpression, RangeEndExpression, BracedExpressionNode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ParseExpression();
|
|
|
+ }
|
|
|
+
|
|
|
+ // ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
|
|
|
+ // ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
|
|
|
+ // ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
|
|
|
+ // ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
|
|
|
+ //
|
|
|
+ // <initializer> ::= pi <expression>* E # parenthesized initialization
|
|
|
+ private BaseNode ParseNewExpression()
|
|
|
+ {
|
|
|
+ bool IsGlobal = ConsumeIf("gs");
|
|
|
+ bool IsArray = Peek(1) == 'a';
|
|
|
+
|
|
|
+ if (!ConsumeIf("nw") || !ConsumeIf("na"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<BaseNode> Expressions = new List<BaseNode>();
|
|
|
+ List<BaseNode> Initializers = new List<BaseNode>();
|
|
|
+
|
|
|
+ while (!ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ BaseNode Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Expressions.Add(Expression);
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode TypeNode = ParseType();
|
|
|
+ if (TypeNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ConsumeIf("pi"))
|
|
|
+ {
|
|
|
+ while (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ BaseNode Initializer = ParseExpression();
|
|
|
+ if (Initializer == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Initializers.Add(Initializer);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new NewExpression(new NodeArray(Expressions), TypeNode, new NodeArray(Initializers), IsGlobal, IsArray);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // <expression> ::= <unary operator-name> <expression>
|
|
|
+ // ::= <binary operator-name> <expression> <expression>
|
|
|
+ // ::= <ternary operator-name> <expression> <expression> <expression>
|
|
|
+ // ::= pp_ <expression> # prefix ++
|
|
|
+ // ::= mm_ <expression> # prefix --
|
|
|
+ // ::= cl <expression>+ E # expression (expr-list), call
|
|
|
+ // ::= cv <type> <expression> # type (expression), conversion with one argument
|
|
|
+ // ::= cv <type> _ <expression>* E # type (expr-list), conversion with other than one argument
|
|
|
+ // ::= tl <type> <braced-expression>* E # type {expr-list}, conversion with braced-init-list argument
|
|
|
+ // ::= il <braced-expression>* E # {expr-list}, braced-init-list in any other context
|
|
|
+ // ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
|
|
|
+ // ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
|
|
|
+ // ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
|
|
|
+ // ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
|
|
|
+ // ::= [gs] dl <expression> # delete expression
|
|
|
+ // ::= [gs] da <expression> # delete[] expression
|
|
|
+ // ::= dc <type> <expression> # dynamic_cast<type> (expression)
|
|
|
+ // ::= sc <type> <expression> # static_cast<type> (expression)
|
|
|
+ // ::= cc <type> <expression> # const_cast<type> (expression)
|
|
|
+ // ::= rc <type> <expression> # reinterpret_cast<type> (expression)
|
|
|
+ // ::= ti <type> # typeid (type)
|
|
|
+ // ::= te <expression> # typeid (expression)
|
|
|
+ // ::= st <type> # sizeof (type)
|
|
|
+ // ::= sz <expression> # sizeof (expression)
|
|
|
+ // ::= at <type> # alignof (type)
|
|
|
+ // ::= az <expression> # alignof (expression)
|
|
|
+ // ::= nx <expression> # noexcept (expression)
|
|
|
+ // ::= <template-param>
|
|
|
+ // ::= <function-param>
|
|
|
+ // ::= dt <expression> <unresolved-name> # expr.name
|
|
|
+ // ::= pt <expression> <unresolved-name> # expr->name
|
|
|
+ // ::= ds <expression> <expression> # expr.*expr
|
|
|
+ // ::= sZ <template-param> # sizeof...(T), size of a template parameter pack
|
|
|
+ // ::= sZ <function-param> # sizeof...(parameter), size of a function parameter pack
|
|
|
+ // ::= sP <template-arg>* E # sizeof...(T), size of a captured template parameter pack from an alias template
|
|
|
+ // ::= sp <expression> # expression..., pack expansion
|
|
|
+ // ::= tw <expression> # throw expression
|
|
|
+ // ::= tr # throw with no operand (rethrow)
|
|
|
+ // ::= <unresolved-name> # f(p), N::f(p), ::f(p),
|
|
|
+ // # freestanding dependent name (e.g., T::x),
|
|
|
+ // # objectless nonstatic member reference
|
|
|
+ // ::= <expr-primary>
|
|
|
+ private BaseNode ParseExpression()
|
|
|
+ {
|
|
|
+ bool IsGlobal = ConsumeIf("gs");
|
|
|
+ BaseNode Expression = null;
|
|
|
+ if (Count() < 2)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (Peek())
|
|
|
+ {
|
|
|
+ case 'L':
|
|
|
+ return ParseExpressionPrimary();
|
|
|
+ case 'T':
|
|
|
+ return ParseTemplateParam();
|
|
|
+ case 'f':
|
|
|
+ char C = Peek(1);
|
|
|
+ if (C == 'p' || (C == 'L' && char.IsDigit(Peek(2))))
|
|
|
+ {
|
|
|
+ return ParseFunctionParameter();
|
|
|
+ }
|
|
|
+
|
|
|
+ return ParseFoldExpression();
|
|
|
+ case 'a':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'a':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("&&");
|
|
|
+ case 'd':
|
|
|
+ case 'n':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("&");
|
|
|
+ case 'N':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("&=");
|
|
|
+ case 'S':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("=");
|
|
|
+ case 't':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode Type = ParseType();
|
|
|
+ if (Type == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new EnclosedExpression("alignof (", Type, ")");
|
|
|
+ case 'z':
|
|
|
+ Position += 2;
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new EnclosedExpression("alignof (", Expression, ")");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'c':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'c':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode To = ParseType();
|
|
|
+ if (To == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode From = ParseExpression();
|
|
|
+ if (From == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new CastExpression("const_cast", To, From);
|
|
|
+ case 'l':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode Callee = ParseExpression();
|
|
|
+ if (Callee == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<BaseNode> Names = new List<BaseNode>();
|
|
|
+ while (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Names.Add(Expression);
|
|
|
+ }
|
|
|
+ return new CallExpression(Callee, Names);
|
|
|
+ case 'm':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression(",");
|
|
|
+ case 'o':
|
|
|
+ Position += 2;
|
|
|
+ return ParsePrefixExpression("~");
|
|
|
+ case 'v':
|
|
|
+ return ParseConversionExpression();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'd':
|
|
|
+ BaseNode LeftNode = null;
|
|
|
+ BaseNode RightNode = null;
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'a':
|
|
|
+ Position += 2;
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return Expression;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new DeleteExpression(Expression, IsGlobal, true);
|
|
|
+ case 'c':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode Type = ParseType();
|
|
|
+ if (Type == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return Expression;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new CastExpression("dynamic_cast", Type, Expression);
|
|
|
+ case 'e':
|
|
|
+ Position += 2;
|
|
|
+ return ParsePrefixExpression("*");
|
|
|
+ case 'l':
|
|
|
+ Position += 2;
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new DeleteExpression(Expression, IsGlobal, false);
|
|
|
+ case 'n':
|
|
|
+ return ParseUnresolvedName();
|
|
|
+ case 's':
|
|
|
+ Position += 2;
|
|
|
+ LeftNode = ParseExpression();
|
|
|
+ if (LeftNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ RightNode = ParseExpression();
|
|
|
+ if (RightNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new MemberExpression(LeftNode, ".*", RightNode);
|
|
|
+ case 't':
|
|
|
+ Position += 2;
|
|
|
+ LeftNode = ParseExpression();
|
|
|
+ if (LeftNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ RightNode = ParseExpression();
|
|
|
+ if (RightNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new MemberExpression(LeftNode, ".", RightNode);
|
|
|
+ case 'v':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("/");
|
|
|
+ case 'V':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("/=");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'e':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'o':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("^");
|
|
|
+ case 'O':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("^=");
|
|
|
+ case 'q':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("==");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'g':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'e':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression(">=");
|
|
|
+ case 't':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression(">");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'i':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'x':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode Base = ParseExpression();
|
|
|
+ if (Base == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode Subscript = ParseExpression();
|
|
|
+ if (Base == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new ArraySubscriptingExpression(Base, Subscript);
|
|
|
+ case 'l':
|
|
|
+ Position += 2;
|
|
|
+
|
|
|
+ List<BaseNode> BracedExpressions = new List<BaseNode>();
|
|
|
+ while (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ Expression = ParseBracedExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BracedExpressions.Add(Expression);
|
|
|
+ }
|
|
|
+ return new InitListExpression(null, BracedExpressions);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'l':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'e':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("<=");
|
|
|
+ case 's':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("<<");
|
|
|
+ case 'S':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("<<=");
|
|
|
+ case 't':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("<");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'm':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'i':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("-");
|
|
|
+ case 'I':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("-=");
|
|
|
+ case 'l':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("*");
|
|
|
+ case 'L':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("*=");
|
|
|
+ case 'm':
|
|
|
+ Position += 2;
|
|
|
+ if (ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ return ParsePrefixExpression("--");
|
|
|
+ }
|
|
|
+
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new PostfixExpression(Expression, "--");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'n':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'a':
|
|
|
+ case 'w':
|
|
|
+ Position += 2;
|
|
|
+ return ParseNewExpression();
|
|
|
+ case 'e':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("!=");
|
|
|
+ case 'g':
|
|
|
+ Position += 2;
|
|
|
+ return ParsePrefixExpression("-");
|
|
|
+ case 't':
|
|
|
+ Position += 2;
|
|
|
+ return ParsePrefixExpression("!");
|
|
|
+ case 'x':
|
|
|
+ Position += 2;
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new EnclosedExpression("noexcept (", Expression, ")");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'o':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'n':
|
|
|
+ return ParseUnresolvedName();
|
|
|
+ case 'o':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("||");
|
|
|
+ case 'r':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("|");
|
|
|
+ case 'R':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("|=");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'p':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'm':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("->*");
|
|
|
+ case 'l':
|
|
|
+ case 's':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("+");
|
|
|
+ case 'L':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("+=");
|
|
|
+ case 'p':
|
|
|
+ Position += 2;
|
|
|
+ if (ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ return ParsePrefixExpression("++");
|
|
|
+ }
|
|
|
+
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new PostfixExpression(Expression, "++");
|
|
|
+ case 't':
|
|
|
+ Position += 2;
|
|
|
+ LeftNode = ParseExpression();
|
|
|
+ if (LeftNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ RightNode = ParseExpression();
|
|
|
+ if (RightNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new MemberExpression(LeftNode, "->", RightNode);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'q':
|
|
|
+ if (Peek(1) == 'u')
|
|
|
+ {
|
|
|
+ Position += 2;
|
|
|
+ BaseNode Condition = ParseExpression();
|
|
|
+ if (Condition == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ LeftNode = ParseExpression();
|
|
|
+ if (LeftNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ RightNode = ParseExpression();
|
|
|
+ if (RightNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new ConditionalExpression(Condition, LeftNode, RightNode);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'r':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'c':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode To = ParseType();
|
|
|
+ if (To == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode From = ParseExpression();
|
|
|
+ if (From == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new CastExpression("reinterpret_cast", To, From);
|
|
|
+ case 'm':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("%");
|
|
|
+ case 'M':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression("%");
|
|
|
+ case 's':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression(">>");
|
|
|
+ case 'S':
|
|
|
+ Position += 2;
|
|
|
+ return ParseBinaryExpression(">>=");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 's':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'c':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode To = ParseType();
|
|
|
+ if (To == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode From = ParseExpression();
|
|
|
+ if (From == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new CastExpression("static_cast", To, From);
|
|
|
+ case 'p':
|
|
|
+ Position += 2;
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new PackedTemplateParameterExpansion(Expression);
|
|
|
+ case 'r':
|
|
|
+ return ParseUnresolvedName();
|
|
|
+ case 't':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode EnclosedType = ParseType();
|
|
|
+ if (EnclosedType == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new EnclosedExpression("sizeof (", EnclosedType, ")");
|
|
|
+ case 'z':
|
|
|
+ Position += 2;
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new EnclosedExpression("sizeof (", Expression, ")");
|
|
|
+ case 'Z':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode SizeofParamNode = null;
|
|
|
+ switch (Peek())
|
|
|
+ {
|
|
|
+ case 'T':
|
|
|
+ // FIXME: ??? Not entire sure if it's right
|
|
|
+ SizeofParamNode = ParseFunctionParameter();
|
|
|
+ if (SizeofParamNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new EnclosedExpression("sizeof...(", new PackedTemplateParameterExpansion(SizeofParamNode), ")");
|
|
|
+ case 'f':
|
|
|
+ SizeofParamNode = ParseFunctionParameter();
|
|
|
+ if (SizeofParamNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new EnclosedExpression("sizeof...(", SizeofParamNode, ")");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'P':
|
|
|
+ Position += 2;
|
|
|
+ List<BaseNode> Arguments = new List<BaseNode>();
|
|
|
+ while (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ BaseNode Argument = ParseTemplateArgument();
|
|
|
+ if (Argument == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Arguments.Add(Argument);
|
|
|
+ }
|
|
|
+ return new EnclosedExpression("sizeof...(", new NodeArray(Arguments), ")");
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 't':
|
|
|
+ switch (Peek(1))
|
|
|
+ {
|
|
|
+ case 'e':
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new EnclosedExpression("typeid (", Expression, ")");
|
|
|
+ case 't':
|
|
|
+ BaseNode EnclosedType = ParseExpression();
|
|
|
+ if (EnclosedType == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new EnclosedExpression("typeid (", EnclosedType, ")");
|
|
|
+ case 'l':
|
|
|
+ Position += 2;
|
|
|
+ BaseNode TypeNode = ParseType();
|
|
|
+ if (TypeNode == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<BaseNode> BracedExpressions = new List<BaseNode>();
|
|
|
+ while (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ Expression = ParseBracedExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BracedExpressions.Add(Expression);
|
|
|
+ }
|
|
|
+ return new InitListExpression(TypeNode, BracedExpressions);
|
|
|
+ case 'r':
|
|
|
+ Position += 2;
|
|
|
+ return new NameType("throw");
|
|
|
+ case 'w':
|
|
|
+ Position += 2;
|
|
|
+ Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new ThrowExpression(Expression);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (char.IsDigit(Peek()))
|
|
|
+ {
|
|
|
+ return ParseUnresolvedName();
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private BaseNode ParseIntegerLiteral(string LiteralName)
|
|
|
+ {
|
|
|
+ string Number = ParseNumber(true);
|
|
|
+ if (Number == null || Number.Length == 0 || !ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new IntegerLiteral(LiteralName, Number);
|
|
|
+ }
|
|
|
+
|
|
|
+ // <expr-primary> ::= L <type> <value number> E # integer literal
|
|
|
+ // ::= L <type> <value float> E # floating literal (TODO)
|
|
|
+ // ::= L <string type> E # string literal
|
|
|
+ // ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
|
|
|
+ // ::= L <pointer type> 0 E # null pointer template argument
|
|
|
+ // ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
|
|
|
+ // ::= L _Z <encoding> E # external name
|
|
|
+ private BaseNode ParseExpressionPrimary()
|
|
|
+ {
|
|
|
+ if (!ConsumeIf("L"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (Peek())
|
|
|
+ {
|
|
|
+ case 'w':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("wchar_t");
|
|
|
+ case 'b':
|
|
|
+ if (ConsumeIf("b0E"))
|
|
|
+ {
|
|
|
+ return new NameType("false", NodeType.BooleanExpression);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ConsumeIf("b1E"))
|
|
|
+ {
|
|
|
+ return new NameType("true", NodeType.BooleanExpression);
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ case 'c':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("char");
|
|
|
+ case 'a':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("signed char");
|
|
|
+ case 'h':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("unsigned char");
|
|
|
+ case 's':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("short");
|
|
|
+ case 't':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("unsigned short");
|
|
|
+ case 'i':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("");
|
|
|
+ case 'j':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("u");
|
|
|
+ case 'l':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("l");
|
|
|
+ case 'm':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("ul");
|
|
|
+ case 'x':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("ll");
|
|
|
+ case 'y':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("ull");
|
|
|
+ case 'n':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("__int128");
|
|
|
+ case 'o':
|
|
|
+ Position++;
|
|
|
+ return ParseIntegerLiteral("unsigned __int128");
|
|
|
+ case 'd':
|
|
|
+ case 'e':
|
|
|
+ case 'f':
|
|
|
+ // TODO: floating literal
|
|
|
+ return null;
|
|
|
+ case '_':
|
|
|
+ if (ConsumeIf("_Z"))
|
|
|
+ {
|
|
|
+ BaseNode Encoding = ParseEncoding();
|
|
|
+ if (Encoding != null && ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ return Encoding;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ case 'T':
|
|
|
+ return null;
|
|
|
+ default:
|
|
|
+ BaseNode Type = ParseType();
|
|
|
+ if (Type == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ string Number = ParseNumber();
|
|
|
+ if (Number == null || Number.Length == 0 || !ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new IntegerCastExpression(Type, Number);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
|
|
|
+ // ::= DT <expression> E # decltype of an expression (C++0x)
|
|
|
+ private BaseNode ParseDecltype()
|
|
|
+ {
|
|
|
+ if (!ConsumeIf("D") || (!ConsumeIf("t") && !ConsumeIf("T")))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode Expression = ParseExpression();
|
|
|
+ if (Expression == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new EnclosedExpression("decltype(", Expression, ")");
|
|
|
+ }
|
|
|
+
|
|
|
+ // <template-param> ::= T_ # first template parameter
|
|
|
+ // ::= T <parameter-2 non-negative number> _
|
|
|
+ // <template-template-param> ::= <template-param>
|
|
|
+ // ::= <substitution>
|
|
|
+ private BaseNode ParseTemplateParam()
|
|
|
+ {
|
|
|
+ if (!ConsumeIf("T"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ int Index = 0;
|
|
|
+ if (!ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ Index = ParsePositiveNumber();
|
|
|
+ if (Index < 0)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Index++;
|
|
|
+ if (!ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5.1.8: TODO: lambda?
|
|
|
+ // if (IsParsingLambdaParameters)
|
|
|
+ // return new NameType("auto");
|
|
|
+
|
|
|
+ if (CanForwardTemplateReference)
|
|
|
+ {
|
|
|
+ ForwardTemplateReference ForwardTemplateReference = new ForwardTemplateReference(Index);
|
|
|
+ ForwardTemplateReferenceList.Add(ForwardTemplateReference);
|
|
|
+ return ForwardTemplateReference;
|
|
|
+ }
|
|
|
+ if (Index >= TemplateParamList.Count)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return TemplateParamList[Index];
|
|
|
+ }
|
|
|
+
|
|
|
+ // <template-args> ::= I <template-arg>+ E
|
|
|
+ private BaseNode ParseTemplateArguments(bool HasContext = false)
|
|
|
+ {
|
|
|
+ if (!ConsumeIf("I"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (HasContext)
|
|
|
+ {
|
|
|
+ TemplateParamList.Clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ List<BaseNode> Args = new List<BaseNode>();
|
|
|
+ while (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ if (HasContext)
|
|
|
+ {
|
|
|
+ List<BaseNode> TemplateParamListTemp = new List<BaseNode>(TemplateParamList);
|
|
|
+ BaseNode TemplateArgument = ParseTemplateArgument();
|
|
|
+ TemplateParamList = TemplateParamListTemp;
|
|
|
+ if (TemplateArgument == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Args.Add(TemplateArgument);
|
|
|
+ if (TemplateArgument.GetType().Equals(NodeType.PackedTemplateArgument))
|
|
|
+ {
|
|
|
+ TemplateArgument = new PackedTemplateParameter(((NodeArray)TemplateArgument).Nodes);
|
|
|
+ }
|
|
|
+ TemplateParamList.Add(TemplateArgument);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ BaseNode TemplateArgument = ParseTemplateArgument();
|
|
|
+ if (TemplateArgument == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Args.Add(TemplateArgument);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return new TemplateArguments(Args);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // <template-arg> ::= <type> # type or template
|
|
|
+ // ::= X <expression> E # expression
|
|
|
+ // ::= <expr-primary> # simple expressions
|
|
|
+ // ::= J <template-arg>* E # argument pack
|
|
|
+ private BaseNode ParseTemplateArgument()
|
|
|
+ {
|
|
|
+ switch (Peek())
|
|
|
+ {
|
|
|
+ // X <expression> E
|
|
|
+ case 'X':
|
|
|
+ Position++;
|
|
|
+ BaseNode Expression = ParseExpression();
|
|
|
+ if (Expression == null || !ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return Expression;
|
|
|
+ // <expr-primary>
|
|
|
+ case 'L':
|
|
|
+ return ParseExpressionPrimary();
|
|
|
+ // J <template-arg>* E
|
|
|
+ case 'J':
|
|
|
+ Position++;
|
|
|
+ List<BaseNode> TemplateArguments = new List<BaseNode>();
|
|
|
+ while (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ BaseNode TemplateArgument = ParseTemplateArgument();
|
|
|
+ if (TemplateArgument == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ TemplateArguments.Add(TemplateArgument);
|
|
|
+ }
|
|
|
+ return new NodeArray(TemplateArguments, NodeType.PackedTemplateArgument);
|
|
|
+ // <type>
|
|
|
+ default:
|
|
|
+ return ParseType();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ class NameParserContext
|
|
|
+ {
|
|
|
+ public CVType CV;
|
|
|
+ public SimpleReferenceType Ref;
|
|
|
+ public bool FinishWithTemplateArguments;
|
|
|
+ public bool CtorDtorConversion;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // <unresolved-type> ::= <template-param> [ <template-args> ] # T:: or T<X,Y>::
|
|
|
+ // ::= <decltype> # decltype(p)::
|
|
|
+ // ::= <substitution>
|
|
|
+ private BaseNode ParseUnresolvedType()
|
|
|
+ {
|
|
|
+ if (Peek() == 'T')
|
|
|
+ {
|
|
|
+ BaseNode TemplateParam = ParseTemplateParam();
|
|
|
+ if (TemplateParam == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ SubstitutionList.Add(TemplateParam);
|
|
|
+ return TemplateParam;
|
|
|
+ }
|
|
|
+ else if (Peek() == 'D')
|
|
|
+ {
|
|
|
+ BaseNode DeclType = ParseDecltype();
|
|
|
+ if (DeclType == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ SubstitutionList.Add(DeclType);
|
|
|
+ return DeclType;
|
|
|
+ }
|
|
|
+ return ParseSubstitution();
|
|
|
+ }
|
|
|
+
|
|
|
+ // <simple-id> ::= <source-name> [ <template-args> ]
|
|
|
+ private BaseNode ParseSimpleId()
|
|
|
+ {
|
|
|
+ BaseNode SourceName = ParseSourceName();
|
|
|
+ if (SourceName == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Peek() == 'I')
|
|
|
+ {
|
|
|
+ BaseNode TemplateArguments = ParseTemplateArguments();
|
|
|
+ if (TemplateArguments == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new NameTypeWithTemplateArguments(SourceName, TemplateArguments);
|
|
|
+ }
|
|
|
+ return SourceName;
|
|
|
+ }
|
|
|
+
|
|
|
+ // <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
|
|
|
+ // ::= <simple-id> # e.g., ~A<2*N>
|
|
|
+ private BaseNode ParseDestructorName()
|
|
|
+ {
|
|
|
+ BaseNode Node;
|
|
|
+ if (char.IsDigit(Peek()))
|
|
|
+ {
|
|
|
+ Node = ParseSimpleId();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Node = ParseUnresolvedType();
|
|
|
+ }
|
|
|
+ if (Node == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new DtorName(Node);
|
|
|
+ }
|
|
|
+
|
|
|
+ // <base-unresolved-name> ::= <simple-id> # unresolved name
|
|
|
+ // extension ::= <operator-name> # unresolved operator-function-id
|
|
|
+ // extension ::= <operator-name> <template-args> # unresolved operator template-id
|
|
|
+ // ::= on <operator-name> # unresolved operator-function-id
|
|
|
+ // ::= on <operator-name> <template-args> # unresolved operator template-id
|
|
|
+ // ::= dn <destructor-name> # destructor or pseudo-destructor;
|
|
|
+ // # e.g. ~X or ~X<N-1>
|
|
|
+ private BaseNode ParseBaseUnresolvedName()
|
|
|
+ {
|
|
|
+ if (char.IsDigit(Peek()))
|
|
|
+ {
|
|
|
+ return ParseSimpleId();
|
|
|
+ }
|
|
|
+ else if (ConsumeIf("dn"))
|
|
|
+ {
|
|
|
+ return ParseDestructorName();
|
|
|
+ }
|
|
|
+
|
|
|
+ ConsumeIf("on");
|
|
|
+ BaseNode OperatorName = ParseOperatorName(null);
|
|
|
+ if (OperatorName == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Peek() == 'I')
|
|
|
+ {
|
|
|
+ BaseNode TemplateArguments = ParseTemplateArguments();
|
|
|
+ if (TemplateArguments == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new NameTypeWithTemplateArguments(OperatorName, TemplateArguments);
|
|
|
+ }
|
|
|
+ return OperatorName;
|
|
|
+ }
|
|
|
+
|
|
|
+ // <unresolved-name> ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
|
|
|
+ // ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
|
|
|
+ // ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
|
|
|
+ // # T::N::x /decltype(p)::N::x
|
|
|
+ // ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
|
|
|
+ // # A::x, N::y, A<T>::z; "gs" means leading "::"
|
|
|
+ private BaseNode ParseUnresolvedName(NameParserContext Context = null)
|
|
|
+ {
|
|
|
+ BaseNode Result = null;
|
|
|
+ if (ConsumeIf("srN"))
|
|
|
+ {
|
|
|
+ Result = ParseUnresolvedType();
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Peek() == 'I')
|
|
|
+ {
|
|
|
+ BaseNode TemplateArguments = ParseTemplateArguments();
|
|
|
+ if (TemplateArguments == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new NameTypeWithTemplateArguments(Result, TemplateArguments);
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ while (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ BaseNode SimpleId = ParseSimpleId();
|
|
|
+ if (SimpleId == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new QualifiedName(Result, SimpleId);
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode BaseName = ParseBaseUnresolvedName();
|
|
|
+ if (BaseName == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new QualifiedName(Result, BaseName);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool IsGlobal = ConsumeIf("gs");
|
|
|
+
|
|
|
+ // ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
|
|
|
+ if (!ConsumeIf("sr"))
|
|
|
+ {
|
|
|
+ Result = ParseBaseUnresolvedName();
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (IsGlobal)
|
|
|
+ {
|
|
|
+ Result = new GlobalQualifiedName(Result);
|
|
|
+ }
|
|
|
+
|
|
|
+ return Result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
|
|
|
+ if (char.IsDigit(Peek()))
|
|
|
+ {
|
|
|
+ do
|
|
|
+ {
|
|
|
+ BaseNode Qualifier = ParseSimpleId();
|
|
|
+ if (Qualifier == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Result != null)
|
|
|
+ {
|
|
|
+ Result = new QualifiedName(Result, Qualifier);
|
|
|
+ }
|
|
|
+ else if (IsGlobal)
|
|
|
+ {
|
|
|
+ Result = new GlobalQualifiedName(Qualifier);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Result = Qualifier;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ } while (!ConsumeIf("E"));
|
|
|
+ }
|
|
|
+ // ::= sr <unresolved-type> [tempate-args] <base-unresolved-name> # T::x / decltype(p)::x
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Result = ParseUnresolvedType();
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Peek() == 'I')
|
|
|
+ {
|
|
|
+ BaseNode TemplateArguments = ParseTemplateArguments();
|
|
|
+ if (TemplateArguments == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new NameTypeWithTemplateArguments(Result, TemplateArguments);
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode BaseUnresolvedName = ParseBaseUnresolvedName();
|
|
|
+ if (BaseUnresolvedName == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new QualifiedName(Result, BaseUnresolvedName);
|
|
|
+ }
|
|
|
+
|
|
|
+ // <unscoped-name> ::= <unqualified-name>
|
|
|
+ // ::= St <unqualified-name> # ::std::
|
|
|
+ private BaseNode ParseUnscopedName(NameParserContext Context)
|
|
|
+ {
|
|
|
+ if (ConsumeIf("St"))
|
|
|
+ {
|
|
|
+ BaseNode UnresolvedName = ParseUnresolvedName(Context);
|
|
|
+ if (UnresolvedName == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new StdQualifiedName(UnresolvedName);
|
|
|
+ }
|
|
|
+ return ParseUnresolvedName(Context);
|
|
|
+ }
|
|
|
+
|
|
|
+ // <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix (TODO)> <unqualified-name> E
|
|
|
+ // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix (TODO)> <template-args (TODO)> E
|
|
|
+ private BaseNode ParseNestedName(NameParserContext Context)
|
|
|
+ {
|
|
|
+ // Impossible in theory
|
|
|
+ if (Consume() != 'N')
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode Result = null;
|
|
|
+ CVType CV = new CVType(ParseCVQualifiers(), null);
|
|
|
+ if (Context != null)
|
|
|
+ {
|
|
|
+ Context.CV = CV;
|
|
|
+ }
|
|
|
+
|
|
|
+ SimpleReferenceType Ref = ParseRefQualifiers();
|
|
|
+ if (Context != null)
|
|
|
+ {
|
|
|
+ Context.Ref = Ref;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ConsumeIf("St"))
|
|
|
+ {
|
|
|
+ Result = new NameType("std");
|
|
|
+ }
|
|
|
+
|
|
|
+ while (!ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ // <data-member-prefix> end
|
|
|
+ if (ConsumeIf("M"))
|
|
|
+ {
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ char C = Peek();
|
|
|
+
|
|
|
+ // TODO: template args
|
|
|
+ if (C == 'T')
|
|
|
+ {
|
|
|
+ BaseNode TemplateParam = ParseTemplateParam();
|
|
|
+ if (TemplateParam == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = CreateNameNode(Result, TemplateParam, Context);
|
|
|
+ SubstitutionList.Add(Result);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // <template-prefix> <template-args>
|
|
|
+ if (C == 'I')
|
|
|
+ {
|
|
|
+ BaseNode TemplateArgument = ParseTemplateArguments(Context != null);
|
|
|
+ if (TemplateArgument == null || Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = new NameTypeWithTemplateArguments(Result, TemplateArgument);
|
|
|
+ if (Context != null)
|
|
|
+ {
|
|
|
+ Context.FinishWithTemplateArguments = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ SubstitutionList.Add(Result);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // <decltype>
|
|
|
+ if (C == 'D' && (Peek(1) == 't' || Peek(1) == 'T'))
|
|
|
+ {
|
|
|
+ BaseNode Decltype = ParseDecltype();
|
|
|
+ if (Decltype == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = CreateNameNode(Result, Decltype, Context);
|
|
|
+ SubstitutionList.Add(Result);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // <substitution>
|
|
|
+ if (C == 'S' && Peek(1) != 't')
|
|
|
+ {
|
|
|
+ BaseNode Substitution = ParseSubstitution();
|
|
|
+ if (Substitution == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = CreateNameNode(Result, Substitution, Context);
|
|
|
+ if (Result != Substitution)
|
|
|
+ {
|
|
|
+ SubstitutionList.Add(Substitution);
|
|
|
+ }
|
|
|
+
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // <ctor-dtor-name> of ParseUnqualifiedName
|
|
|
+ if (C == 'C' || (C == 'D' && Peek(1) != 'C'))
|
|
|
+ {
|
|
|
+ // We cannot have nothing before this
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode CtOrDtorName = ParseCtorDtorName(Context, Result);
|
|
|
+
|
|
|
+ if (CtOrDtorName == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Result = CreateNameNode(Result, CtOrDtorName, Context);
|
|
|
+
|
|
|
+ // TODO: ABI Tags (before)
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ SubstitutionList.Add(Result);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode UnqualifiedName = ParseUnqualifiedName(Context);
|
|
|
+ if (UnqualifiedName == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ Result = CreateNameNode(Result, UnqualifiedName, Context);
|
|
|
+
|
|
|
+ SubstitutionList.Add(Result);
|
|
|
+ }
|
|
|
+ if (Result == null || SubstitutionList.Count == 0)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ SubstitutionList.RemoveAt(SubstitutionList.Count - 1);
|
|
|
+ return Result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // <discriminator> ::= _ <non-negative number> # when number < 10
|
|
|
+ // ::= __ <non-negative number> _ # when number >= 10
|
|
|
+ private void ParseDiscriminator()
|
|
|
+ {
|
|
|
+ if (Count() == 0)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // We ignore the discriminator, we don't need it.
|
|
|
+ if (ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ ConsumeIf("_");
|
|
|
+ while (char.IsDigit(Peek()) && Count() != 0)
|
|
|
+ {
|
|
|
+ Consume();
|
|
|
+ }
|
|
|
+ ConsumeIf("_");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // <local-name> ::= Z <function encoding> E <entity name> [<discriminator>]
|
|
|
+ // ::= Z <function encoding> E s [<discriminator>]
|
|
|
+ // ::= Z <function encoding> Ed [ <parameter number> ] _ <entity name>
|
|
|
+ private BaseNode ParseLocalName(NameParserContext Context)
|
|
|
+ {
|
|
|
+ if (!ConsumeIf("Z"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode Encoding = ParseEncoding();
|
|
|
+ if (Encoding == null || !ConsumeIf("E"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode EntityName;
|
|
|
+ if (ConsumeIf("s"))
|
|
|
+ {
|
|
|
+ ParseDiscriminator();
|
|
|
+ return new LocalName(Encoding, new NameType("string literal"));
|
|
|
+ }
|
|
|
+ else if (ConsumeIf("d"))
|
|
|
+ {
|
|
|
+ ParseNumber(true);
|
|
|
+ if (!ConsumeIf("_"))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ EntityName = ParseName(Context);
|
|
|
+ if (EntityName == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new LocalName(Encoding, EntityName);
|
|
|
+ }
|
|
|
+
|
|
|
+ EntityName = ParseName(Context);
|
|
|
+ if (EntityName == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ ParseDiscriminator();
|
|
|
+ return new LocalName(Encoding, EntityName);
|
|
|
+ }
|
|
|
+
|
|
|
+ // <name> ::= <nested-name>
|
|
|
+ // ::= <unscoped-name>
|
|
|
+ // ::= <unscoped-template-name> <template-args>
|
|
|
+ // ::= <local-name> # See Scope Encoding below (TODO)
|
|
|
+ private BaseNode ParseName(NameParserContext Context = null)
|
|
|
+ {
|
|
|
+ ConsumeIf("L");
|
|
|
+
|
|
|
+ if (Peek() == 'N')
|
|
|
+ {
|
|
|
+ return ParseNestedName(Context);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Peek() == 'Z')
|
|
|
+ {
|
|
|
+ return ParseLocalName(Context);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Peek() == 'S' && Peek(1) != 't')
|
|
|
+ {
|
|
|
+ BaseNode Substitution = ParseSubstitution();
|
|
|
+ if (Substitution == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Peek() != 'I')
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode TemplateArguments = ParseTemplateArguments(Context != null);
|
|
|
+ if (TemplateArguments == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Context != null)
|
|
|
+ {
|
|
|
+ Context.FinishWithTemplateArguments = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new NameTypeWithTemplateArguments(Substitution, TemplateArguments);
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode Result = ParseUnscopedName(Context);
|
|
|
+ if (Result == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Peek() == 'I')
|
|
|
+ {
|
|
|
+ SubstitutionList.Add(Result);
|
|
|
+ BaseNode TemplateArguments = ParseTemplateArguments(Context != null);
|
|
|
+ if (TemplateArguments == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Context != null)
|
|
|
+ {
|
|
|
+ Context.FinishWithTemplateArguments = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return new NameTypeWithTemplateArguments(Result, TemplateArguments);
|
|
|
+ }
|
|
|
+
|
|
|
+ return Result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool IsEncodingEnd()
|
|
|
+ {
|
|
|
+ char C = Peek();
|
|
|
+ return Count() == 0 || C == 'E' || C == '.' || C == '_';
|
|
|
+ }
|
|
|
+
|
|
|
+ // <encoding> ::= <function name> <bare-function-type>
|
|
|
+ // ::= <data name>
|
|
|
+ // ::= <special-name>
|
|
|
+ private BaseNode ParseEncoding()
|
|
|
+ {
|
|
|
+ NameParserContext Context = new NameParserContext();
|
|
|
+ if (Peek() == 'T' || (Peek() == 'G' && Peek(1) == 'V'))
|
|
|
+ {
|
|
|
+ return ParseSpecialName(Context);
|
|
|
+ }
|
|
|
+
|
|
|
+ BaseNode Name = ParseName(Context);
|
|
|
+ if (Name == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO: compute template refs here
|
|
|
+
|
|
|
+ if (IsEncodingEnd())
|
|
|
+ {
|
|
|
+ return Name;
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO: Ua9enable_ifI
|
|
|
+
|
|
|
+ BaseNode ReturnType = null;
|
|
|
+ if (!Context.CtorDtorConversion && Context.FinishWithTemplateArguments)
|
|
|
+ {
|
|
|
+ ReturnType = ParseType();
|
|
|
+ if (ReturnType == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ConsumeIf("v"))
|
|
|
+ {
|
|
|
+ return new EncodedFunction(Name, null, Context.CV, Context.Ref, null, ReturnType);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<BaseNode> Params = new List<BaseNode>();
|
|
|
+
|
|
|
+ // backup because that can be destroyed by parseType
|
|
|
+ CVType CV = Context.CV;
|
|
|
+ SimpleReferenceType Ref = Context.Ref;
|
|
|
+
|
|
|
+ while (!IsEncodingEnd())
|
|
|
+ {
|
|
|
+ BaseNode Param = ParseType();
|
|
|
+ if (Param == null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Params.Add(Param);
|
|
|
+ }
|
|
|
+
|
|
|
+ return new EncodedFunction(Name, new NodeArray(Params), CV, Ref, null, ReturnType);
|
|
|
+ }
|
|
|
+
|
|
|
+ // <mangled-name> ::= _Z <encoding>
|
|
|
+ // ::= <type>
|
|
|
+ private BaseNode Parse()
|
|
|
+ {
|
|
|
+ if (ConsumeIf("_Z"))
|
|
|
+ {
|
|
|
+ BaseNode Encoding = ParseEncoding();
|
|
|
+ if (Encoding != null && Count() == 0)
|
|
|
+ {
|
|
|
+ return Encoding;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ BaseNode Type = ParseType();
|
|
|
+ if (Type != null && Count() == 0)
|
|
|
+ {
|
|
|
+ return Type;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static string Parse(string OriginalMangled)
|
|
|
+ {
|
|
|
+ Demangler Instance = new Demangler(OriginalMangled);
|
|
|
+ BaseNode ResNode = Instance.Parse();
|
|
|
+
|
|
|
+ if (ResNode != null)
|
|
|
+ {
|
|
|
+ StringWriter Writer = new StringWriter();
|
|
|
+ ResNode.Print(Writer);
|
|
|
+ return Writer.ToString();
|
|
|
+ }
|
|
|
+
|
|
|
+ return OriginalMangled;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|