public void TestBalanceSkip() { // skip JavaCodeParser parser1 = new JavaCodeParser("simple;D"); parser1.SkipToIfBalanced(';'); Assert.AreEqual(';', parser1.Char); Assert.AreEqual('D', parser1.Next()); JavaCodeParser parser2 = new JavaCodeParser("find ( ;semicolon {[ ( ; ) ; ]} ; keep looking ) ;-)"); parser2.SkipToIfBalanced(';'); Assert.AreEqual(';', parser2.Char); Assert.AreEqual('-', parser2.Next()); Assert.AreEqual(')', parser2.Next()); JavaCodeParser parser3 = new JavaCodeParser("nope"); parser3.SkipToIfBalanced(';'); Assert.AreEqual('n', parser3.Char); JavaCodeParser parser4 = new JavaCodeParser("cannot find (;;;)"); parser4.SkipToIfBalanced(';'); Assert.AreEqual('c', parser4.Char); JavaCodeParser parser5 = new JavaCodeParser("( invalid [ balance ) ] ;"); parser5.SkipToIfBalanced(';'); Assert.AreEqual('(', parser5.Char); // read JavaCodeParser parser6 = new JavaCodeParser("these (are) contents; abc"); JavaCodeParser readBlock6 = parser6.ReadToIfBalanced(';'); Assert.AreEqual("these (are) contents", readBlock6.Contents); Assert.AreEqual(';', parser6.Char); JavaCodeParser parser7 = new JavaCodeParser("cannot find"); Assert.AreEqual(string.Empty, parser7.ReadToIfBalanced(';').Contents); }
public void TestAnnotations() { Annotation? annotation1 = new JavaCodeParser("@SimpleAnnotation").ReadAnnotation(); Assert.IsTrue(annotation1.HasValue); Assert.AreEqual("SimpleAnnotation", annotation1.Value.SimpleName); Annotation? annotation2 = new JavaCodeParser("@ AnnotationWithSpace ").ReadAnnotation(); Assert.IsTrue(annotation2.HasValue); Assert.AreEqual("AnnotationWithSpace", annotation2.Value.SimpleName); Annotation? annotation3 = new JavaCodeParser("@full.name.Annotation").ReadAnnotation(); Assert.IsTrue(annotation3.HasValue); Assert.AreEqual("Annotation", annotation3.Value.SimpleName); Annotation? annotation4 = new JavaCodeParser("@AnnotationWithArguments(var = true, other = 15)").ReadAnnotation(); Assert.IsTrue(annotation4.HasValue); Assert.AreEqual("AnnotationWithArguments", annotation4.Value.SimpleName); Annotation? annotation5 = new JavaCodeParser("@ all.Combined (var = '') ").ReadAnnotation(); Assert.IsTrue(annotation5.HasValue); Assert.AreEqual("Combined", annotation5.Value.SimpleName); Annotation? annotation6 = new JavaCodeParser("Invalid").ReadAnnotation(); Assert.IsFalse(annotation6.HasValue); Annotation? annotation7 = new JavaCodeParser("@").ReadAnnotation(); Assert.IsFalse(annotation7.HasValue); Annotation? annotation8 = new JavaCodeParser("@123").ReadAnnotation(); Assert.IsFalse(annotation8.HasValue); }
private static void ReadPackage(JavaCodeParser parser, JavaFileInfo info) { parser.SkipSpaces(); parser.SkipReadAnnotationList(); parser.SkipSpaces(); info.Package = parser.ReadPackageDeclaration(); }
private static void ReadImportList(JavaCodeParser parser, JavaFileInfo info) { while (true) { parser.SkipSpaces(); Import?import = parser.ReadImportDeclaration(); if (!import.HasValue) { break; } info.Imports.Add(import.Value); } }
public JavaFileInfo Process(File file) { JavaFileInfo info = new JavaFileInfo(); fileInfo.Add(file, info); JavaCodeParser parser = new JavaCodeParser(JavaParseUtils.PrepareCodeFile(file.Contents)); parser.AnnotationCallback += IncrementAnnotation; parser.CodeBlockCallback += blockParser => ReadCodeBlock(blockParser, GlobalInfo); ReadPackage(parser, info); ReadImportList(parser, info); ReadTopLevelTypes(parser, info); UpdateLocalData(info); return info; }
public JavaFileInfo Process(File file) { JavaFileInfo info = new JavaFileInfo(); fileInfo.Add(file, info); JavaCodeParser parser = new JavaCodeParser(JavaParseUtils.PrepareCodeFile(file.Contents)); parser.AnnotationCallback += IncrementAnnotation; parser.CodeBlockCallback += blockParser => ReadCodeBlock(blockParser, GlobalInfo); ReadPackage(parser, info); ReadImportList(parser, info); ReadTopLevelTypes(parser, info); UpdateLocalData(info); return(info); }
private static void ReadTopLevelTypes(JavaCodeParser parser, JavaFileInfo info) { while (true) { parser.SkipSpaces(); if (parser.IsEOF) { break; } Type type = parser.ReadType(); if (type != null) { info.Types.Add(type); } else { break; } } }
private static void ReadCodeBlock(JavaCodeBlockParser blockParser, JavaGlobalInfo info) { string keyword; while((keyword = blockParser.ReadNextKeywordSkip()).Length > 0){ switch(keyword){ case "do": ReadCodeBlock((JavaCodeBlockParser)blockParser.ReadBlock('{', '}'), info); if (blockParser.ReadNextKeywordSkip() != "while"){ blockParser.RevertKeywordSkip(); // should not happen } ++info.Statements[FlowStatement.DoWhile]; break; case "while": ++info.Statements[FlowStatement.While]; break; case "for": JavaCodeBlockParser cycleDeclBlock = (JavaCodeBlockParser)blockParser.ReadBlock('(', ')'); ReadCodeBlock(cycleDeclBlock, info); JavaCodeParser cycleDeclParser = new JavaCodeParser(cycleDeclBlock.Contents); cycleDeclParser.ReadTypeOf(false); cycleDeclParser.SkipSpaces().ReadIdentifier(); ++info.Statements[cycleDeclParser.SkipSpaces().Char == ':' ? FlowStatement.EnhancedFor : FlowStatement.For]; break; case "switch": JavaCodeBlockParser switchBlock = (JavaCodeBlockParser)blockParser.ReadBlock('{', '}'); ReadCodeBlock(switchBlock, info); switchBlock.Reset(); string switchKeyword; int cases = 0; while((switchKeyword = switchBlock.ReadNextKeywordSkip()).Length > 0){ if (switchKeyword == "switch"){ switchBlock.SkipBlock('{', '}'); } else if (switchKeyword == "case"){ ++info.Statements[FlowStatement.SwitchCase]; ++cases; } else if (switchKeyword == "default"){ ++info.Statements[FlowStatement.SwitchDefault]; // TODO count as a case? } } if (cases < info.MinSwitchCases)info.MinSwitchCases = cases; if (cases > info.MaxSwitchCases)info.MaxSwitchCases = cases; ++info.Statements[FlowStatement.Switch]; break; case "try": bool isTryWithResources = blockParser.SkipSpaces().Char == '('; ReadCodeBlock((JavaCodeBlockParser)blockParser.ReadBlock('{', '}'), info); string tryKeyword; int catches = 0; while((tryKeyword = blockParser.ReadNextKeywordSkip()).Length > 0){ if (tryKeyword == "catch"){ ++info.Statements[FlowStatement.Catch]; ++catches; } else if (tryKeyword == "finally"){ ++info.Statements[FlowStatement.Finally]; if (isTryWithResources)++info.TryWithResourcesWithFinally; else ++info.TryCatchWithFinally; } else if (tryKeyword != "try"){ blockParser.RevertKeywordSkip(); break; } ReadCodeBlock((JavaCodeBlockParser)blockParser.ReadBlock('{', '}'), info); } if (catches < info.MinCatchBlocks)info.MinCatchBlocks = catches; if (catches > info.MaxCatchBlocks)info.MaxCatchBlocks = catches; ++info.Statements[isTryWithResources ? FlowStatement.TryWithResources : FlowStatement.TryCatch]; ++info.Statements[FlowStatement.Try]; break; case "if": ++info.Statements[FlowStatement.If]; break; case "else": ++info.Statements[FlowStatement.Else]; if (blockParser.ReadNextKeywordSkip() != "if"){ blockParser.RevertKeywordSkip(); } break; case "return": ++info.Statements[FlowStatement.Return]; break; case "continue": ++info.Statements[FlowStatement.Continue]; break; case "break": ++info.Statements[FlowStatement.Break]; break; } } }
private static void ReadTopLevelTypes(JavaCodeParser parser, JavaFileInfo info) { while(true){ parser.SkipSpaces(); if (parser.IsEOF)break; Type type = parser.ReadType(); if (type != null)info.Types.Add(type); else break; } }
private static void ReadPackage(JavaCodeParser parser, JavaFileInfo info) { parser.SkipSpaces(); parser.SkipReadAnnotationList(); parser.SkipSpaces(); info.Package = parser.ReadPackageDeclaration(); }
private static void ReadImportList(JavaCodeParser parser, JavaFileInfo info) { while(true){ parser.SkipSpaces(); Import? import = parser.ReadImportDeclaration(); if (!import.HasValue)break; info.Imports.Add(import.Value); } }
private static void ReadCodeBlock(JavaCodeBlockParser blockParser, JavaGlobalInfo info) { string keyword; while ((keyword = blockParser.ReadNextKeywordSkip()).Length > 0) { switch (keyword) { case "do": ReadCodeBlock((JavaCodeBlockParser)blockParser.ReadBlock('{', '}'), info); if (blockParser.ReadNextKeywordSkip() != "while") { blockParser.RevertKeywordSkip(); // should not happen } ++info.Statements[FlowStatement.DoWhile]; break; case "while": ++info.Statements[FlowStatement.While]; break; case "for": JavaCodeBlockParser cycleDeclBlock = (JavaCodeBlockParser)blockParser.ReadBlock('(', ')'); ReadCodeBlock(cycleDeclBlock, info); JavaCodeParser cycleDeclParser = new JavaCodeParser(cycleDeclBlock.Contents); cycleDeclParser.ReadTypeOf(false); cycleDeclParser.SkipSpaces().ReadIdentifier(); ++info.Statements[cycleDeclParser.SkipSpaces().Char == ':' ? FlowStatement.EnhancedFor : FlowStatement.For]; break; case "switch": JavaCodeBlockParser switchBlock = (JavaCodeBlockParser)blockParser.ReadBlock('{', '}'); ReadCodeBlock(switchBlock, info); switchBlock.Reset(); string switchKeyword; int cases = 0; while ((switchKeyword = switchBlock.ReadNextKeywordSkip()).Length > 0) { if (switchKeyword == "switch") { switchBlock.SkipBlock('{', '}'); } else if (switchKeyword == "case") { ++info.Statements[FlowStatement.SwitchCase]; ++cases; } else if (switchKeyword == "default") { ++info.Statements[FlowStatement.SwitchDefault]; // TODO count as a case? } } if (cases < info.MinSwitchCases) { info.MinSwitchCases = cases; } if (cases > info.MaxSwitchCases) { info.MaxSwitchCases = cases; } ++info.Statements[FlowStatement.Switch]; break; case "try": bool isTryWithResources = blockParser.SkipSpaces().Char == '('; ReadCodeBlock((JavaCodeBlockParser)blockParser.ReadBlock('{', '}'), info); string tryKeyword; int catches = 0; while ((tryKeyword = blockParser.ReadNextKeywordSkip()).Length > 0) { if (tryKeyword == "catch") { ++info.Statements[FlowStatement.Catch]; ++catches; } else if (tryKeyword == "finally") { ++info.Statements[FlowStatement.Finally]; if (isTryWithResources) { ++info.TryWithResourcesWithFinally; } else { ++info.TryCatchWithFinally; } } else if (tryKeyword != "try") { blockParser.RevertKeywordSkip(); break; } ReadCodeBlock((JavaCodeBlockParser)blockParser.ReadBlock('{', '}'), info); } if (catches < info.MinCatchBlocks) { info.MinCatchBlocks = catches; } if (catches > info.MaxCatchBlocks) { info.MaxCatchBlocks = catches; } ++info.Statements[isTryWithResources ? FlowStatement.TryWithResources : FlowStatement.TryCatch]; ++info.Statements[FlowStatement.Try]; break; case "if": ++info.Statements[FlowStatement.If]; break; case "else": ++info.Statements[FlowStatement.Else]; if (blockParser.ReadNextKeywordSkip() != "if") { blockParser.RevertKeywordSkip(); } break; case "return": ++info.Statements[FlowStatement.Return]; break; case "continue": ++info.Statements[FlowStatement.Continue]; break; case "break": ++info.Statements[FlowStatement.Break]; break; } } }
/// <summary> /// Recursively reads all members of a Type, including all nested Types. Called on a cloned JavaCodeParser that only /// contains contents of the Type block. /// </summary> private void ReadTypeContents(Type type) { // enum values if (type.Declaration == Type.DeclarationType.Enum){ Type.DataEnum enumData = type.GetData<Type.DataEnum>(); JavaCodeParser enumParser = ReadToIfBalanced(';'); if (enumParser.Contents.Length == 0)enumParser = this; foreach(string enumValue in enumParser.ReadEnumValueList()){ enumData.EnumValues.Add(enumValue); } if (Char == ';')Skip(); } // members int skippedMembers = 0; while(!IsEOF && skippedMembers < 50){ Member memberInfo = SkipReadMemberInfo(); // skips spaces at the beginning and end // nested types Type.DeclarationType? declaration = ReadTypeDeclaration(); if (declaration.HasValue){ string identifier = SkipSpaces().ReadIdentifier(); if (identifier.Length == 0)break; // error, break out Type nestedType = new Type(declaration.Value, identifier, memberInfo); ((JavaCodeParser)SkipTo('{').ReadBlock('{', '}')).ReadTypeContents(nestedType); SkipSpacesAndSemicolons(); type.NestedTypes.Add(nestedType); continue; } // static / instance initializer if (Char == '{'){ Method method = new Method(memberInfo.Modifiers.HasFlag(Modifiers.Static) ? "<clinit>" : "<init>", TypeOf.Void(), memberInfo); SkipProcessCodeBlock(); type.GetData().Methods.Add(method); continue; } // fields and methods TypeOf? returnOrFieldType = ReadTypeOf(false); if (returnOrFieldType.HasValue){ int prevCursor = cursor; string identifier = SkipSpaces().ReadIdentifier(); if (identifier.Length == 0 && string.Equals(returnOrFieldType.Value.AsSimpleType(), type.Identifier)){ // constructor identifier = Method.ConstructorIdentifier; returnOrFieldType = TypeOf.Void(); } if (identifier.Length == 0)break; // error, break out if (SkipSpaces().Char == '('){ // method List<TypeOf> parameterList = ((JavaCodeParser)ReadBlock('(', ')')).ReadMethodParameterList(); if (type.Declaration == Type.DeclarationType.Annotation){ if (SkipSpaces().SkipIfMatch("default^n")){ memberInfo = new Member(memberInfo, memberInfo.Modifiers | Modifiers.Default); SkipTo(';'); } } else{ if (SkipSpaces().SkipIfMatch("throws^s")){ while(true){ ReadFullTypeName(); if (SkipSpaces().Char == ',')Skip().SkipSpaces(); else break; } } } if (Char == ';')Skip(); else{ SkipProcessCodeBlock(); SkipSpacesAndSemicolons(); } type.GetData().Methods.Add(new Method(identifier, returnOrFieldType.Value, parameterList, type.GetData().UpdateMethodInfo(memberInfo))); } else{ // field Type.TypeData data = type.GetData(); cursor = prevCursor; foreach(string fieldIdentifier in ReadToIfBalanced(';').ReadFieldIdentifierList()){ data.Fields.Add(new Field(fieldIdentifier, returnOrFieldType.Value, data.UpdateFieldInfo(memberInfo))); } Skip(); } continue; } // extra checks before the skip if (Char == ';'){ Skip(); continue; } if (IsEOF)break; // skip if (skippedMembers == 0){ System.Diagnostics.Debugger.Break(); } SkipBlock('{', '}'); SkipSpacesAndSemicolons(); ++skippedMembers; } }