Cosmetic + Optimization + Assertion + Void-safety
(no significant interface changes)
This commit is contained in:
@@ -14,24 +14,29 @@ indexing
|
||||
|
||||
class
|
||||
JSON_ARRAY
|
||||
inherit
|
||||
|
||||
inherit
|
||||
JSON_VALUE
|
||||
|
||||
DEBUG_OUTPUT
|
||||
|
||||
create
|
||||
make_array
|
||||
|
||||
feature -- Initialization
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_array is
|
||||
--
|
||||
do
|
||||
create values.make (10)
|
||||
end
|
||||
-- Initialize JSON Array
|
||||
do
|
||||
create values.make (10)
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
i_th alias "[]" (i: INTEGER):JSON_VALUE is
|
||||
|
||||
i_th alias "[]" (i: INTEGER): JSON_VALUE is
|
||||
-- Item at `i'-th position
|
||||
require
|
||||
is_valid_index:valid_index (i)
|
||||
is_valid_index: valid_index (i)
|
||||
do
|
||||
Result := values.i_th (i)
|
||||
end
|
||||
@@ -46,13 +51,15 @@ feature -- Visitor pattern
|
||||
end
|
||||
|
||||
feature -- Mesurement
|
||||
count:INTEGER is
|
||||
|
||||
count: INTEGER is
|
||||
-- Number of items.
|
||||
do
|
||||
Result:=values.count
|
||||
Result := values.count
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
valid_index (i: INTEGER): BOOLEAN is
|
||||
-- Is `i' a valid index?
|
||||
do
|
||||
@@ -60,43 +67,54 @@ feature -- Status report
|
||||
end
|
||||
|
||||
feature -- Change Element
|
||||
add(value:JSON_VALUE) is
|
||||
require
|
||||
not_null:value /= void
|
||||
do
|
||||
values.extend(value)
|
||||
ensure
|
||||
has_new_value:old values.count + 1 = values.count and
|
||||
values.has (value)
|
||||
end
|
||||
|
||||
add (value: JSON_VALUE) is
|
||||
require
|
||||
value_not_null: value /= void
|
||||
do
|
||||
values.extend(value)
|
||||
ensure
|
||||
has_new_value: old values.count + 1 = values.count and
|
||||
values.has (value)
|
||||
end
|
||||
|
||||
feature -- Report
|
||||
|
||||
hash_code:INTEGER is
|
||||
--
|
||||
do
|
||||
from
|
||||
values.start
|
||||
Result:=values.item.hash_code
|
||||
until
|
||||
values.off
|
||||
loop
|
||||
Result:= ((Result \\ 8388593) |<< 8) + values.item.hash_code
|
||||
values.forth
|
||||
end
|
||||
Result := Result \\ values.count
|
||||
|
||||
end
|
||||
feature -- Conversion
|
||||
|
||||
array_representation:ARRAYED_LIST[JSON_VALUE] is
|
||||
-- Representation as a sequences of values
|
||||
hash_code: INTEGER is
|
||||
-- Hash code value
|
||||
do
|
||||
Result:=values
|
||||
from
|
||||
values.start
|
||||
Result := values.item.hash_code
|
||||
until
|
||||
values.off
|
||||
loop
|
||||
Result:= ((Result \\ 8388593) |<< 8) + values.item.hash_code
|
||||
values.forth
|
||||
end
|
||||
Result := Result \\ values.count
|
||||
end
|
||||
|
||||
feature {NONE} --Implementation
|
||||
values:ARRAYED_LIST[JSON_VALUE]
|
||||
feature -- Conversion
|
||||
|
||||
array_representation: ARRAYED_LIST [JSON_VALUE] is
|
||||
-- Representation as a sequences of values
|
||||
do
|
||||
Result := values
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
Result := count.out
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
values: ARRAYED_LIST [JSON_VALUE]
|
||||
-- Value container
|
||||
|
||||
invariant
|
||||
value_not_void: values /= Void
|
||||
|
||||
@@ -5,17 +5,15 @@ indexing
|
||||
revision: "Revision 0.1"
|
||||
|
||||
class
|
||||
|
||||
JSON_BOOLEAN
|
||||
|
||||
inherit
|
||||
JSON_VALUE
|
||||
|
||||
create
|
||||
|
||||
make_boolean
|
||||
|
||||
feature -- Initialization
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_boolean (an_item: BOOLEAN) is
|
||||
--Initialize.
|
||||
@@ -28,9 +26,8 @@ feature -- Access
|
||||
item: BOOLEAN
|
||||
-- Content
|
||||
|
||||
|
||||
hash_code: INTEGER is
|
||||
--Hash code value
|
||||
-- Hash code value
|
||||
do
|
||||
Result := item.hash_code
|
||||
end
|
||||
@@ -44,6 +41,12 @@ feature -- Visitor pattern
|
||||
a_visitor.visit_json_boolean (Current)
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
Result := item.out
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -8,28 +8,31 @@ class
|
||||
JSON_FILE_READER
|
||||
|
||||
feature -- Access
|
||||
read_json_from(a_path:STRING):STRING is
|
||||
local
|
||||
l_file: PLAIN_TEXT_FILE
|
||||
template_content:STRING
|
||||
do
|
||||
|
||||
create l_file.make (a_path)
|
||||
-- We perform several checks until we make a real attempt to open the file.
|
||||
if not l_file.exists then
|
||||
print ("error: '" + a_path + "' does not exist%N")
|
||||
else
|
||||
if not l_file.is_readable then
|
||||
print ("error: '" + a_path + "' is not readable.%N")
|
||||
else
|
||||
l_file.open_read
|
||||
create template_content.make_empty
|
||||
l_file.read_stream (l_file.count)
|
||||
template_content.append (l_file.last_string.twin)
|
||||
Result := template_content
|
||||
l_file.close
|
||||
end
|
||||
end
|
||||
end
|
||||
read_json_from (a_path: STRING): ?STRING is
|
||||
local
|
||||
l_file: PLAIN_TEXT_FILE
|
||||
template_content: STRING
|
||||
l_last_string: ?STRING
|
||||
do
|
||||
create l_file.make (a_path)
|
||||
-- We perform several checks until we make a real attempt to open the file.
|
||||
if not l_file.exists then
|
||||
print ("error: '" + a_path + "' does not exist%N")
|
||||
else
|
||||
if not l_file.is_readable then
|
||||
print ("error: '" + a_path + "' is not readable.%N")
|
||||
else
|
||||
l_file.open_read
|
||||
create template_content.make_empty
|
||||
l_file.read_stream (l_file.count)
|
||||
l_last_string := l_file.last_string
|
||||
check l_last_string /= Void end -- implied by postcondition of `l_file.read_stream'
|
||||
template_content.append (l_last_string.string)
|
||||
Result := template_content
|
||||
l_file.close
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -6,16 +6,18 @@ indexing
|
||||
|
||||
class
|
||||
JSON_NULL
|
||||
inherit
|
||||
JSON_VALUE
|
||||
|
||||
inherit
|
||||
JSON_VALUE
|
||||
|
||||
feature --Access
|
||||
|
||||
hash_code:INTEGER is
|
||||
hash_code: INTEGER is
|
||||
-- Hash code value
|
||||
do
|
||||
Result:= null_value.hash_code
|
||||
Result := null_value.hash_code
|
||||
end
|
||||
|
||||
feature -- Visitor pattern
|
||||
|
||||
accept (a_visitor: JSON_VISITOR) is
|
||||
@@ -25,6 +27,16 @@ feature -- Visitor pattern
|
||||
a_visitor.visit_json_null (Current)
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
Result := null_value
|
||||
end
|
||||
|
||||
feature {NONE}-- Implementation
|
||||
null_value:STRING is "null"
|
||||
|
||||
null_value: STRING is "null"
|
||||
|
||||
end
|
||||
|
||||
@@ -10,19 +10,16 @@ class
|
||||
JSON_NUMBER
|
||||
|
||||
inherit
|
||||
|
||||
JSON_VALUE
|
||||
redefine
|
||||
is_equal
|
||||
end
|
||||
|
||||
|
||||
create
|
||||
|
||||
make_integer,
|
||||
make_real
|
||||
|
||||
feature -- initialization
|
||||
feature {NONE} -- initialization
|
||||
|
||||
make_integer (an_argument: INTEGER) is
|
||||
-- Initialize an instance of JSON_NUMBER as INTEGER
|
||||
@@ -38,16 +35,15 @@ feature -- initialization
|
||||
numeric_type := DOUBLE_TYPE
|
||||
end
|
||||
|
||||
|
||||
feature -- Access
|
||||
|
||||
item: STRING
|
||||
-- Content
|
||||
-- Content
|
||||
|
||||
hash_code: INTEGER is
|
||||
--Hash code value
|
||||
do
|
||||
Result:=item.hash_code
|
||||
Result := item.hash_code
|
||||
end
|
||||
|
||||
feature -- Visitor pattern
|
||||
@@ -68,7 +64,13 @@ feature -- Status
|
||||
Result := item.is_equal (other.item)
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
Result := item
|
||||
end
|
||||
|
||||
feature -- Implementation
|
||||
|
||||
@@ -77,9 +79,7 @@ feature -- Implementation
|
||||
|
||||
numeric_type: INTEGER
|
||||
|
||||
|
||||
invariant
|
||||
|
||||
item_not_void: item /= Void
|
||||
|
||||
end
|
||||
|
||||
@@ -1,36 +1,31 @@
|
||||
indexing
|
||||
|
||||
description: "[
|
||||
An JSON_OBJECT represent an object in JSON.
|
||||
An object is an unordered set of name/value pairs
|
||||
An JSON_OBJECT represent an object in JSON.
|
||||
An object is an unordered set of name/value pairs
|
||||
|
||||
Examples:
|
||||
Examples:
|
||||
|
||||
object
|
||||
{}
|
||||
{"key","value"}
|
||||
|
||||
|
||||
]"
|
||||
author: "Javier Velilla"
|
||||
date: "2008/08/24"
|
||||
revision: "Revision 0.1"
|
||||
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
|
||||
object
|
||||
{}
|
||||
{"key","value"}
|
||||
|
||||
]"
|
||||
author: "Javier Velilla"
|
||||
date: "2008/08/24"
|
||||
revision: "Revision 0.1"
|
||||
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
|
||||
|
||||
class
|
||||
|
||||
JSON_OBJECT
|
||||
|
||||
inherit
|
||||
|
||||
JSON_VALUE
|
||||
|
||||
create
|
||||
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make is
|
||||
-- Initialize
|
||||
@@ -40,49 +35,45 @@ feature -- Initialization
|
||||
|
||||
feature -- Change Element
|
||||
|
||||
|
||||
put (value: JSON_VALUE ; key: JSON_STRING) is
|
||||
put (value: ?JSON_VALUE; key: JSON_STRING) is
|
||||
-- Assuming there is no item of key `key',
|
||||
-- insert `value' with `key'.
|
||||
require
|
||||
not_present: not has_key (key)
|
||||
key_not_present: not has_key (key)
|
||||
local
|
||||
l_json_null: JSON_NULL
|
||||
l_value: JSON_VALUE
|
||||
l_value: ?JSON_VALUE
|
||||
do
|
||||
l_value:=value
|
||||
if value = Void then
|
||||
create l_json_null
|
||||
l_value:=l_json_null
|
||||
l_value := value
|
||||
if l_value = Void then
|
||||
create {JSON_NULL} l_value
|
||||
end
|
||||
object.extend (l_value,key)
|
||||
object.extend (l_value, key)
|
||||
end
|
||||
|
||||
|
||||
feature -- Access
|
||||
|
||||
has_key (key: JSON_STRING):BOOLEAN is
|
||||
has_key (key: JSON_STRING): BOOLEAN is
|
||||
-- has the JSON_OBJECT contains a specific key 'key'.
|
||||
do
|
||||
Result := object.has (key)
|
||||
end
|
||||
|
||||
has_item (value: JSON_VALUE):BOOLEAN is
|
||||
has_item (value: JSON_VALUE): BOOLEAN is
|
||||
-- has the JSON_OBJECT contain a specfic item 'value'
|
||||
do
|
||||
Result := object.has_item (value)
|
||||
end
|
||||
|
||||
item (key: JSON_STRING):JSON_VALUE is
|
||||
item (key: JSON_STRING): ?JSON_VALUE is
|
||||
-- the json_value associated with a key.
|
||||
do
|
||||
Result:= object.item (key)
|
||||
Result := object.item (key)
|
||||
end
|
||||
|
||||
current_keys: ARRAY [JSON_STRING] is
|
||||
-- array containing actually used keys
|
||||
do
|
||||
Result:=object.current_keys
|
||||
Result := object.current_keys
|
||||
end
|
||||
|
||||
feature -- Visitor pattern
|
||||
@@ -94,19 +85,18 @@ feature -- Visitor pattern
|
||||
a_visitor.visit_json_object (Current)
|
||||
end
|
||||
|
||||
|
||||
feature -- Conversion
|
||||
map_representation: HASH_TABLE[JSON_VALUE,JSON_STRING] is
|
||||
|
||||
map_representation: HASH_TABLE [JSON_VALUE, JSON_STRING] is
|
||||
--A representation that maps keys to values
|
||||
do
|
||||
Result:=object
|
||||
Result := object
|
||||
end
|
||||
|
||||
feature -- Report
|
||||
|
||||
hash_code: INTEGER is
|
||||
-- Hash code value
|
||||
local
|
||||
do
|
||||
from
|
||||
object.start
|
||||
@@ -121,10 +111,18 @@ feature -- Report
|
||||
Result := Result.hash_code
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
Result := object.count.out
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
object: HASH_TABLE[JSON_VALUE,JSON_STRING]
|
||||
object: HASH_TABLE [JSON_VALUE, JSON_STRING]
|
||||
-- Value container
|
||||
|
||||
invariant
|
||||
object_not_null: object /= Void
|
||||
|
||||
@@ -13,21 +13,18 @@ indexing
|
||||
|
||||
|
||||
class
|
||||
|
||||
JSON_STRING
|
||||
|
||||
inherit
|
||||
|
||||
JSON_VALUE
|
||||
redefine
|
||||
is_equal
|
||||
end
|
||||
|
||||
create
|
||||
|
||||
make_json
|
||||
|
||||
feature -- Initialization
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make_json (an_item: STRING) is
|
||||
-- Initialize.
|
||||
@@ -37,7 +34,6 @@ feature -- Initialization
|
||||
item := an_item
|
||||
end
|
||||
|
||||
|
||||
feature -- Access
|
||||
|
||||
item: STRING
|
||||
@@ -52,7 +48,6 @@ feature -- Visitor pattern
|
||||
a_visitor.visit_json_string (Current)
|
||||
end
|
||||
|
||||
|
||||
feature -- Comparison
|
||||
|
||||
is_equal (other: like Current): BOOLEAN is
|
||||
@@ -64,13 +59,14 @@ feature -- Comparison
|
||||
|
||||
feature -- Change Element
|
||||
|
||||
append (an_item: STRING)is
|
||||
append (a_string: STRING)is
|
||||
-- Add an_item
|
||||
require
|
||||
a_string_not_void: a_string /= Void
|
||||
do
|
||||
item.append_string (an_item)
|
||||
item.append_string (a_string)
|
||||
end
|
||||
|
||||
|
||||
feature -- Status report
|
||||
|
||||
hash_code: INTEGER is
|
||||
@@ -79,8 +75,15 @@ feature -- Status report
|
||||
Result := item.hash_code
|
||||
end
|
||||
|
||||
invariant
|
||||
feature -- Status report
|
||||
|
||||
debug_output: STRING
|
||||
-- String that should be displayed in debugger to represent `Current'.
|
||||
do
|
||||
Result := item
|
||||
end
|
||||
|
||||
invariant
|
||||
value_not_void: item /= Void
|
||||
|
||||
end
|
||||
|
||||
@@ -8,8 +8,6 @@ indexing
|
||||
* null
|
||||
* an object
|
||||
* an array
|
||||
|
||||
|
||||
]"
|
||||
author: "Javier Velilla"
|
||||
date: "2008/05/19"
|
||||
@@ -21,9 +19,10 @@ deferred class
|
||||
JSON_VALUE
|
||||
|
||||
inherit
|
||||
|
||||
HASHABLE
|
||||
|
||||
DEBUG_OUTPUT
|
||||
|
||||
feature -- Visitor pattern
|
||||
|
||||
accept (a_visitor: JSON_VISITOR) is
|
||||
@@ -33,4 +32,5 @@ feature -- Visitor pattern
|
||||
a_visitor_not_void: a_visitor /= Void
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -6,14 +6,13 @@ indexing
|
||||
revision: "Revision 0.1"
|
||||
|
||||
class
|
||||
|
||||
JSON_PARSER
|
||||
|
||||
inherit
|
||||
JSON_READER
|
||||
JSON_TOKENS
|
||||
|
||||
create
|
||||
|
||||
make_parser
|
||||
|
||||
feature {NONE} -- Initialize
|
||||
@@ -25,170 +24,204 @@ feature {NONE} -- Initialize
|
||||
do
|
||||
make (a_json)
|
||||
is_parsed := True
|
||||
create current_errors.make_empty
|
||||
create errors.make
|
||||
end
|
||||
|
||||
|
||||
feature -- Access
|
||||
feature -- Status report
|
||||
|
||||
is_parsed: BOOLEAN
|
||||
-- Is parsed?
|
||||
|
||||
errors: LINKED_LIST [STRING]
|
||||
-- Current errors
|
||||
|
||||
current_errors: STRING
|
||||
|
||||
|
||||
feature -- Commands
|
||||
|
||||
parse_json: JSON_VALUE is
|
||||
--
|
||||
-- Current errors as string
|
||||
do
|
||||
Result := parse
|
||||
if extra_elements then
|
||||
is_parsed := false
|
||||
create Result.make_empty
|
||||
from
|
||||
errors.start
|
||||
until
|
||||
errors.after
|
||||
loop
|
||||
Result.append_string (errors.item + "%N")
|
||||
errors.forth
|
||||
end
|
||||
end
|
||||
|
||||
parse: JSON_VALUE is
|
||||
--
|
||||
feature -- Element change
|
||||
|
||||
report_error (e: STRING) is
|
||||
-- Report error `e'
|
||||
require
|
||||
e_not_void: e /= Void
|
||||
do
|
||||
errors.force (e)
|
||||
end
|
||||
|
||||
feature -- Commands
|
||||
|
||||
parse_json: ?JSON_VALUE is
|
||||
-- Parse JSON data `representation'
|
||||
do
|
||||
Result := parse
|
||||
if extra_elements then
|
||||
is_parsed := False
|
||||
end
|
||||
end
|
||||
|
||||
parse: ?JSON_VALUE is
|
||||
-- Parse JSON data `representation'
|
||||
local
|
||||
c: CHARACTER
|
||||
do
|
||||
if is_parsed then
|
||||
skip_withe_spaces
|
||||
skip_white_spaces
|
||||
c := actual
|
||||
if c.is_equal (j_object_open) then
|
||||
inspect c
|
||||
when j_OBJECT_OPEN then
|
||||
Result := parse_object
|
||||
elseif c.is_equal (j_string) then
|
||||
when j_STRING then
|
||||
Result := parse_string
|
||||
elseif c.is_equal (j_array_open) then
|
||||
when j_ARRAY_OPEN then
|
||||
Result := parse_array
|
||||
elseif c.is_digit or c.is_equal (j_minus) then
|
||||
Result := parse_number
|
||||
elseif is_null then
|
||||
--
|
||||
Result := create {JSON_NULL}
|
||||
next;next;next
|
||||
elseif is_true then
|
||||
Result := create {JSON_BOOLEAN}.make_boolean (true)
|
||||
next;next;next
|
||||
elseif is_false then
|
||||
Result := create {JSON_BOOLEAN}.make_boolean (false)
|
||||
next;next;next;next
|
||||
else
|
||||
is_parsed := false
|
||||
current_errors.append ("JSON is not well formed in parse")
|
||||
Result := void
|
||||
if c.is_digit or c = j_MINUS then
|
||||
Result := parse_number
|
||||
elseif is_null then
|
||||
Result := create {JSON_NULL}
|
||||
next
|
||||
next
|
||||
next
|
||||
elseif is_true then
|
||||
Result := create {JSON_BOOLEAN}.make_boolean (True)
|
||||
next
|
||||
next
|
||||
next
|
||||
elseif is_false then
|
||||
Result := create {JSON_BOOLEAN}.make_boolean (False)
|
||||
next
|
||||
next
|
||||
next
|
||||
next
|
||||
else
|
||||
is_parsed := False
|
||||
report_error ("JSON is not well formed in parse")
|
||||
Result := Void
|
||||
end
|
||||
end
|
||||
end
|
||||
ensure
|
||||
is_parsed_implies_result_not_void: is_parsed implies Result /= Void
|
||||
end
|
||||
|
||||
parse_object: JSON_OBJECT is
|
||||
-- object
|
||||
-- {}
|
||||
-- {"key" : "value" [,]}
|
||||
|
||||
local
|
||||
has_more: BOOLEAN
|
||||
l_json_string: JSON_STRING
|
||||
l_value: JSON_VALUE
|
||||
l_json_string: ?JSON_STRING
|
||||
l_value: ?JSON_VALUE
|
||||
do
|
||||
create Result.make
|
||||
-- check if is an empty object {}
|
||||
next
|
||||
skip_withe_spaces
|
||||
if actual.is_equal (j_object_close) then
|
||||
skip_white_spaces
|
||||
if actual = j_OBJECT_CLOSE then
|
||||
--is an empty object
|
||||
else
|
||||
-- a complex object {"key" : "value"}
|
||||
previous
|
||||
from has_more := true until not has_more
|
||||
loop
|
||||
from has_more := True until not has_more loop
|
||||
next
|
||||
skip_withe_spaces
|
||||
skip_white_spaces
|
||||
l_json_string := parse_string
|
||||
next
|
||||
skip_withe_spaces
|
||||
if actual.is_equal (':') then
|
||||
skip_white_spaces
|
||||
if actual = ':' then
|
||||
next
|
||||
skip_withe_spaces
|
||||
skip_white_spaces
|
||||
else
|
||||
is_parsed := false
|
||||
current_errors.append ("%N Input string is a not well formed JSON, expected: : found: " + actual.out +"%N")
|
||||
has_more := false
|
||||
is_parsed := False
|
||||
report_error ("%N Input string is a not well formed JSON, expected: : found: " + actual.out)
|
||||
has_more := False
|
||||
end
|
||||
|
||||
l_value := parse
|
||||
if is_parsed then
|
||||
Result.put (l_value,l_json_string)
|
||||
if is_parsed and then (l_value /= Void and l_json_string /= Void) then
|
||||
Result.put (l_value, l_json_string)
|
||||
next
|
||||
skip_withe_spaces
|
||||
if actual.is_equal (j_object_close) then
|
||||
has_more := false
|
||||
elseif not actual.is_equal (',') then
|
||||
has_more := false
|
||||
is_parsed := false
|
||||
current_errors.append ("JSON Object sintactically malformed expected , found: [" + actual.out + "] %N")
|
||||
skip_white_spaces
|
||||
if actual = j_OBJECT_CLOSE then
|
||||
has_more := False
|
||||
elseif actual /= ',' then
|
||||
has_more := False
|
||||
is_parsed := False
|
||||
report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]")
|
||||
end
|
||||
else
|
||||
has_more := false
|
||||
has_more := False
|
||||
-- explain the error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parse_string: JSON_STRING is
|
||||
--
|
||||
parse_string: ?JSON_STRING is
|
||||
-- Parsed string
|
||||
local
|
||||
has_more: BOOLEAN
|
||||
l_json_string: STRING
|
||||
l_unicode: STRING
|
||||
c: like actual
|
||||
do
|
||||
create l_json_string.make_empty
|
||||
if actual.is_equal (j_string) then
|
||||
if actual = j_STRING then
|
||||
from
|
||||
has_more := true
|
||||
until not has_more
|
||||
|
||||
has_more := True
|
||||
until
|
||||
not has_more
|
||||
loop
|
||||
next
|
||||
if actual.is_equal (j_string) then
|
||||
has_more := false
|
||||
elseif actual.is_equal ('%H') then
|
||||
c := actual
|
||||
if c = j_STRING then
|
||||
has_more := False
|
||||
elseif c = '%H' then
|
||||
next
|
||||
if actual.is_equal ('u') then
|
||||
c := actual
|
||||
if c = 'u' then
|
||||
create l_unicode.make_from_string ("\u")
|
||||
l_unicode.append (read_unicode)
|
||||
c := actual
|
||||
if is_a_valid_unicode (l_unicode) then
|
||||
l_json_string.append (l_unicode)
|
||||
else
|
||||
has_more := false
|
||||
is_parsed := false
|
||||
current_errors.append ("Input String is not well formed JSON, expected a Unicode value, found [" + actual.out + " ] %N")
|
||||
has_more := False
|
||||
is_parsed := False
|
||||
report_error ("Input String is not well formed JSON, expected a Unicode value, found [" + c.out + " ]")
|
||||
end
|
||||
elseif (not special_characters.has (actual) and not special_controls.has (actual)) or actual.is_equal ('%N') then
|
||||
has_more := false
|
||||
is_parsed := false
|
||||
current_errors.append ("Input String is not well formed JSON, found [" + actual.out + " ] %N")
|
||||
|
||||
elseif (not is_special_character (c) and not is_special_control (c)) or c = '%N' then
|
||||
has_more := False
|
||||
is_parsed := False
|
||||
report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
|
||||
else
|
||||
l_json_string.append ("\")
|
||||
l_json_string.append (actual.out)
|
||||
|
||||
l_json_string.append (c.out)
|
||||
end
|
||||
|
||||
else
|
||||
if special_characters.has (actual) and not actual.is_equal ('/') then
|
||||
has_more := false
|
||||
is_parsed := false
|
||||
current_errors.append ("Input String is not well formed JSON, found [" + actual.out + " ] %N")
|
||||
if is_special_character (c) and c /= '/' then
|
||||
has_more := False
|
||||
is_parsed := False
|
||||
report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
|
||||
else
|
||||
l_json_string.append (actual.out)
|
||||
l_json_string.append_character (c)
|
||||
end
|
||||
end
|
||||
end
|
||||
create Result.make_json (l_json_string)
|
||||
else
|
||||
Result := void
|
||||
Result := Void
|
||||
end
|
||||
end
|
||||
|
||||
@@ -198,137 +231,142 @@ feature -- Commands
|
||||
-- [elements [,]]
|
||||
local
|
||||
flag: BOOLEAN
|
||||
l_value: JSON_VALUE
|
||||
l_value: ?JSON_VALUE
|
||||
c: like actual
|
||||
do
|
||||
create Result.make_array
|
||||
--check if is an empty array []
|
||||
next
|
||||
skip_withe_spaces
|
||||
if actual.is_equal (j_array_close) then
|
||||
skip_white_spaces
|
||||
if actual = j_array_close then
|
||||
--is an empty array
|
||||
else
|
||||
previous
|
||||
from
|
||||
flag := true
|
||||
flag := True
|
||||
until
|
||||
not flag
|
||||
loop
|
||||
next
|
||||
skip_withe_spaces
|
||||
skip_white_spaces
|
||||
l_value := parse
|
||||
if is_parsed then
|
||||
if is_parsed and then l_value /= Void then
|
||||
Result.add (l_value)
|
||||
next
|
||||
skip_withe_spaces
|
||||
if not actual.is_equal (j_array_close) and not actual.is_equal (',')then
|
||||
flag := false
|
||||
is_parsed := false
|
||||
current_errors.append ("Array is not well formed JSON, found [" + actual.out + " ] %N")
|
||||
elseif actual.is_equal (j_array_close) then
|
||||
flag := false
|
||||
skip_white_spaces
|
||||
c := actual
|
||||
if c = j_ARRAY_CLOSE then
|
||||
flag := False
|
||||
elseif c /= ',' then
|
||||
flag := False
|
||||
is_parsed := False
|
||||
report_error ("Array is not well formed JSON, found [" + c.out + " ]")
|
||||
end
|
||||
else
|
||||
flag := false
|
||||
current_errors.append ("Array is not well formed JSON, found [" + actual.out + " ] %N")
|
||||
flag := False
|
||||
report_error ("Array is not well formed JSON, found [" + actual.out + " ]")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
parse_number: JSON_NUMBER is
|
||||
--
|
||||
parse_number: ?JSON_NUMBER is
|
||||
-- Parsed number
|
||||
local
|
||||
sb: STRING
|
||||
flag: BOOLEAN
|
||||
is_integer: BOOLEAN
|
||||
c: like actual
|
||||
do
|
||||
create sb.make_empty
|
||||
sb.append (actual.out)
|
||||
sb.append_character (actual)
|
||||
|
||||
from
|
||||
flag := true
|
||||
until not flag
|
||||
flag := True
|
||||
until
|
||||
not flag
|
||||
loop
|
||||
next
|
||||
if not has_next or close_tokens.has (actual) or actual.is_equal (',')
|
||||
or actual.is_equal ('%N') or actual.is_equal ('%R') then
|
||||
flag := false
|
||||
c := actual
|
||||
if not has_next or is_close_token (c)
|
||||
or c = ',' or c = '%N' or c = '%R'
|
||||
then
|
||||
flag := False
|
||||
previous
|
||||
else
|
||||
sb.append (actual.out)
|
||||
sb.append_character (c)
|
||||
end
|
||||
end
|
||||
|
||||
if is_a_valid_number (sb) then
|
||||
if sb.is_integer then
|
||||
create Result.make_integer (sb.to_integer)
|
||||
is_integer := true
|
||||
is_integer := True
|
||||
elseif sb.is_double and not is_integer then
|
||||
create Result.make_real (sb.to_double)
|
||||
end
|
||||
else
|
||||
is_parsed := false
|
||||
current_errors.append ("Expected a number, found: [ " + sb + " ]")
|
||||
is_parsed := False
|
||||
report_error ("Expected a number, found: [ " + sb + " ]")
|
||||
end
|
||||
end
|
||||
|
||||
is_null: BOOLEAN is
|
||||
--
|
||||
-- Word at index represents null?
|
||||
local
|
||||
l_null: STRING
|
||||
l_string: STRING
|
||||
do
|
||||
l_null := "null"
|
||||
l_null := null_id
|
||||
l_string := json_substring (index,index + l_null.count - 1)
|
||||
if l_string.is_equal (l_null) then
|
||||
Result := true
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
|
||||
is_false: BOOLEAN is
|
||||
--
|
||||
-- Word at index represents false?
|
||||
local
|
||||
l_false: STRING
|
||||
l_string: STRING
|
||||
do
|
||||
l_false := "false"
|
||||
l_string := json_substring (index,index + l_false.count - 1)
|
||||
l_false := false_id
|
||||
l_string := json_substring (index, index + l_false.count - 1)
|
||||
if l_string.is_equal (l_false) then
|
||||
Result := true
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
|
||||
is_true: BOOLEAN is
|
||||
--
|
||||
-- Word at index represents true?
|
||||
local
|
||||
l_true: STRING
|
||||
l_string: STRING
|
||||
do
|
||||
l_true := "true"
|
||||
l_true := true_id
|
||||
l_string := json_substring (index,index + l_true.count - 1)
|
||||
if l_string.is_equal (l_true) then
|
||||
Result := true
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
|
||||
read_unicode: STRING is
|
||||
--
|
||||
-- Read unicode and return value
|
||||
local
|
||||
i: INTEGER
|
||||
do
|
||||
create Result.make_empty
|
||||
from
|
||||
i := 1
|
||||
until i > 4 or not has_next
|
||||
|
||||
until
|
||||
i > 4 or not has_next
|
||||
loop
|
||||
next
|
||||
Result.append (actual.out)
|
||||
Result.append_character (actual)
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
is_a_valid_number (a_number: STRING): BOOLEAN is
|
||||
@@ -348,9 +386,7 @@ feature {NONE} -- Implementation
|
||||
number_regex := "-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?\b"
|
||||
regexp.compile (number_regex)
|
||||
if regexp.matches (a_number) then
|
||||
if a_number.is_equal (regexp.captured_substring (0)) then
|
||||
Result := true
|
||||
end
|
||||
Result := a_number.is_equal (regexp.captured_substring (0))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -365,34 +401,38 @@ feature {NONE} -- Implementation
|
||||
unicode_regex := "\\u[0-9a-fA-F]{4}"
|
||||
regexp.compile (unicode_regex)
|
||||
if regexp.matches (a_unicode) then
|
||||
Result := true
|
||||
check
|
||||
is_valid: a_unicode.is_equal (regexp.captured_substring (0))
|
||||
end
|
||||
Result := True
|
||||
check
|
||||
is_valid: a_unicode.is_equal (regexp.captured_substring (0))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
extra_elements: BOOLEAN is
|
||||
--has more elements?
|
||||
-- has more elements?
|
||||
local
|
||||
c: like actual
|
||||
do
|
||||
|
||||
if has_next then
|
||||
next
|
||||
end
|
||||
from
|
||||
c := actual
|
||||
until
|
||||
not actual.is_equal (' ') or not actual.is_equal ('%R') or
|
||||
not actual.is_equal ('%U') or not actual.is_equal ('%T')
|
||||
or not actual.is_equal ('%N') or not has_next
|
||||
c /= ' ' or c /= '%R' or c /= '%U' or c /= '%T' or c /= '%N' or not has_next
|
||||
loop
|
||||
next
|
||||
end
|
||||
|
||||
if has_next then
|
||||
Result := True
|
||||
end
|
||||
|
||||
Result := has_next
|
||||
end
|
||||
|
||||
feature {NONE} -- Constants
|
||||
|
||||
false_id: STRING is "false"
|
||||
|
||||
true_id: STRING is "false"
|
||||
|
||||
null_id: STRING is "null"
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -1,56 +1,36 @@
|
||||
indexing
|
||||
|
||||
description: "Objects that ..."
|
||||
author: "jvelilla"
|
||||
date: "2008/08/24"
|
||||
revision: "0.1"
|
||||
|
||||
class
|
||||
|
||||
JSON_READER
|
||||
|
||||
create
|
||||
|
||||
make
|
||||
|
||||
feature -- Initialization
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a_json: STRING) is
|
||||
--
|
||||
-- Initialize Reader
|
||||
do
|
||||
representation := a_json
|
||||
index := 1
|
||||
end
|
||||
|
||||
|
||||
feature -- Commands
|
||||
|
||||
read: CHARACTER is
|
||||
--
|
||||
-- Read character
|
||||
do
|
||||
if not representation.is_empty then
|
||||
Result := representation.item (index)
|
||||
end
|
||||
end
|
||||
|
||||
has_next: BOOLEAN is
|
||||
--
|
||||
do
|
||||
if index <= representation.count then
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
|
||||
has_previous: BOOLEAN is
|
||||
--
|
||||
do
|
||||
if index >=1 then
|
||||
Result := True
|
||||
end
|
||||
end
|
||||
|
||||
next is
|
||||
--
|
||||
-- Move to next index
|
||||
require
|
||||
has_more_elements: has_next
|
||||
do
|
||||
@@ -60,7 +40,7 @@ feature -- Commands
|
||||
end
|
||||
|
||||
previous is
|
||||
--
|
||||
-- Move to previous index
|
||||
require
|
||||
not_is_first: has_previous
|
||||
do
|
||||
@@ -69,30 +49,46 @@ feature -- Commands
|
||||
incremented: old index - 1 = index
|
||||
end
|
||||
|
||||
|
||||
skip_withe_spaces is
|
||||
-- Remove withe spaces
|
||||
skip_white_spaces is
|
||||
-- Remove white spaces
|
||||
local
|
||||
c: like actual
|
||||
do
|
||||
from
|
||||
until (actual /= ' ' and actual /= '%N' and actual /= '%R') or not has_next
|
||||
c := actual
|
||||
until
|
||||
(c /= ' ' and c /= '%N' and c /= '%R') or not has_next
|
||||
loop
|
||||
next
|
||||
c := actual
|
||||
end
|
||||
end
|
||||
|
||||
json_substring (start_index, end_index: INTEGER_32): STRING is
|
||||
--
|
||||
-- JSON representation between `start_index' and `end_index'
|
||||
do
|
||||
Result := representation.substring (start_index, end_index)
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_next: BOOLEAN is
|
||||
-- Has a next character?
|
||||
do
|
||||
Result := index <= representation.count
|
||||
end
|
||||
|
||||
has_previous: BOOLEAN is
|
||||
-- Has a previous character?
|
||||
do
|
||||
Result := index >= 1
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
representation: STRING
|
||||
-- Serialized representation of the original JSON string
|
||||
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
actual: CHARACTER is
|
||||
@@ -108,9 +104,7 @@ feature {NONE} -- Implementation
|
||||
index: INTEGER
|
||||
-- Actual index
|
||||
|
||||
|
||||
invariant
|
||||
|
||||
representation_not_void: representation /= Void
|
||||
|
||||
end
|
||||
|
||||
@@ -8,29 +8,42 @@ class
|
||||
JSON_TOKENS
|
||||
|
||||
feature -- Access
|
||||
J_OBJECT_OPEN:CHARACTER is '{'
|
||||
J_ARRAY_OPEN:CHARACTER is '['
|
||||
J_OBJECT_CLOSE:CHARACTER is '}'
|
||||
J_ARRAY_CLOSE:CHARACTER is ']'
|
||||
|
||||
J_STRING:CHARACTER is '"'
|
||||
J_PLUS:CHARACTER is '+'
|
||||
J_MINUS:CHARACTER is '-'
|
||||
J_DOT:CHARACTER is '.'
|
||||
j_OBJECT_OPEN: CHARACTER is '{'
|
||||
j_ARRAY_OPEN: CHARACTER is '['
|
||||
j_OBJECT_CLOSE: CHARACTER is '}'
|
||||
j_ARRAY_CLOSE: CHARACTER is ']'
|
||||
|
||||
j_STRING: CHARACTER is '"'
|
||||
j_PLUS: CHARACTER is '+'
|
||||
j_MINUS: CHARACTER is '-'
|
||||
j_DOT: CHARACTER is '.'
|
||||
|
||||
feature -- Status report
|
||||
|
||||
is_open_token (c: CHARACTER): BOOLEAN is
|
||||
-- Characters which open a type
|
||||
do
|
||||
inspect c
|
||||
when j_OBJECT_OPEN, j_ARRAY_OPEN, j_STRING, j_PLUS, j_MINUS, j_DOT then
|
||||
Result := True
|
||||
else
|
||||
|
||||
open_tokens:ARRAY[CHARACTER] is
|
||||
-- Characters wich open a type
|
||||
once
|
||||
Result:=<<J_OBJECT_OPEN,J_ARRAY_OPEN,J_STRING,J_PLUS,J_MINUS,J_DOT>>
|
||||
end
|
||||
end
|
||||
|
||||
is_close_token (c: CHARACTER): BOOLEAN is
|
||||
-- Characters which close a type
|
||||
do
|
||||
inspect c
|
||||
when j_OBJECT_CLOSE, j_ARRAY_CLOSE, j_STRING then
|
||||
Result := True
|
||||
else
|
||||
|
||||
close_tokens:ARRAY[CHARACTER] is
|
||||
-- Characters wich close a type
|
||||
once
|
||||
Result:=<<J_OBJECT_CLOSE,J_ARRAY_CLOSE,J_STRING >>
|
||||
end
|
||||
end
|
||||
|
||||
special_characters:ARRAY[CHARACTER] is
|
||||
is_special_character (c: CHARACTER): BOOLEAN is
|
||||
-- Control Characters
|
||||
-- %F Form feed
|
||||
-- %H backslasH
|
||||
@@ -40,14 +53,25 @@ feature -- Access
|
||||
-- %B Backspace
|
||||
-- / Solidus
|
||||
-- " Quotation
|
||||
do
|
||||
Result:=<<'%F','%H','%N','%R','%T','%B','/','"'>>
|
||||
end
|
||||
do
|
||||
inspect c
|
||||
when '%F', '%H', '%N', '%R', '%T', '%B', '/', '"' then
|
||||
Result := True
|
||||
else
|
||||
|
||||
special_controls:ARRAY[CHARACTER] is
|
||||
end
|
||||
end
|
||||
|
||||
is_special_control (c: CHARACTER): BOOLEAN is
|
||||
--Control Characters
|
||||
-- \b\f\n\r\t
|
||||
do
|
||||
Result:=<<'b','f','n','r','t'>>
|
||||
end
|
||||
do
|
||||
inspect c
|
||||
when 'b', 'f', 'n', 'r', 't' then
|
||||
Result := True
|
||||
else
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -35,7 +35,6 @@ feature -- Visitor Pattern
|
||||
deferred
|
||||
end
|
||||
|
||||
|
||||
visit_json_number (a_json_number: JSON_NUMBER) is
|
||||
-- Visit `a_json_number'.
|
||||
require
|
||||
@@ -57,5 +56,4 @@ feature -- Visitor Pattern
|
||||
deferred
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
@@ -13,39 +13,41 @@ inherit
|
||||
create make
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make is
|
||||
-- Create a new instance
|
||||
do
|
||||
create to_json.make_empty
|
||||
create to_json.make_empty
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
to_json:STRING
|
||||
to_json: STRING
|
||||
-- JSON representation
|
||||
|
||||
feature -- Visitor Pattern
|
||||
|
||||
visit_json_array (a_json_array: JSON_ARRAY) is
|
||||
-- Visit `a_json_array'.
|
||||
local
|
||||
value:JSON_VALUE
|
||||
l_json_array:ARRAYED_LIST[JSON_VALUE]
|
||||
value: JSON_VALUE
|
||||
l_json_array: ARRAYED_LIST [JSON_VALUE]
|
||||
do
|
||||
l_json_array:=a_json_array.array_representation
|
||||
to_json.append("[")
|
||||
from
|
||||
l_json_array.start
|
||||
until
|
||||
l_json_array.off
|
||||
loop
|
||||
value:=l_json_array.item
|
||||
value.accept (Current)
|
||||
l_json_array.forth
|
||||
if not l_json_array.after then
|
||||
to_json.append(",")
|
||||
end
|
||||
l_json_array:=a_json_array.array_representation
|
||||
to_json.append ("[")
|
||||
from
|
||||
l_json_array.start
|
||||
until
|
||||
l_json_array.off
|
||||
loop
|
||||
value := l_json_array.item
|
||||
value.accept (Current)
|
||||
l_json_array.forth
|
||||
if not l_json_array.after then
|
||||
to_json.append(",")
|
||||
end
|
||||
to_json.append("]")
|
||||
end
|
||||
to_json.append ("]")
|
||||
end
|
||||
|
||||
visit_json_boolean (a_json_boolean: JSON_BOOLEAN) is
|
||||
@@ -60,7 +62,6 @@ feature -- Visitor Pattern
|
||||
to_json.append ("null")
|
||||
end
|
||||
|
||||
|
||||
visit_json_number (a_json_number: JSON_NUMBER) is
|
||||
-- Visit `a_json_number'.
|
||||
do
|
||||
@@ -72,7 +73,7 @@ feature -- Visitor Pattern
|
||||
local
|
||||
l_pairs: HASH_TABLE[JSON_VALUE,JSON_STRING]
|
||||
do
|
||||
l_pairs:=a_json_object.map_representation
|
||||
l_pairs := a_json_object.map_representation
|
||||
to_json.append ("{")
|
||||
from
|
||||
l_pairs.start
|
||||
|
||||
Reference in New Issue
Block a user