Skip to content

Commit c4b8bbf

Browse files
authored
Add support for large JSON documents (> Int32::MAX) (#16144)
1 parent ca3d4a3 commit c4b8bbf

File tree

6 files changed

+93
-18
lines changed

6 files changed

+93
-18
lines changed

src/json.cr

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,41 @@ module JSON
120120

121121
# Exception thrown on a JSON parse error.
122122
class ParseException < Error
123-
getter line_number : Int32
124-
getter column_number : Int32
123+
@line_number : Int64
124+
@column_number : Int64
125125

126-
def initialize(message, @line_number, @column_number, cause = nil)
126+
def line_number : Int32
127+
@line_number.to_i32
128+
end
129+
130+
def column_number : Int32
131+
@column_number.to_i32
132+
end
133+
134+
@[Experimental]
135+
def line_number_i64 : Int64
136+
@line_number
137+
end
138+
139+
@[Experimental]
140+
def column_number_i64
141+
@column_number
142+
end
143+
144+
def initialize(message, line_number, column_number, cause = nil)
145+
@line_number = line_number.to_i64
146+
@column_number = column_number.to_i64
127147
super "#{message} at line #{@line_number}, column #{@column_number}", cause
128148
end
129149

130150
def location : {Int32, Int32}
131151
{line_number, column_number}
132152
end
153+
154+
@[Experimental]
155+
def location_i64 : {Int64, Int64}
156+
{line_number_i64, column_number_i64}
157+
end
133158
end
134159

135160
# Parses a JSON document as a `JSON::Any`.

src/json/from_json.cr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ end
138138
} %}
139139
def {{type.id}}.new(pull : JSON::PullParser)
140140
# TODO: use `PullParser#read?` instead
141-
location = pull.location
141+
location = pull.location_i64
142142
value =
143143
{% if type == "UInt64" || type == "UInt128" || type == "Int128" %}
144144
pull.read_raw
@@ -282,7 +282,7 @@ def NamedTuple.new(pull : JSON::PullParser)
282282
{% end %}
283283
{% end %}
284284

285-
location = pull.location
285+
location = pull.location_i64
286286

287287
pull.read_object do |key|
288288
case key
@@ -389,7 +389,7 @@ module Enum::ValueConverter(T)
389389
end
390390

391391
def Union.new(pull : JSON::PullParser)
392-
location = pull.location
392+
location = pull.location_i64
393393

394394
{% begin %}
395395
case pull.kind

src/json/lexer.cr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ abstract class JSON::Lexer
1212
getter token : Token
1313
property skip : Bool
1414

15+
@line_number : Int64
16+
@column_number : Int64
17+
1518
def initialize
1619
@token = Token.new
1720
@line_number = 1

src/json/pull_parser.cr

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class JSON::PullParser
104104
@raw_value = ""
105105
@object_stack = [] of ObjectStackKind
106106
@skip_count = 0
107-
@location = {0, 0}
107+
@location = {0_i64, 0_i64}
108108

109109
next_token
110110
case token.kind
@@ -577,19 +577,39 @@ class JSON::PullParser
577577
end
578578

579579
# Returns the current line number.
580-
def line_number
580+
@[Experimental]
581+
def line_number_i64 : Int64
581582
@location[0]
582583
end
583584

585+
# Returns the current line number.
586+
def line_number : Int32
587+
@location[0].to_i32
588+
end
589+
584590
# Returns the current column number.
585-
def column_number
591+
@[Experimental]
592+
def column_number_i64
586593
@location[1]
587594
end
588595

596+
# Returns the current column number.
597+
def column_number
598+
@location[1].to_i32
599+
end
600+
589601
# Returns the current location.
590602
#
591603
# The location is a tuple `{line number, column number}`.
592604
def location : Tuple(Int32, Int32)
605+
{line_number, column_number}
606+
end
607+
608+
# Returns the current location.
609+
#
610+
# The location is a tuple `{line number, column number}`.
611+
@[Experimental]
612+
def location_i64 : Tuple(Int64, Int64)
593613
@location
594614
end
595615

@@ -654,12 +674,12 @@ class JSON::PullParser
654674
end
655675

656676
private def next_token
657-
@location = {@lexer.token.line_number, @lexer.token.column_number}
677+
@location = {@lexer.token.line_number_i64, @lexer.token.column_number_i64}
658678
@lexer.next_token
659679
end
660680

661681
private def next_token_expect_object_key
662-
@location = {@lexer.token.line_number, @lexer.token.column_number}
682+
@location = {@lexer.token.line_number_i64, @lexer.token.column_number_i64}
663683
@lexer.next_token_expect_object_key
664684
end
665685

src/json/serialization.cr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,14 @@ module JSON
210210
%found{name} = false
211211
{% end %}
212212

213-
%location = pull.location
213+
%location = pull.location_i64
214214
begin
215215
pull.read_begin_object
216216
rescue exc : ::JSON::ParseException
217217
raise ::JSON::SerializableError.new(exc.message, self.class.to_s, nil, *%location, exc)
218218
end
219219
until pull.kind.end_object?
220-
%key_location = pull.location
220+
%key_location = pull.location_i64
221221
key = pull.read_object_key
222222
case key
223223
{% for name, value in properties %}
@@ -421,7 +421,7 @@ module JSON
421421
{% end %}
422422

423423
def self.new(pull : ::JSON::PullParser)
424-
location = pull.location
424+
location = pull.location_i64
425425

426426
discriminator_value = nil
427427

@@ -486,7 +486,7 @@ module JSON
486486
getter klass : String
487487
getter attribute : String?
488488

489-
def initialize(message : String?, @klass : String, @attribute : String?, line_number : Int32, column_number : Int32, cause)
489+
def initialize(message : String?, @klass : String, @attribute : String?, line_number, column_number, cause)
490490
message = String.build do |io|
491491
io << message
492492
io << "\n parsing "
@@ -497,7 +497,7 @@ module JSON
497497
end
498498
super(message, line_number, column_number, cause)
499499
if cause
500-
@line_number, @column_number = cause.location
500+
@line_number, @column_number = cause.location_i64
501501
end
502502
end
503503
end

src/json/token.cr

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,35 @@ class JSON::Token
3030
raise ParseException.new(exc.message, line_number, column_number)
3131
end
3232

33-
property line_number : Int32
34-
property column_number : Int32
33+
@line_number : Int64
34+
@column_number : Int64
35+
36+
def line_number : Int32
37+
@line_number.to_i32
38+
end
39+
40+
@[Experimental]
41+
def line_number_i64 : Int64
42+
@line_number
43+
end
44+
45+
def line_number=(line_number)
46+
@line_number = line_number.to_i64
47+
end
48+
49+
def column_number : Int32
50+
@column_number.to_i32
51+
end
52+
53+
@[Experimental]
54+
def column_number_i64
55+
@column_number
56+
end
57+
58+
def column_number=(column_number)
59+
@column_number = column_number.to_i64
60+
end
61+
3562
property raw_value : String
3663

3764
def initialize

0 commit comments

Comments
 (0)