@@ -67,22 +67,22 @@ class JSON5Lexer(private val source: String) {
6767 advance() // Skip the backslash
6868
6969 if (currentChar != ' u' ) {
70- throw JSON5Exception ( " Expected 'u' after backslash in identifier " , line, column)
70+ throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column)
7171 }
7272
73- advance() // Skip 'u'
73+ advance() // Skip the 'u'
7474 val hexDigits = StringBuilder ()
7575 repeat(4 ) {
7676 if (currentChar == null || ! currentChar!! .isHexDigit()) {
77- throw JSON5Exception ( " Invalid hex escape sequence in identifier " , line, column)
77+ throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column)
7878 }
7979 hexDigits.append(currentChar)
8080 advance()
8181 }
8282
8383 val char = hexDigits.toString().toInt(16 ).toChar()
8484 if (! isIdentifierStart(char)) {
85- throw JSON5Exception ( " Invalid identifier character " , line, startColumn)
85+ throw JSON5Exception .invalidIdentifierChar( line, startColumn)
8686 }
8787
8888 val buffer = StringBuilder ().append(char)
@@ -92,14 +92,14 @@ class JSON5Lexer(private val source: String) {
9292 if (currentChar == ' \\ ' ) {
9393 advance() // Skip backslash
9494 if (currentChar != ' u' ) {
95- throw JSON5Exception ( " Expected 'u' after backslash in identifier " , line, column)
95+ throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column)
9696 }
9797 advance() // Skip 'u'
9898
9999 val identHexDigits = StringBuilder ()
100100 repeat(4 ) {
101101 if (currentChar == null || ! currentChar!! .isHexDigit()) {
102- throw JSON5Exception ( " Invalid hex escape sequence in identifier " , line, column)
102+ throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column)
103103 }
104104 identHexDigits.append(currentChar)
105105 advance()
@@ -116,11 +116,18 @@ class JSON5Lexer(private val source: String) {
116116
117117 return Token .IdentifierToken (buffer.toString(), line, startColumn)
118118 }
119+ ' /' -> {
120+ // Handle incomplete comments
121+ if (peek() == null ) {
122+ throw JSON5Exception .invalidChar(' /' , line, column)
123+ }
124+ throw JSON5Exception .invalidChar(peek() ? : ' ' , line, column + 1 )
125+ }
119126 else -> {
120127 if (isIdentifierStart(currentChar)) {
121128 readIdentifier()
122129 } else {
123- throw JSON5Exception ( " Unexpected character: $currentChar " , line, column)
130+ throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column)
124131 }
125132 }
126133 }
@@ -200,6 +207,7 @@ class JSON5Lexer(private val source: String) {
200207
201208 private fun readString (): Token .StringToken {
202209 val startColumn = column
210+ val startLine = line
203211 val quoteChar = currentChar
204212 advance() // Skip the quote character
205213
@@ -216,7 +224,7 @@ class JSON5Lexer(private val source: String) {
216224 advance() // Skip the backslash
217225 buffer.append(readEscapeSequence())
218226 }
219- ' \n ' , ' \r ' -> throw JSON5Exception ( " Unterminated string " , line, startColumn )
227+ ' \n ' , ' \r ' -> throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column )
220228 else -> {
221229 buffer.append(currentChar)
222230 advance()
@@ -225,7 +233,7 @@ class JSON5Lexer(private val source: String) {
225233 }
226234
227235 if (! done) {
228- throw JSON5Exception ( " Unterminated string " , line , startColumn)
236+ throw JSON5Exception .invalidEndOfInput(startLine , startColumn)
229237 }
230238
231239 return Token .StringToken (buffer.toString(), line, startColumn)
@@ -292,17 +300,33 @@ class JSON5Lexer(private val source: String) {
292300 }
293301 ' x' -> {
294302 advance()
295- return readHexEscape(2 )
303+ try {
304+ return readHexEscape(2 )
305+ } catch (e: Exception ) {
306+ if (currentChar != null ) {
307+ throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column)
308+ }
309+ throw JSON5Exception .invalidEndOfInput(line, column)
310+ }
296311 }
297312 ' u' -> {
298313 advance()
299- return readHexEscape(4 )
314+ try {
315+ return readHexEscape(4 )
316+ } catch (e: Exception ) {
317+ if (currentChar != null ) {
318+ throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column)
319+ }
320+ throw JSON5Exception .invalidEndOfInput(line, column)
321+ }
300322 }
323+ null -> throw JSON5Exception .invalidEndOfInput(line, column)
324+ in ' 1' .. ' 9' -> throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column)
301325 else -> {
302326 // Just return the character after the backslash (e.g. for \', \", etc.)
303327 val c = currentChar
304328 advance()
305- return c ? : throw JSON5Exception ( " Invalid escape sequence " , line, column)
329+ return c ? : throw JSON5Exception .invalidEndOfInput( line, column)
306330 }
307331 }
308332 }
@@ -403,7 +427,7 @@ class JSON5Lexer(private val source: String) {
403427 }
404428
405429 if (! hasDigits) {
406- throw JSON5Exception ( " Invalid hexadecimal number " , line, column)
430+ throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column)
407431 }
408432
409433 try {
@@ -416,7 +440,7 @@ class JSON5Lexer(private val source: String) {
416440 }
417441 return Token .NumericToken (value, startLine, startColumn)
418442 } catch (e: NumberFormatException ) {
419- throw JSON5Exception (" Invalid hexadecimal number: ${buffer} " , line, column)
443+ throw JSON5Exception (" Invalid hexadecimal number" , line, column)
420444 }
421445 }
422446
@@ -464,15 +488,15 @@ class JSON5Lexer(private val source: String) {
464488 }
465489
466490 if (! hasExponentDigits) {
467- throw JSON5Exception ( " Invalid exponent in number " , line, column)
491+ throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column)
468492 }
469493
470494 hasExponentPart = true
471495 }
472496
473497 // Must have at least one part (integer, fraction, or starts with a decimal point)
474498 if (! (hasIntegerPart || hasFractionPart) || (hasFractionPart && ! hasIntegerPart && buffer.length == 1 )) {
475- throw JSON5Exception ( " Invalid number " , line, column)
499+ throw JSON5Exception .invalidChar(currentChar ? : ' ' , line, column)
476500 }
477501
478502 val value = buffer.toString().toDouble()
@@ -516,8 +540,11 @@ class JSON5Lexer(private val source: String) {
516540 private fun readHexEscape (digits : Int ): Char {
517541 val hexString = StringBuilder ()
518542 repeat(digits) {
519- if (currentChar == null || ! currentChar!! .isHexDigit()) {
520- throw JSON5Exception (" Invalid hex escape sequence" , line, column)
543+ if (currentChar == null ) {
544+ throw JSON5Exception .invalidEndOfInput(line, column)
545+ }
546+ if (! currentChar!! .isHexDigit()) {
547+ throw JSON5Exception .invalidChar(currentChar!! , line, column)
521548 }
522549 hexString.append(currentChar)
523550 advance()
0 commit comments