Skip to content

Commit c9ff08c

Browse files
committed
0.14.2 - Fixed issue parsing C# and Java classes that extend/implement multiple types, these are now parsed and returned in the correct order
1 parent 53806a5 commit c9ff08c

23 files changed

+162
-107
lines changed

CHANGELOG.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,17 @@ This project does its best to adhere to [Semantic Versioning](http://semver.org/
44

55

66
--------
7-
###[0.14.1](N/A) - 2016-12-03
7+
###[0.14.2](N/A) - 2017-02-06
8+
#### Changed
9+
* Removed lombok.val usage/dependency from from test classes.
10+
11+
#### Fixed
12+
* Fixed parsing C# classes that extend/implement multiple types, unrecognized types are assumed to possibly be interfaces.
13+
* Fixed parsing Java classes that implement multiple types, unrecognized types are assumed to possibly be interfaces.
14+
15+
16+
--------
17+
###[0.14.1](https://github.com/TeamworkGuy2/JParseCode/commit/53806a53d3b8152b35e3166a81dbe9a81a49f354) - 2016-12-03
818
#### Changed
919
* Updated dependencies to latest versions: jtext-parser@0.11.0, jtext-tokenizer@0.2.0, jparser-primitive@0.2.0
1020
* This includes a new parsing strategy which tries to parse non-compound tokens from start to finish using one parser at a time without passing the characters to compound parser, this improves performance and simplifies some of the compound parsers, but makes some compound parsers more difficult, such as ending conditions that try to keep track of characters between the start and end of the compound parser segment

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
JParseCode
22
==============
3-
version: 0.14.1
3+
version: 0.14.2
44

55
In progress C#/Java/TypeScript parser tools built atop [JTextParser] (https://github.com/TeamworkGuy2/JTextParser), [Jackson] (https://github.com/FasterXML/jackson-core/) (core, databind, annotations) and half a dozen other utility libraries.
66

bin/jparse_code-with-tests.jar

-692 Bytes
Binary file not shown.

bin/jparse_code.jar

-1.06 KB
Binary file not shown.

package-lib.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version" : "0.14.1",
2+
"version" : "0.14.2",
33
"name" : "jparse-code",
44
"description" : "An in-progress suite of parsing/transpilation tools for C#, Java, and TypeScript code. Generates simple JSON ASTs.",
55
"homepage" : "https://github.com/TeamworkGuy2/JParseCode",

rsc/csharp/ParserExamples/Models/TrackInfo.cs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Runtime.Serialization;
23

34
namespace ParserExamples.Models {
@@ -9,7 +10,7 @@ namespace ParserExamples.Models {
910
/// This class is mutable. And it is not thread-safe.
1011
/// </threadsafety>
1112
[DataContract]
12-
public class TrackInfo {
13+
public class TrackInfo : ISerializable, IComparable<TrackInfo> {
1314

1415
/// <value>The track name.</value>
1516
[DataMember]
@@ -25,6 +26,15 @@ public class TrackInfo {
2526
/// <value>The track duration in milliseconds</value>
2627
public long contentId;
2728

29+
30+
public int CompareTo(Implementer other) {
31+
return other != null ? (this.Name != null ? this.Name.CompareTo(other.Name) : (other.Name != null ? 1 : 0)) : (this.Name != null ? -1 : 0);
32+
}
33+
34+
35+
public void GetObjectData(SerializationInfo info, StreamingContext context) {
36+
}
37+
2838
}
2939

3040
}

rsc/java/ParserExamples/Models/TrackInfo.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package ParserExamples.Models;
22

3+
import java.io.Serializable;
4+
35
import System.Runtime.Serialization;
46

57
/// <summary>
@@ -9,7 +11,7 @@
911
/// This class is mutable. And it is not thread-safe.
1012
/// </threadsafety>
1113
[DataContract]
12-
public class TrackInfo {
14+
public class TrackInfo implements Serializable, Comparable<TrackInfo> {
1315

1416
/// <value>The track name.</value>
1517
@DataMember
@@ -25,4 +27,10 @@ public class TrackInfo {
2527
/// <value>The track duration in milliseconds</value>
2628
public long contentId;
2729

30+
31+
@Override
32+
public int compareTo(TrackInfo o) {
33+
return other != null ? (this.Name != null ? this.Name.CompareTo(other.Name) : (other.Name != null ? 1 : 0)) : (this.Name != null ? -1 : 0);
34+
}
35+
2836
}

src/twg2/parser/codeParser/KeywordUtil.java

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ public interface KeywordUtil<T_KEYWORD extends AccessModifier> {
2020
*/
2121
public T_KEYWORD tryToKeyword(String str);
2222

23+
/** Check if a string is an inheritance keyword (i.e. ':' in C# or 'extends' and 'implements' in Java and TypeScript */
24+
public boolean isInheritanceKeyword(String str);
25+
2326
/** Check if a string is a keyword */
2427
public boolean isKeyword(String str);
2528

src/twg2/parser/codeParser/csharp/CsBlockParser.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -181,17 +181,18 @@ private static Entry<String, List<String>> readClassIdentifierAndExtends(Enhance
181181
SimpleTree<CodeToken> prevNode = iter.hasPrevious() ? iter.previous() : null;
182182

183183
// TODO should read ', ' between each name, currently only works with 1 extend/implement class name
184-
while(prevNode != null && AstFragType.isIdentifierOrKeyword(prevNode.getData()) && !lang.getKeywordUtil().blockModifiers().is(prevNode.getData())) {
184+
while(prevNode != null && AstFragType.isIdentifierOrKeyword(prevNode.getData()) && !lang.getKeywordUtil().blockModifiers().is(prevNode.getData()) && !lang.getKeywordUtil().isInheritanceKeyword(prevNode.getData().getText())) {
185185
names.add(prevNode.getData().getText());
186186
prevNode = iter.hasPrevious() ? iter.previous() : null;
187187
if(iter.hasPrevious()) { prevCount++; }
188188
}
189189

190190
// if the class signature extends/implements, then the identifiers just read are the class/interface names, next read the actual class name
191-
if(prevNode != null && prevNode.getData().getText().trim().equals(":")) {
191+
if(prevNode != null && prevNode.getData().getText().equals(":")) {
192192
prevNode = iter.hasPrevious() ? iter.previous() : null;
193193
if(iter.hasPrevious()) { prevCount++; }
194194
if(prevNode != null && AstFragType.isIdentifierOrKeyword(prevNode.getData()) && !lang.getKeywordUtil().blockModifiers().is(prevNode.getData())) {
195+
Collections.reverse(names);
195196
val extendImplementNames = names;
196197
val className = prevNode.getData().getText();
197198
nameCompoundRes = Tuples.of(className, extendImplementNames);

src/twg2/parser/codeParser/csharp/CsKeyword.java

+6
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,12 @@ public CsKeyword tryToKeyword(String str) {
211211
}
212212

213213

214+
@Override
215+
public boolean isInheritanceKeyword(String str) {
216+
return ":".equals(str);
217+
}
218+
219+
214220
@Override
215221
public boolean isKeyword(String str) {
216222
return Arrays.binarySearch(keywords, str) > -1;

src/twg2/parser/codeParser/java/JavaBlockParser.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ private static Entry<String, List<String>> readClassIdentifierAndExtends(Enhance
206206
SimpleTree<CodeToken> prevNode = iter.hasPrevious() ? iter.previous() : null;
207207

208208
// TODO should read ', ' between each name, currently only works with 1 extend/implement class name
209-
while(prevNode != null && AstFragType.isIdentifierOrKeyword(prevNode.getData()) && !lang.getKeywordUtil().blockModifiers().is(prevNode.getData())) {
209+
while(prevNode != null && AstFragType.isIdentifierOrKeyword(prevNode.getData()) && !lang.getKeywordUtil().blockModifiers().is(prevNode.getData()) && !lang.getKeywordUtil().isInheritanceKeyword(prevNode.getData().getText())) {
210210
names.add(prevNode.getData().getText());
211211
prevNode = iter.hasPrevious() ? iter.previous() : null;
212212
if(iter.hasPrevious()) { prevCount++; }
@@ -217,6 +217,7 @@ private static Entry<String, List<String>> readClassIdentifierAndExtends(Enhance
217217
prevNode = iter.hasPrevious() ? iter.previous() : null;
218218
if(iter.hasPrevious()) { prevCount++; }
219219
if(prevNode != null && AstFragType.isIdentifierOrKeyword(prevNode.getData()) && !lang.getKeywordUtil().blockModifiers().is(prevNode.getData())) {
220+
Collections.reverse(names);
220221
val extendImplementNames = names;
221222
val className = prevNode.getData().getText();
222223
nameCompoundRes = Tuples.of(className, extendImplementNames);

src/twg2/parser/codeParser/java/JavaKeyword.java

+6
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@ public JavaKeyword tryToKeyword(String str) {
180180
}
181181

182182

183+
@Override
184+
public boolean isInheritanceKeyword(String str) {
185+
return EXTENDS.srcName.equals(str) || IMPLEMENTS.srcName.equals(str);
186+
}
187+
188+
183189
@Override
184190
public boolean isKeyword(String str) {
185191
return Arrays.binarySearch(keywords, str) > -1;

src/twg2/parser/main/MainParser.java

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import twg2.io.files.FileReadUtil;
1919
import twg2.parser.codeParser.analytics.PerformanceTrackers;
2020
import twg2.parser.codeParser.csharp.CsBlock;
21+
import twg2.parser.codeParser.test.JavaClassParseTest;
2122
import twg2.parser.codeParser.tools.NameUtil;
2223
import twg2.parser.language.CodeLanguage;
2324
import twg2.parser.output.WriteSettings;
@@ -76,6 +77,12 @@ public static void parseAndValidProjectCsClasses(FileReadUtil fileReader) throws
7677

7778

7879
public static void main(String[] args) throws IOException, FileFormatException {
80+
new JavaClassParseTest().parseBlocksTest();
81+
82+
if(3/1.4 > 1.6) {
83+
return;
84+
}
85+
7986
boolean multithread = false;
8087
boolean logPerformance = false;
8188
ExecutorService executor = multithread ? Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()) : null;

src/twg2/parser/resolver/ClassSigResolver.java

+15-13
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,30 @@ public class ClassSigResolver {
2727
*/
2828
public static <T_ID, T_SIG extends ClassSig.SimpleImpl> ClassSig.ResolvedImpl resolveClassSigFrom(KeywordUtil<? extends AccessModifier> keywordUtil, T_SIG classSig, ClassAst.SimpleImpl<? extends BlockType> namespaceClass,
2929
ProjectClassSet.Simple<T_ID, ? extends BlockType> projFiles, BlockType defaultBlockType, Collection<List<String>> missingNamespacesDst) {
30-
List<List<String>> resolvedCompilationUnitNames = new ArrayList<>();
31-
List<BlockType> resolvedCompilationUnitBlockTypes = new ArrayList<>();
30+
List<List<String>> resolvedParentNames = new ArrayList<>();
31+
List<BlockType> resolvedParentBlockTypess = new ArrayList<>();
3232
val classExtendImplementNames = classSig.getExtendImplementSimpleNames();
3333

3434
if(classExtendImplementNames != null) {
3535
for(val simpleName : classExtendImplementNames) {
3636
val resolvedClass = projFiles.resolveSimpleNameToClass(simpleName, namespaceClass, missingNamespacesDst);
3737
if(resolvedClass != null) {
38-
resolvedCompilationUnitBlockTypes.add(resolvedClass.getBlockType());
39-
resolvedCompilationUnitNames.add(resolvedClass.getSignature().getFullName());
38+
resolvedParentBlockTypess.add(resolvedClass.getBlockType());
39+
resolvedParentNames.add(resolvedClass.getSignature().getFullName());
4040
}
4141
else {
42-
resolvedCompilationUnitBlockTypes.add(defaultBlockType);
43-
resolvedCompilationUnitNames.add(new ArrayList<>(Arrays.asList(simpleName)));
42+
resolvedParentBlockTypess.add(defaultBlockType);
43+
resolvedParentNames.add(new ArrayList<>(Arrays.asList(simpleName)));
4444
}
4545
}
4646
}
4747

4848
// check the extends/implements name list, ensure that the first
4949
TypeSig.TypeSigResolved extendClassType = null;
5050
List<TypeSig.TypeSigResolved> implementInterfaceTypes = Collections.emptyList();
51-
if(resolvedCompilationUnitNames.size() > 0) {
52-
val firstCompilationUnitName = resolvedCompilationUnitNames.get(0);
53-
val firstCompilationUnitBlockType = resolvedCompilationUnitBlockTypes.get(0);
51+
if(resolvedParentNames.size() > 0) {
52+
val firstCompilationUnitName = resolvedParentNames.get(0);
53+
val firstCompilationUnitBlockType = resolvedParentBlockTypess.get(0);
5454
boolean extendsClass = false;
5555
// Get the extends class name
5656
// TODO maybe should check isClass() rather than !isInterface()
@@ -61,13 +61,15 @@ public static <T_ID, T_SIG extends ClassSig.SimpleImpl> ClassSig.ResolvedImpl re
6161
extendsClass = true;
6262
}
6363
// Get the implements interface names
64-
if(resolvedCompilationUnitBlockTypes.size() > (extendsClass ? 1 : 0)) {
64+
if(resolvedParentBlockTypess.size() > (extendsClass ? 1 : 0)) {
6565
implementInterfaceTypes = new ArrayList<>();
66-
for(int i = extendsClass ? 1 : 0, size = resolvedCompilationUnitBlockTypes.size(); i < size; i++) {
67-
if(!resolvedCompilationUnitBlockTypes.get(i).isInterface()) {
66+
for(int i = extendsClass ? 1 : 0, size = resolvedParentBlockTypess.size(); i < size; i++) {
67+
// if the extend/implement type is not a recognized interface and the name is resolved (resolved names are longer than 1 part, since all classes should come from a namespace)
68+
// assume that unresolved names could be interfaces and don't count them against the 1 extend class limit
69+
if(!resolvedParentBlockTypess.get(i).isInterface() && resolvedParentNames.get(i).size() > 1) {
6870
throw new IllegalStateException("class cannot extend more than one class (checking extends/implements list: " + classSig.getExtendImplementSimpleNames() + ") for class '" + classSig.getFullName() + "'");
6971
}
70-
val name = NameUtil.joinFqName(resolvedCompilationUnitNames.get(i));
72+
val name = NameUtil.joinFqName(resolvedParentNames.get(i));
7173
val implementInterfaceSimpleType = DataTypeExtractor.extractGenericTypes(name, keywordUtil);
7274
val implementInterfaceType = TypeSigResolver.resolveFrom(implementInterfaceSimpleType, namespaceClass, projFiles, missingNamespacesDst);
7375
implementInterfaceTypes.add(implementInterfaceType);

test/twg2/parser/codeParser/test/CsClassParseTest.java

+11-8
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
import java.nio.file.Paths;
55
import java.util.Arrays;
66
import java.util.List;
7-
8-
import lombok.val;
7+
import java.util.Map.Entry;
98

109
import org.junit.Assert;
1110
import org.junit.Test;
1211
import org.junit.runners.Parameterized.Parameter;
1312

13+
import twg2.ast.interm.classes.ClassAst;
1414
import twg2.ast.interm.field.FieldSig;
1515
import twg2.ast.interm.method.MethodSig;
1616
import twg2.ast.interm.method.ParameterSig;
@@ -20,11 +20,14 @@
2020
import twg2.parser.codeParser.csharp.CsBlockParser;
2121
import twg2.parser.codeParser.csharp.CsKeyword;
2222
import twg2.parser.codeParser.tools.NameUtil;
23+
import twg2.parser.fragment.CodeToken;
2324
import twg2.parser.language.CodeLanguage;
2425
import twg2.parser.language.CodeLanguageOptions;
2526
import twg2.parser.main.ParseCodeFile;
2627
import twg2.parser.test.utils.CodeFileAndAst;
28+
import twg2.parser.workflow.CodeFileParsed;
2729
import twg2.parser.workflow.CodeFileSrc;
30+
import twg2.treeLike.simpleTree.SimpleTree;
2831
import static twg2.parser.test.utils.ParseAnnotationAssert.*;
2932

3033
/**
@@ -110,23 +113,23 @@ public CsClassParseTest() throws IOException {
110113

111114
@Test
112115
public void parseBlocksTest() {
113-
val tree = file.getDoc();
114-
val blocks = new CsBlockParser().extractClassFieldsAndMethodSignatures(tree);
116+
SimpleTree<CodeToken> tree = file.getDoc();
117+
List<Entry<SimpleTree<CodeToken>, ClassAst.SimpleImpl<CsBlock>>> blocks = new CsBlockParser().extractClassFieldsAndMethodSignatures(tree);
115118

116119
Assert.assertEquals(1, blocks.size());
117120

118-
val trackInfoBlock = blocks.get(0).getValue();
121+
ClassAst.SimpleImpl<CsBlock> trackInfoBlock = blocks.get(0).getValue();
119122
Assert.assertEquals(CsBlock.CLASS, trackInfoBlock.getBlockType());
120123
Assert.assertEquals("TrackInfo", trackInfoBlock.getSignature().getSimpleName());
121124
}
122125

123126

124127
@Test
125128
public void simpleCsParseTest() {
126-
val blocks = simpleCs.parsedBlocks;
127-
val fullClassName = simpleCs.fullClassName;
129+
List<CodeFileParsed.Simple<String, CsBlock>> blocks = simpleCs.parsedBlocks;
130+
String fullClassName = simpleCs.fullClassName;
128131
Assert.assertEquals(1, blocks.size());
129-
val clas = blocks.get(0).getParsedClass();
132+
ClassAst.SimpleImpl<CsBlock> clas = blocks.get(0).getParsedClass();
130133
Assert.assertEquals(8, clas.getFields().size());
131134

132135
Assert.assertEquals(fullClassName, NameUtil.joinFqName(clas.getSignature().getFullName()));

test/twg2/parser/codeParser/test/CsEnumParseTest.java

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
package twg2.parser.codeParser.test;
22

33
import java.util.Arrays;
4-
5-
import lombok.val;
4+
import java.util.List;
65

76
import org.junit.Assert;
87
import org.junit.Test;
98

9+
import twg2.ast.interm.classes.ClassAst;
10+
import twg2.ast.interm.field.FieldDef;
1011
import twg2.ast.interm.field.FieldSig;
1112
import twg2.parser.codeParser.AccessModifierEnum;
1213
import twg2.parser.codeParser.csharp.CsBlock;
1314
import twg2.parser.codeParser.tools.NameUtil;
1415
import twg2.parser.language.CodeLanguageOptions;
1516
import twg2.parser.test.utils.CodeFileAndAst;
17+
import twg2.parser.workflow.CodeFileParsed;
1618

1719
/**
1820
* @author TeamworkGuy2
@@ -39,11 +41,11 @@ public class CsEnumParseTest {
3941

4042
@Test
4143
public void simpleEnumCsParseTest() {
42-
val blocks = simpleEnumCs.parsedBlocks;
43-
val fullClassName = simpleEnumCs.fullClassName;
44+
List<CodeFileParsed.Simple<String, CsBlock>> blocks = simpleEnumCs.parsedBlocks;
45+
String fullClassName = simpleEnumCs.fullClassName;
4446
Assert.assertEquals(1, blocks.size());
45-
val clas = blocks.get(0).getParsedClass();
46-
val enums = clas.getEnumMembers();
47+
ClassAst.SimpleImpl<CsBlock> clas = blocks.get(0).getParsedClass();
48+
List<FieldDef> enums = clas.getEnumMembers();
4749
Assert.assertEquals(3, enums.size());
4850

4951
Assert.assertEquals(fullClassName, NameUtil.joinFqName(clas.getSignature().getFullName()));

0 commit comments

Comments
 (0)