static void ParseTypeContinue(string[] tokens, ref int index, out CallingConvention callingConvention, out TypeDecl decl, out Action <TypeDecl> continuation, out string name) { callingConvention = CallingConvention.Default; decl = null; continuation = null; name = null; if (Parser.Token(tokens, ref index, "__cdecl")) { callingConvention = CallingConvention.CDecl; } else if (Parser.Token(tokens, ref index, "__clrcall")) { callingConvention = CallingConvention.ClrCall; } else if (Parser.Token(tokens, ref index, "__stdcall")) { callingConvention = CallingConvention.StdCall; } else if (Parser.Token(tokens, ref index, "__fastcall")) { callingConvention = CallingConvention.FastCall; } else if (Parser.Token(tokens, ref index, "__thiscall")) { callingConvention = CallingConvention.ThisCall; } else if (Parser.Token(tokens, ref index, "__vectorcall")) { callingConvention = CallingConvention.VectorCall; } TypeDecl beforeDecl = null; Action <TypeDecl> beforeContinuation = null; ParseTypeContinueBeforeName(tokens, ref index, out beforeDecl, out beforeContinuation, out name); TypeDecl middleDecl = null; Action <TypeDecl> middleContinuation = null; if (name == null) { int middleIndex = index; bool recursive = false; if (Parser.Token(tokens, ref middleIndex, "(")) { string token = null; Parser.SkipUntil(tokens, ref middleIndex, out token, ",", ")"); if (token == ")") { recursive = tokens[middleIndex] == "(" || tokens[middleIndex] == "["; } } if (recursive) { Parser.EnsureToken(tokens, ref index, "("); var middleCallingConvention = CallingConvention.Default; ParseTypeContinue(tokens, ref index, out middleCallingConvention, out middleDecl, out middleContinuation, out name); Parser.EnsureToken(tokens, ref index, ")"); if (middleCallingConvention != CallingConvention.Default) { if (callingConvention == CallingConvention.Default) { callingConvention = middleCallingConvention; } else { throw new ArgumentException("Failed to parse."); } } } } TypeDecl afterDecl = null; Action <TypeDecl> afterContinuation = null; ParseTypeContinueAfterName(tokens, ref index, ref callingConvention, out afterDecl, out afterContinuation); decl = middleDecl; continuation = middleContinuation; if (afterDecl != null) { if (decl == null) { decl = afterDecl; } else { continuation(afterDecl); } continuation = afterContinuation; } if (beforeDecl != null) { if (decl == null) { decl = beforeDecl; } else { continuation(beforeDecl); } continuation = beforeContinuation; } }
static bool ParseMiniType(string[] tokens, ref int index, out TypeDecl decl) { decl = null; if (Parser.Token(tokens, ref index, "const")) { decl = new DecorateTypeDecl { Decoration = Decoration.Const, Element = EnsureMiniType(tokens, ref index), }; return(true); } else if (Parser.Token(tokens, ref index, "volatile")) { decl = new DecorateTypeDecl { Decoration = Decoration.Volatile, Element = EnsureMiniType(tokens, ref index), }; return(true); } else if (Parser.Token(tokens, ref index, "signed")) { decl = new DecorateTypeDecl { Decoration = Decoration.Signed, Element = EnsureMiniType(tokens, ref index), }; return(true); } else if (Parser.Token(tokens, ref index, "unsigned")) { decl = new DecorateTypeDecl { Decoration = Decoration.Unsigned, Element = EnsureMiniType(tokens, ref index), }; return(true); } else if (Parser.Token(tokens, ref index, "decltype")) { Parser.EnsureToken(tokens, ref index, "("); int oldIndex = index; Parser.SkipUntil(tokens, ref index, ")"); decl = new DeclTypeDecl { Expression = tokens .Skip(oldIndex) .Take(index - 1 - oldIndex) .Aggregate((a, b) => a + " " + b), }; return(true); } else if (Parser.Token(tokens, ref index, "false") || Parser.Token(tokens, ref index, "true")) { decl = new ConstantTypeDecl { Value = tokens[index - 1], }; return(true); } else { if (index < tokens.Length) { int value = 0; if (int.TryParse(tokens[index], out value)) { index++; decl = new ConstantTypeDecl { Value = tokens[index - 1], }; return(true); } } string token = null; Parser.Token(tokens, ref index, "typename"); if (Parser.Id(tokens, ref index, out token)) { decl = new RefTypeDecl { Name = token, }; if (token != "operator") { while (true) { if (Parser.Token(tokens, ref index, "<")) { var genericDecl = new GenericTypeDecl { Element = decl, TypeArguments = new List <TypeDecl>(), }; decl = genericDecl; if (!Parser.Token(tokens, ref index, ">")) { while (true) { genericDecl.TypeArguments.Add(EnsureTypeWithoutName(tokens, ref index)); if (Parser.Token(tokens, ref index, ">")) { break; } else { Parser.EnsureToken(tokens, ref index, ","); } } } } else if (Parser.Token(tokens, ref index, ":")) { Parser.EnsureToken(tokens, ref index, ":"); Parser.Token(tokens, ref index, "template"); if (Parser.Id(tokens, ref index, out token)) { decl = new SubTypeDecl { Parent = decl, Name = token, }; } else { index -= 2; break; } } else { break; } } } return(true); } else { return(false); } } }
internal static void ParseTypeContinueAfterName(string[] tokens, ref int index, ref CallingConvention callingConvention, out TypeDecl decl, out Action <TypeDecl> continuation) { decl = null; continuation = null; while (true) { if (Parser.Token(tokens, ref index, "[")) { Parser.SkipUntil(tokens, ref index, "]"); var arrayDecl = new ArrayTypeDecl(); if (decl == null) { continuation = x => arrayDecl.Element = x; } else { arrayDecl.Element = decl; } decl = arrayDecl; } else if (Parser.Token(tokens, ref index, "(")) { var funcDecl = new FunctionTypeDecl { Const = false, CallingConvention = callingConvention, Parameters = new List <VarDecl>(), }; callingConvention = CallingConvention.Default; if (decl == null) { continuation = x => funcDecl.ReturnType = x; } else { funcDecl.ReturnType = decl; } decl = funcDecl; bool skipParameters = false; if (Parser.Token(tokens, ref index, "void")) { if (Parser.Token(tokens, ref index, ")")) { skipParameters = true; } else { index--; } } if (!skipParameters && !Parser.Token(tokens, ref index, ")")) { while (true) { string name = null; var parameterType = EnsureType(tokens, ref index, out name); funcDecl.Parameters.Add(new VarDecl { Static = false, Name = name, Type = parameterType, }); if (Parser.Token(tokens, ref index, "=")) { Parser.SkipUntilInTemplate(tokens, ref index, ",", ")", ";"); index--; } if (Parser.Token(tokens, ref index, ")")) { break; } Parser.EnsureToken(tokens, ref index, ","); } } while (true) { if (Parser.Token(tokens, ref index, "const")) { funcDecl.Const = true; } else if (Parser.Token(tokens, ref index, "override")) { } else { break; } } } else { break; } } }
static SymbolDecl[] ParseSymbol(string[] tokens, ref int index) { while (index < tokens.Length && tokens[index].Length >= 3 && tokens[index].StartsWith("///")) { index++; } if (Parser.Token(tokens, ref index, "public") || Parser.Token(tokens, ref index, "protected") || Parser.Token(tokens, ref index, "private")) { index--; return(null); } TemplateDecl templateDecl = null; if (Parser.Token(tokens, ref index, "template")) { templateDecl = new TemplateDecl { TypeParameters = new List <string>(), Specialization = new List <TypeDecl>(), }; Parser.EnsureToken(tokens, ref index, "<"); if (!Parser.Token(tokens, ref index, ">")) { while (true) { string token = null; Parser.SkipUntilInTemplate(tokens, ref index, out token, ",", ">", "="); index -= 2; templateDecl.TypeParameters.Add(Parser.EnsureId(tokens, ref index)); index++; if (token == "=") { Parser.SkipUntilInTemplate(tokens, ref index, out token, ",", ">"); } if (token == ">") { break; } } } } if (Parser.Token(tokens, ref index, "friend")) { int oldIndex = index - 1; string token = null; Parser.SkipUntil(tokens, ref index, out token, ";", "{"); if (token == ";") { return(null); } else { index = oldIndex; tokens[index] = "static"; } } if (Parser.Token(tokens, ref index, "namespace")) { if (templateDecl != null) { throw new ArgumentException("Failed to parse."); } var decl = new NamespaceDecl(); decl.Name = Parser.EnsureId(tokens, ref index); Parser.EnsureToken(tokens, ref index, "{"); ParseSymbols(tokens, ref index, decl); Parser.EnsureToken(tokens, ref index, "}"); return(new SymbolDecl[] { decl }); } else if (Parser.Token(tokens, ref index, "using")) { if (Parser.Token(tokens, ref index, "namespace")) { if (templateDecl != null) { throw new ArgumentException("Failed to parse."); } var decl = new UsingNamespaceDecl(); decl.Path = new List <string>(); decl.Path.Add(Parser.EnsureId(tokens, ref index)); while (!Parser.Token(tokens, ref index, ";")) { Parser.EnsureToken(tokens, ref index, ":"); Parser.EnsureToken(tokens, ref index, ":"); decl.Path.Add(Parser.EnsureId(tokens, ref index)); } return(new SymbolDecl[] { decl }); } else { string name = null; if (Parser.Id(tokens, ref index, out name)) { if (templateDecl != null) { if (Parser.Token(tokens, ref index, "<")) { while (true) { templateDecl.Specialization.Add(TypeDecl.EnsureTypeWithoutName(tokens, ref index)); if (Parser.Token(tokens, ref index, ">")) { break; } Parser.EnsureToken(tokens, ref index, ","); } } } if (Parser.Token(tokens, ref index, "=")) { SymbolDecl decl = new TypedefDecl { Name = name, Type = TypeDecl.EnsureTypeWithoutName(tokens, ref index), }; Parser.EnsureToken(tokens, ref index, ";"); if (templateDecl != null) { templateDecl.Element = decl; decl = templateDecl; } return(new SymbolDecl[] { decl }); } } if (templateDecl != null) { throw new ArgumentException("Failed to parse."); } Parser.SkipUntil(tokens, ref index, ";"); } } else if (Parser.Token(tokens, ref index, "typedef")) { if (templateDecl != null) { throw new ArgumentException("Failed to parse."); } string name = null; var type = TypeDecl.EnsureTypeWithName(tokens, ref index, out name); Parser.EnsureToken(tokens, ref index, ";"); var decl = new TypedefDecl(); decl.Name = name; decl.Type = type; return(new SymbolDecl[] { decl }); } else if (Parser.Token(tokens, ref index, "enum")) { if (templateDecl != null) { throw new ArgumentException("Failed to parse."); } Parser.Token(tokens, ref index, "class"); string name = Parser.EnsureId(tokens, ref index); if (Parser.Token(tokens, ref index, ":")) { TypeDecl.EnsureTypeWithoutName(tokens, ref index); } if (!Parser.Token(tokens, ref index, ";")) { Parser.EnsureToken(tokens, ref index, "{"); var decl = new EnumDecl { Name = name, Children = new List <SymbolDecl>(), }; while (true) { if (Parser.Token(tokens, ref index, "}")) { break; } while (index < tokens.Length && tokens[index].Length >= 3 && tokens[index].StartsWith("///")) { index++; } decl.Children.Add(new EnumItemDecl { Name = Parser.EnsureId(tokens, ref index), }); string token = null; Parser.SkipUntil(tokens, ref index, out token, ",", "}"); if (token == "}") { break; } } if (Parser.Id(tokens, ref index, out name)) { var varDecl = new VarDecl { Static = false, Name = name, Type = new RefTypeDecl { Name = decl.Name, }, }; Parser.EnsureToken(tokens, ref index, ";"); return(new SymbolDecl[] { decl, varDecl }); } else { Parser.EnsureToken(tokens, ref index, ";"); return(new SymbolDecl[] { decl }); } } } else if (Parser.Token(tokens, ref index, "struct") || Parser.Token(tokens, ref index, "class") || Parser.Token(tokens, ref index, "union")) { if (Parser.Token(tokens, ref index, "{")) { if (tokens[index - 2] == "class") { throw new ArgumentException("Failed to parse."); } var decl = new GroupedFieldDecl { Grouping = tokens[index - 2] == "struct" ? Grouping.Struct : Grouping.Union, }; ParseSymbols(tokens, ref index, decl); Parser.EnsureToken(tokens, ref index, "}"); Parser.EnsureToken(tokens, ref index, ";"); return(new SymbolDecl[] { decl }); } else { string name = Parser.EnsureId(tokens, ref index); if (!Parser.Token(tokens, ref index, ";")) { var classDecl = new ClassDecl { ClassType = tokens[index - 2] == "struct" ? ClassType.Struct : tokens[index - 2] == "class" ? ClassType.Class : ClassType.Union, BaseTypes = new List <BaseTypeDecl>(), Name = name, }; if (templateDecl != null) { if (Parser.Token(tokens, ref index, "<")) { if (!Parser.Token(tokens, ref index, ">")) { while (true) { int oldIndex = index; try { templateDecl.Specialization.Add(TypeDecl.EnsureTypeWithoutName(tokens, ref index)); } catch (ArgumentException) { index = oldIndex; Parser.SkipUntilInTemplate(tokens, ref index, ",", ">"); index--; templateDecl.Specialization.Add(new ConstantTypeDecl { Value = tokens .Skip(oldIndex) .Take(index - oldIndex) .Aggregate((a, b) => a + " " + b), }); } if (Parser.Token(tokens, ref index, ">")) { break; } Parser.EnsureToken(tokens, ref index, ","); } } } } Parser.Token(tokens, ref index, "abstract"); if (Parser.Token(tokens, ref index, ":")) { while (true) { Access access = classDecl.ClassType == ClassType.Class ? Access.Private : Access.Public; Parser.Token(tokens, ref index, "virtual"); if (Parser.Token(tokens, ref index, "private")) { access = Access.Private; } else if (Parser.Token(tokens, ref index, "protected")) { access = Access.Protected; } else if (Parser.Token(tokens, ref index, "public")) { access = Access.Public; } Parser.Token(tokens, ref index, "virtual"); classDecl.BaseTypes.Add(new BaseTypeDecl { Access = access, Type = TypeDecl.EnsureTypeWithoutName(tokens, ref index), }); if (!Parser.Token(tokens, ref index, ",")) { break; } } } Parser.EnsureToken(tokens, ref index, "{"); while (true) { if (Parser.Token(tokens, ref index, "}")) { break; } Access access = classDecl.ClassType == ClassType.Class ? Access.Private : Access.Public; if (Parser.Token(tokens, ref index, "private")) { access = Access.Private; Parser.EnsureToken(tokens, ref index, ":"); } else if (Parser.Token(tokens, ref index, "protected")) { access = Access.Protected; Parser.EnsureToken(tokens, ref index, ":"); } else if (Parser.Token(tokens, ref index, "public")) { access = Access.Public; Parser.EnsureToken(tokens, ref index, ":"); } ParseSymbols(tokens, ref index, classDecl, access); } SymbolDecl decl = classDecl; if (templateDecl != null) { templateDecl.Element = decl; decl = templateDecl; } if (Parser.Id(tokens, ref index, out name)) { var varDecl = new VarDecl { Static = false, Name = name, Type = new RefTypeDecl { Name = classDecl.Name, }, }; Parser.EnsureToken(tokens, ref index, ";"); return(new SymbolDecl[] { decl, varDecl }); } else { Parser.EnsureToken(tokens, ref index, ";"); return(new SymbolDecl[] { decl }); } } } } else if (!Parser.Token(tokens, ref index, ";")) { Function function = Function.Function; { int oldIndex = index; string name = null; if (Parser.Id(tokens, ref index, out name)) { if (Parser.Token(tokens, ref index, "(")) { Parser.SkipUntil(tokens, ref index, ")"); if (Parser.Token(tokens, ref index, ";") || Parser.Token(tokens, ref index, "=") || Parser.Token(tokens, ref index, ":") || Parser.Token(tokens, ref index, "{")) { function = Function.Constructor; } } index = oldIndex; } else if (Parser.Token(tokens, ref index, "~")) { function = Function.Destructor; } } if (function == Function.Function) { Virtual virtualFunction = Virtual.Normal; Parser.Token(tokens, ref index, "extern"); Parser.Token(tokens, ref index, "mutable"); if (Parser.Token(tokens, ref index, "virtual")) { virtualFunction = Virtual.Virtual; } else if (Parser.Token(tokens, ref index, "static")) { virtualFunction = Virtual.Static; } Parser.Token(tokens, ref index, "inline"); Parser.Token(tokens, ref index, "__forceinline"); if (Parser.Token(tokens, ref index, "operator")) { TypeDecl returnType = null; { int oldIndex = index; Parser.SkipUntilInTemplate(tokens, ref index, "("); int modify = --index; tokens[modify] = "$"; index = oldIndex; returnType = TypeDecl.EnsureTypeWithoutName(tokens, ref index); if (index != modify) { throw new ArgumentException("Failed to parse."); } tokens[modify] = "("; } var decl = new FuncDecl { Virtual = global::Parser.Virtual.Normal, Name = "operator", Function = function, }; TypeDecl functionType = null; Action <TypeDecl> continuation = null; CallingConvention callingConvention = CallingConvention.Default; TypeDecl.ParseTypeContinueAfterName(tokens, ref index, ref callingConvention, out functionType, out continuation); continuation(returnType); decl.Type = functionType; if (!Parser.Token(tokens, ref index, ";")) { Parser.EnsureToken(tokens, ref index, "{"); Parser.SkipUntil(tokens, ref index, "}"); } if (templateDecl != null) { templateDecl.Element = decl; return(new SymbolDecl[] { templateDecl }); } else { return(new SymbolDecl[] { decl }); } } else { string name = null; TypeDecl type = null; if (TypeDecl.ParseType(tokens, ref index, out type, out name)) { if (name == null) { throw new ArgumentException("Failed to parse."); } if (type is FunctionTypeDecl) { if (Parser.Token(tokens, ref index, "=")) { if (Parser.Token(tokens, ref index, "0")) { virtualFunction = Virtual.Abstract; } else { Parser.EnsureToken(tokens, ref index, "default", "delete"); } } var decl = new FuncDecl { Virtual = virtualFunction, Name = name, Type = type, Function = Function.Function, }; if (!Parser.Token(tokens, ref index, ";")) { Parser.EnsureToken(tokens, ref index, "{"); Parser.SkipUntil(tokens, ref index, "}"); } if (templateDecl != null) { templateDecl.Element = decl; return(new SymbolDecl[] { templateDecl }); } else { return(new SymbolDecl[] { decl }); } } else { if (virtualFunction != Virtual.Normal && virtualFunction != Virtual.Static) { throw new ArgumentException("Failed to parse."); } if (Parser.Token(tokens, ref index, "=")) { Parser.SkipUntil(tokens, ref index, ";"); } else { Parser.EnsureToken(tokens, ref index, ";"); } var decl = new VarDecl { Static = virtualFunction == Virtual.Static, Name = name, Type = type, }; return(new SymbolDecl[] { decl }); } } } } else { var decl = new FuncDecl { Virtual = global::Parser.Virtual.Normal, Name = (function == Function.Constructor ? "" : "~") + Parser.EnsureId(tokens, ref index), Function = function, }; TypeDecl functionType = null; Action <TypeDecl> continuation = null; CallingConvention callingConvention = CallingConvention.Default; TypeDecl.ParseTypeContinueAfterName(tokens, ref index, ref callingConvention, out functionType, out continuation); continuation(new RefTypeDecl { Name = "void" }); decl.Type = functionType; if (Parser.Token(tokens, ref index, "=")) { Parser.EnsureToken(tokens, ref index, "default", "delete"); } if (!Parser.Token(tokens, ref index, ";")) { if (Parser.Token(tokens, ref index, ":")) { Parser.SkipUntil(tokens, ref index, "{"); } else { Parser.EnsureToken(tokens, ref index, "{"); } Parser.SkipUntil(tokens, ref index, "}"); } return(new SymbolDecl[] { decl }); } } return(null); }