3636/** A Java port of <a href="https://github.com/Constellation/doctrine">doctrine</a>. */
3737public class JSDocParser {
3838 private String source ;
39+ private int absoluteOffset ;
3940
4041 /** Parse the given string as a JSDoc comment. */
4142 public JSDocComment parse (Comment comment ) {
4243 source = comment .getText ();
4344 JSDocTagParser p = new JSDocTagParser ();
44- Pair <String , List <JSDocTagParser .Tag >> r = p .new TagParser (null ).parseComment ();
45+ Position startPos = comment .getLoc ().getStart ();
46+ // Get the start of the first line relative to the 'source' string.
47+ // This occurs before the start of 'source', so the lineStart is negative.
48+ int firstLineStart = -(startPos .getColumn () + "/**" .length () - 1 );
49+ this .absoluteOffset = startPos .getOffset ();
50+ Pair <String , List <JSDocTagParser .Tag >> r = p .new TagParser (null ).parseComment (
51+ startPos .getLine () - 1 ,
52+ firstLineStart );
4553 List <JSDocTag > tags = new ArrayList <>();
4654 for (JSDocTagParser .Tag tag : r .snd ()) {
4755 String title = tag .title ;
@@ -52,14 +60,12 @@ public JSDocComment parse(Comment comment) {
5260
5361 JSDocTypeExpression jsdocType = tag .type ;
5462
55- int realStartLine = comment .getLoc ().getStart ().getLine () + startLine ;
56- int realStartColumn =
57- (startLine == 0 ? comment .getLoc ().getStart ().getColumn () + 3 : 0 ) + startColumn ;
63+ int lineNumber = startLine + 1 ; // convert to 1-based
5864 SourceLocation loc =
5965 new SourceLocation (
6066 source ,
61- new Position (realStartLine , realStartColumn , -1 ),
62- new Position (realStartLine , realStartColumn + 1 + title .length (), -1 ));
67+ new Position (lineNumber , startColumn , -1 ),
68+ new Position (lineNumber , startColumn + 1 + title .length (), -1 ));
6369 tags .add (new JSDocTag (loc , title , description , name , jsdocType , tag .errors ));
6470 }
6571 return new JSDocComment (comment , r .fst (), tags );
@@ -223,48 +229,65 @@ private enum Token {
223229 private class TypeExpressionParser {
224230 int startIndex ;
225231 int endIndex ;
226- int previous , index ;
232+ int startOfCurToken , endOfPrevToken , index ;
227233 Token token ;
228234 Object value ;
235+ int lineStart ;
236+ int lineNumber ;
229237
230238 private class Context {
231- int _previous , _index ;
239+ int _startOfCurToken , _endOfPrevToken , _index ;
232240 Token _token ;
233241 Object _value ;
234242
235- Context (int previous , int index , Token token , Object value ) {
236- this ._previous = previous ;
243+ Context (int startOfCurToken , int endOfPrevToken , int index , Token token , Object value ) {
244+ this ._startOfCurToken = startOfCurToken ;
245+ this ._endOfPrevToken = endOfPrevToken ;
237246 this ._index = index ;
238247 this ._token = token ;
239248 this ._value = value ;
240249 }
241250
242251 void restore () {
243- previous = this ._previous ;
252+ startOfCurToken = this ._startOfCurToken ;
253+ endOfPrevToken = this ._endOfPrevToken ;
244254 index = this ._index ;
245255 token = this ._token ;
246256 value = this ._value ;
247257 }
248258 }
249259
250260 Context save () {
251- return new Context (previous , index , token , value );
261+ return new Context (startOfCurToken , endOfPrevToken , index , token , value );
252262 }
253263
254264 private SourceLocation loc () {
255265 return new SourceLocation (pos ());
256266 }
257267
268+ /**
269+ * Returns the absolute position of the start of the current token.
270+ */
258271 private Position pos () {
259- // TEMPORARY: Produce relative positions as the parser originally did
260- return new Position (1 , index + 1 - startIndex , index - startIndex );
272+ return new Position (this .lineNumber + 1 , startOfCurToken - lineStart , startOfCurToken + absoluteOffset );
273+ }
274+
275+ /**
276+ * Returns the absolute position of the end of the previous token.
277+ *
278+ * This can differ from the start of the current token case the two tokens
279+ * are separated by whitespace.
280+ */
281+ private Position endPos () {
282+ return new Position (this .lineNumber + 1 , endOfPrevToken - lineStart , endOfPrevToken + absoluteOffset );
261283 }
262284
263285 private <T extends JSDocTypeExpression > T finishNode (T node ) {
264286 SourceLocation loc = node .getLoc ();
265- Position end = pos ();
266- // TEMPORARY: Assume relative positions as the parser originally did
267- loc .setSource (inputSubstring (loc .getStart ().getOffset () + startIndex , end .getOffset () + startIndex ));
287+ Position end = endPos ();
288+ int relativeStartOffset = loc .getStart ().getOffset () - absoluteOffset ;
289+ int relativeEndOffset = end .getOffset () - absoluteOffset ;
290+ loc .setSource (inputSubstring (relativeStartOffset , relativeEndOffset ));
268291 loc .setEnd (end );
269292 return node ;
270293 }
@@ -546,7 +569,7 @@ private Token scanTypeName() {
546569 private Token next () throws ParseError {
547570 char ch ;
548571
549- previous = index ;
572+ endOfPrevToken = index ;
550573
551574 while (index < endIndex && isWhiteSpace (source .charAt (index ))) {
552575 advance ();
@@ -556,6 +579,8 @@ private Token next() throws ParseError {
556579 return token ;
557580 }
558581
582+ startOfCurToken = index ;
583+
559584 ch = source .charAt (index );
560585 switch (ch ) {
561586 case '"' :
@@ -918,7 +943,7 @@ private List<JSDocTypeExpression> parseParametersType() throws ParseError {
918943 }
919944 if (token == Token .EQUAL ) {
920945 consume (Token .EQUAL );
921- expr = finishNode (new OptionalType (loc , expr ));
946+ expr = finishNode (new OptionalType (new SourceLocation ( loc ) , expr ));
922947 normal = false ;
923948 } else {
924949 if (!normal ) {
@@ -1147,13 +1172,14 @@ private JSDocTypeExpression parseTopParamType() throws ParseError {
11471172 return expr ;
11481173 }
11491174
1150- private JSDocTypeExpression parseType (int startIndex , int endIndex ) throws ParseError {
1175+ private JSDocTypeExpression parseType (int startIndex , int endIndex , int lineStart , int lineNumber ) throws ParseError {
11511176 JSDocTypeExpression expr ;
11521177
1178+ this .lineNumber = lineNumber ;
1179+ this .lineStart = lineStart ;
11531180 this .startIndex = startIndex ;
11541181 this .endIndex = endIndex ;
11551182 index = startIndex ;
1156- previous = startIndex ;
11571183
11581184 next ();
11591185 expr = parseTop ();
@@ -1165,13 +1191,14 @@ private JSDocTypeExpression parseType(int startIndex, int endIndex) throws Parse
11651191 return expr ;
11661192 }
11671193
1168- private JSDocTypeExpression parseParamType (int startIndex , int endIndex ) throws ParseError {
1194+ private JSDocTypeExpression parseParamType (int startIndex , int endIndex , int lineStart , int lineNumber ) throws ParseError {
11691195 JSDocTypeExpression expr ;
11701196
1197+ this .lineNumber = lineNumber ;
1198+ this .lineStart = lineStart ;
11711199 this .startIndex = startIndex ;
11721200 this .endIndex = endIndex ;
11731201 index = startIndex ;
1174- previous = startIndex ;
11751202
11761203 next ();
11771204 expr = parseTopParamType ();
@@ -1283,6 +1310,8 @@ private JSDocTypeExpression parseType(String title, int last) throws ParseError
12831310 if (!direct ) {
12841311 // type expression { is found
12851312 brace = 1 ;
1313+ int firstLineStart = this .lineStart ;
1314+ int firstLineNumber = this .lineNumber ;
12861315 int startIndex = index ;
12871316 while (index < last ) {
12881317 ch = source .charAt (index );
@@ -1305,9 +1334,9 @@ private JSDocTypeExpression parseType(String title, int last) throws ParseError
13051334
13061335 try {
13071336 if (isParamTitle (title )) {
1308- return typed .parseParamType (startIndex , index - 1 );
1337+ return typed .parseParamType (startIndex , index - 1 , firstLineStart , firstLineNumber );
13091338 }
1310- return typed .parseType (startIndex , index - 1 );
1339+ return typed .parseType (startIndex , index - 1 , firstLineStart , firstLineNumber );
13111340 } catch (ParseError e ) {
13121341 // parse failed
13131342 return null ;
@@ -1859,15 +1888,15 @@ String scanJSDocDescription() {
18591888 return description .toString ().trim ();
18601889 }
18611890
1862- public Pair <String , List <Tag >> parseComment () {
1891+ public Pair <String , List <Tag >> parseComment (int lineNumber_ , int lineStart_ ) {
18631892 List <Tag > tags = new ArrayList <>();
18641893 Tag tag ;
18651894 String description ;
18661895
18671896 length = source .length ();
18681897 index = 1 ; // Skip initial "*"
1869- lineNumber = 0 ;
1870- lineStart = 1 ; // Skip initial "*"
1898+ lineNumber = lineNumber_ ;
1899+ lineStart = lineStart_ ;
18711900 recoverable = true ;
18721901 sloppy = true ;
18731902
0 commit comments