@@ -395,6 +395,23 @@ static void raise_parse_error(const char *format, JSON_ParserState *state)
395
395
{
396
396
unsigned char buffer [PARSE_ERROR_FRAGMENT_LEN + 1 ];
397
397
398
+ const char * cursor = state -> cursor ;
399
+ long column = 0 ;
400
+ long line = 1 ;
401
+
402
+ while (cursor >= state -> start ) {
403
+ if (* cursor -- == '\n' ) {
404
+ break ;
405
+ }
406
+ column ++ ;
407
+ }
408
+
409
+ while (cursor >= state -> start ) {
410
+ if (* cursor -- == '\n' ) {
411
+ line ++ ;
412
+ }
413
+ }
414
+
398
415
const char * ptr = state -> cursor ;
399
416
size_t len = ptr ? strnlen (ptr , PARSE_ERROR_FRAGMENT_LEN ) : 0 ;
400
417
@@ -413,7 +430,14 @@ static void raise_parse_error(const char *format, JSON_ParserState *state)
413
430
ptr = (const char * )buffer ;
414
431
}
415
432
416
- rb_enc_raise (enc_utf8 , rb_path2class ("JSON::ParserError" ), format , ptr );
433
+ VALUE msg = rb_sprintf (format , ptr );
434
+ VALUE message = rb_enc_sprintf (enc_utf8 , "%s at line %ld column %ld" , RSTRING_PTR (msg ), line , column );
435
+ RB_GC_GUARD (msg );
436
+
437
+ VALUE exc = rb_exc_new_str (rb_path2class ("JSON::ParserError" ), message );
438
+ rb_ivar_set (exc , rb_intern ("@line" ), LONG2NUM (line ));
439
+ rb_ivar_set (exc , rb_intern ("@column" ), LONG2NUM (column ));
440
+ rb_exc_raise (exc );
417
441
}
418
442
419
443
#ifdef RBIMPL_ATTR_NORETURN
@@ -508,11 +532,11 @@ json_eat_comments(JSON_ParserState *state)
508
532
break ;
509
533
}
510
534
default :
511
- raise_parse_error ("unexpected token at '%s'" , state );
535
+ raise_parse_error ("unexpected token '%s'" , state );
512
536
break ;
513
537
}
514
538
} else {
515
- raise_parse_error ("unexpected token at '%s'" , state );
539
+ raise_parse_error ("unexpected token '%s'" , state );
516
540
}
517
541
}
518
542
@@ -870,15 +894,15 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
870
894
return json_push_value (state , config , Qnil );
871
895
}
872
896
873
- raise_parse_error ("unexpected token at '%s'" , state );
897
+ raise_parse_error ("unexpected token '%s'" , state );
874
898
break ;
875
899
case 't' :
876
900
if ((state -> end - state -> cursor >= 4 ) && (memcmp (state -> cursor , "true" , 4 ) == 0 )) {
877
901
state -> cursor += 4 ;
878
902
return json_push_value (state , config , Qtrue );
879
903
}
880
904
881
- raise_parse_error ("unexpected token at '%s'" , state );
905
+ raise_parse_error ("unexpected token '%s'" , state );
882
906
break ;
883
907
case 'f' :
884
908
// Note: memcmp with a small power of two compile to an integer comparison
@@ -887,7 +911,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
887
911
return json_push_value (state , config , Qfalse );
888
912
}
889
913
890
- raise_parse_error ("unexpected token at '%s'" , state );
914
+ raise_parse_error ("unexpected token '%s'" , state );
891
915
break ;
892
916
case 'N' :
893
917
// Note: memcmp with a small power of two compile to an integer comparison
@@ -896,15 +920,15 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
896
920
return json_push_value (state , config , CNaN );
897
921
}
898
922
899
- raise_parse_error ("unexpected token at '%s'" , state );
923
+ raise_parse_error ("unexpected token '%s'" , state );
900
924
break ;
901
925
case 'I' :
902
926
if (config -> allow_nan && (state -> end - state -> cursor >= 8 ) && (memcmp (state -> cursor , "Infinity" , 8 ) == 0 )) {
903
927
state -> cursor += 8 ;
904
928
return json_push_value (state , config , CInfinity );
905
929
}
906
930
907
- raise_parse_error ("unexpected token at '%s'" , state );
931
+ raise_parse_error ("unexpected token '%s'" , state );
908
932
break ;
909
933
case '-' :
910
934
// Note: memcmp with a small power of two compile to an integer comparison
@@ -913,7 +937,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
913
937
state -> cursor += 9 ;
914
938
return json_push_value (state , config , CMinusInfinity );
915
939
} else {
916
- raise_parse_error ("unexpected token at '%s'" , state );
940
+ raise_parse_error ("unexpected token '%s'" , state );
917
941
}
918
942
}
919
943
// Fallthrough
0 commit comments