Cosmetic + Optimization + Assertion + Void-safety

(no significant interface changes)
This commit is contained in:
jfiat
2009-03-18 15:29:41 +00:00
parent 1359a1ceae
commit 548a320448
13 changed files with 1367 additions and 1273 deletions

View File

@@ -1,104 +1,122 @@
indexing indexing
description: "[ description: "[
JSON_ARRAY represent an array in JSON. JSON_ARRAY represent an array in JSON.
An array in JSON is an ordered set of names. An array in JSON is an ordered set of names.
Examples Examples
array array
[] []
[elements] [elements]
]" ]"
author: "Javier Velilla" author: "Javier Velilla"
date: "2008/08/24" date: "2008/08/24"
revision: "Revision 0.1" revision: "Revision 0.1"
class class
JSON_ARRAY JSON_ARRAY
inherit
JSON_VALUE inherit
JSON_VALUE
create
make_array DEBUG_OUTPUT
feature -- Initialization create
make_array is make_array
--
do feature {NONE} -- Initialization
create values.make (10)
end make_array is
-- Initialize JSON Array
feature -- Access do
i_th alias "[]" (i: INTEGER):JSON_VALUE is create values.make (10)
-- Item at `i'-th position end
require
is_valid_index:valid_index (i) feature -- Access
do
Result := values.i_th (i) i_th alias "[]" (i: INTEGER): JSON_VALUE is
end -- Item at `i'-th position
require
feature -- Visitor pattern is_valid_index: valid_index (i)
do
accept (a_visitor: JSON_VISITOR) is Result := values.i_th (i)
-- Accept `a_visitor'. end
-- (Call `visit_json_array' procedure on `a_visitor'.)
do feature -- Visitor pattern
a_visitor.visit_json_array (Current)
end accept (a_visitor: JSON_VISITOR) is
-- Accept `a_visitor'.
feature -- Mesurement -- (Call `visit_json_array' procedure on `a_visitor'.)
count:INTEGER is do
-- Number of items. a_visitor.visit_json_array (Current)
do end
Result:=values.count
end feature -- Mesurement
feature -- Status report count: INTEGER is
valid_index (i: INTEGER): BOOLEAN is -- Number of items.
-- Is `i' a valid index? do
do Result := values.count
Result := (1 <= i) and (i <= count) end
end
feature -- Status report
feature -- Change Element
add(value:JSON_VALUE) is valid_index (i: INTEGER): BOOLEAN is
require -- Is `i' a valid index?
not_null:value /= void do
do Result := (1 <= i) and (i <= count)
values.extend(value) end
ensure
has_new_value:old values.count + 1 = values.count and feature -- Change Element
values.has (value)
end add (value: JSON_VALUE) is
require
feature -- Report value_not_null: value /= void
do
hash_code:INTEGER is values.extend(value)
-- ensure
do has_new_value: old values.count + 1 = values.count and
from values.has (value)
values.start end
Result:=values.item.hash_code
until feature -- Report
values.off
loop hash_code: INTEGER is
Result:= ((Result \\ 8388593) |<< 8) + values.item.hash_code -- Hash code value
values.forth do
end from
Result := Result \\ values.count values.start
Result := values.item.hash_code
end until
feature -- Conversion values.off
loop
array_representation:ARRAYED_LIST[JSON_VALUE] is Result:= ((Result \\ 8388593) |<< 8) + values.item.hash_code
-- Representation as a sequences of values values.forth
do end
Result:=values Result := Result \\ values.count
end end
feature {NONE} --Implementation feature -- Conversion
values:ARRAYED_LIST[JSON_VALUE]
array_representation: ARRAYED_LIST [JSON_VALUE] is
invariant -- Representation as a sequences of values
value_not_void: values /= Void do
Result := values
end 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
end

View File

@@ -1,49 +1,52 @@
indexing indexing
description: "JSON Truth values" description: "JSON Truth values"
author: "Javier Velilla" author: "Javier Velilla"
date: "2008/08/24" date: "2008/08/24"
revision: "Revision 0.1" revision: "Revision 0.1"
class class
JSON_BOOLEAN
JSON_BOOLEAN
inherit
inherit JSON_VALUE
JSON_VALUE
create
create make_boolean
make_boolean feature {NONE} -- Initialization
feature -- Initialization make_boolean (an_item: BOOLEAN) is
--Initialize.
make_boolean (an_item: BOOLEAN) is do
--Initialize. item := an_item
do end
item := an_item
end feature -- Access
feature -- Access item: BOOLEAN
-- Content
item: BOOLEAN
-- Content hash_code: INTEGER is
-- Hash code value
do
hash_code: INTEGER is Result := item.hash_code
--Hash code value end
do
Result := item.hash_code feature -- Visitor pattern
end
accept (a_visitor: JSON_VISITOR) is
feature -- Visitor pattern -- Accept `a_visitor'.
-- (Call `visit_json_boolean' procedure on `a_visitor'.)
accept (a_visitor: JSON_VISITOR) is do
-- Accept `a_visitor'. a_visitor.visit_json_boolean (Current)
-- (Call `visit_json_boolean' procedure on `a_visitor'.) end
do
a_visitor.visit_json_boolean (Current) feature -- Status report
end
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
end Result := item.out
end
end

View File

@@ -8,28 +8,31 @@ class
JSON_FILE_READER JSON_FILE_READER
feature -- Access 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) read_json_from (a_path: STRING): ?STRING is
-- We perform several checks until we make a real attempt to open the file. local
if not l_file.exists then l_file: PLAIN_TEXT_FILE
print ("error: '" + a_path + "' does not exist%N") template_content: STRING
else l_last_string: ?STRING
if not l_file.is_readable then do
print ("error: '" + a_path + "' is not readable.%N") create l_file.make (a_path)
else -- We perform several checks until we make a real attempt to open the file.
l_file.open_read if not l_file.exists then
create template_content.make_empty print ("error: '" + a_path + "' does not exist%N")
l_file.read_stream (l_file.count) else
template_content.append (l_file.last_string.twin) if not l_file.is_readable then
Result := template_content print ("error: '" + a_path + "' is not readable.%N")
l_file.close else
end l_file.open_read
end create template_content.make_empty
end 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 end

View File

@@ -1,30 +1,42 @@
indexing indexing
description: "JSON Null Values" description: "JSON Null Values"
author: "Javier Velilla" author: "Javier Velilla"
date: "2008/08/24" date: "2008/08/24"
revision: "Revision 0.1" revision: "Revision 0.1"
class class
JSON_NULL JSON_NULL
inherit
JSON_VALUE inherit
JSON_VALUE
feature --Access
feature --Access
hash_code:INTEGER is
-- Hash code value hash_code: INTEGER is
do -- Hash code value
Result:= null_value.hash_code do
end Result := null_value.hash_code
feature -- Visitor pattern end
accept (a_visitor: JSON_VISITOR) is feature -- Visitor pattern
-- Accept `a_visitor'.
-- (Call `visit_element_a' procedure on `a_visitor'.) accept (a_visitor: JSON_VISITOR) is
do -- Accept `a_visitor'.
a_visitor.visit_json_null (Current) -- (Call `visit_element_a' procedure on `a_visitor'.)
end do
a_visitor.visit_json_null (Current)
feature {NONE}-- Implementation end
null_value:STRING is "null"
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"
end

View File

@@ -1,85 +1,85 @@
indexing indexing
description: "JSON Numbers, octal and hexadecimal formats are not used." description: "JSON Numbers, octal and hexadecimal formats are not used."
author: "Javier Velilla" author: "Javier Velilla"
date: "2008/08/24" date: "2008/08/24"
revision: "Revision 0.1" revision: "Revision 0.1"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)" license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
class class
JSON_NUMBER JSON_NUMBER
inherit inherit
JSON_VALUE
JSON_VALUE redefine
redefine is_equal
is_equal end
end
create
make_integer,
create make_real
make_integer, feature {NONE} -- initialization
make_real
make_integer (an_argument: INTEGER) is
feature -- initialization -- Initialize an instance of JSON_NUMBER as INTEGER
do
make_integer (an_argument: INTEGER) is item := an_argument.out
-- Initialize an instance of JSON_NUMBER as INTEGER numeric_type := INTEGER_TYPE
do end
item := an_argument.out
numeric_type := INTEGER_TYPE make_real (an_argument: DOUBLE) is
end -- Initialize an instance of JSON_NUMBER as DOUBLE
do
make_real (an_argument: DOUBLE) is item := an_argument.out
-- Initialize an instance of JSON_NUMBER as DOUBLE numeric_type := DOUBLE_TYPE
do end
item := an_argument.out
numeric_type := DOUBLE_TYPE feature -- Access
end
item: STRING
-- Content
feature -- Access
hash_code: INTEGER is
item: STRING --Hash code value
-- Content do
Result := item.hash_code
hash_code: INTEGER is end
--Hash code value
do feature -- Visitor pattern
Result:=item.hash_code
end accept (a_visitor: JSON_VISITOR) is
-- Accept `a_visitor'.
feature -- Visitor pattern -- (Call `visit_json_number' procedure on `a_visitor'.)
do
accept (a_visitor: JSON_VISITOR) is a_visitor.visit_json_number (Current)
-- Accept `a_visitor'. end
-- (Call `visit_json_number' procedure on `a_visitor'.)
do feature -- Status
a_visitor.visit_json_number (Current)
end is_equal (other: like Current): BOOLEAN is
-- Is `other' attached to an object of the same type
feature -- Status -- as current object and identical to it?
do
is_equal (other: like Current): BOOLEAN is Result := item.is_equal (other.item)
-- Is `other' attached to an object of the same type end
-- as current object and identical to it?
do feature -- Status report
Result := item.is_equal (other.item)
end debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := item
feature -- Implementation end
INTEGER_TYPE: INTEGER is 1 feature -- Implementation
DOUBLE_TYPE: INTEGER is 2
INTEGER_TYPE: INTEGER is 1
numeric_type: INTEGER DOUBLE_TYPE: INTEGER is 2
numeric_type: INTEGER
invariant
invariant
item_not_void: item /= Void item_not_void: item /= Void
end end

View File

@@ -1,132 +1,130 @@
indexing indexing
description: "[ description: "[
An JSON_OBJECT represent an object in JSON. An JSON_OBJECT represent an object in JSON.
An object is an unordered set of name/value pairs An object is an unordered set of name/value pairs
Examples: Examples:
object object
{} {}
{"key","value"} {"key","value"}
]"
]" author: "Javier Velilla"
author: "Javier Velilla" date: "2008/08/24"
date: "2008/08/24" revision: "Revision 0.1"
revision: "Revision 0.1" license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
class
JSON_OBJECT
class
inherit
JSON_OBJECT JSON_VALUE
inherit create
make
JSON_VALUE
feature {NONE} -- Initialization
create
make is
make -- Initialize
do
feature -- Initialization create object.make (10)
end
make is
-- Initialize feature -- Change Element
do
create object.make (10) put (value: ?JSON_VALUE; key: JSON_STRING) is
end -- Assuming there is no item of key `key',
-- insert `value' with `key'.
feature -- Change Element require
key_not_present: not has_key (key)
local
put (value: JSON_VALUE ; key: JSON_STRING) is l_value: ?JSON_VALUE
-- Assuming there is no item of key `key', do
-- insert `value' with `key'. l_value := value
require if l_value = Void then
not_present: not has_key (key) create {JSON_NULL} l_value
local end
l_json_null: JSON_NULL object.extend (l_value, key)
l_value: JSON_VALUE end
do
l_value:=value feature -- Access
if value = Void then
create l_json_null has_key (key: JSON_STRING): BOOLEAN is
l_value:=l_json_null -- has the JSON_OBJECT contains a specific key 'key'.
end do
object.extend (l_value,key) Result := object.has (key)
end end
has_item (value: JSON_VALUE): BOOLEAN is
feature -- Access -- has the JSON_OBJECT contain a specfic item 'value'
do
has_key (key: JSON_STRING):BOOLEAN is Result := object.has_item (value)
-- has the JSON_OBJECT contains a specific key 'key'. end
do
Result := object.has (key) item (key: JSON_STRING): ?JSON_VALUE is
end -- the json_value associated with a key.
do
has_item (value: JSON_VALUE):BOOLEAN is Result := object.item (key)
-- has the JSON_OBJECT contain a specfic item 'value' end
do
Result := object.has_item (value) current_keys: ARRAY [JSON_STRING] is
end -- array containing actually used keys
do
item (key: JSON_STRING):JSON_VALUE is Result := object.current_keys
-- the json_value associated with a key. end
do
Result:= object.item (key) feature -- Visitor pattern
end
accept (a_visitor: JSON_VISITOR) is
current_keys: ARRAY [JSON_STRING] is -- Accept `a_visitor'.
-- array containing actually used keys -- (Call `visit_json_object' procedure on `a_visitor'.)
do do
Result:=object.current_keys a_visitor.visit_json_object (Current)
end end
feature -- Visitor pattern feature -- Conversion
accept (a_visitor: JSON_VISITOR) is map_representation: HASH_TABLE [JSON_VALUE, JSON_STRING] is
-- Accept `a_visitor'. --A representation that maps keys to values
-- (Call `visit_json_object' procedure on `a_visitor'.) do
do Result := object
a_visitor.visit_json_object (Current) end
end
feature -- Report
feature -- Conversion hash_code: INTEGER is
map_representation: HASH_TABLE[JSON_VALUE,JSON_STRING] is -- Hash code value
--A representation that maps keys to values do
do from
Result:=object object.start
end Result := object.item_for_iteration.hash_code
until
feature -- Report object.off
loop
hash_code: INTEGER is Result := ((Result \\ 8388593) |<< 8) + object.item_for_iteration.hash_code
-- Hash code value object.forth
local end
do -- Ensure it is a positive value.
from Result := Result.hash_code
object.start end
Result := object.item_for_iteration.hash_code
until feature -- Status report
object.off
loop debug_output: STRING
Result := ((Result \\ 8388593) |<< 8) + object.item_for_iteration.hash_code -- String that should be displayed in debugger to represent `Current'.
object.forth do
end Result := object.count.out
-- Ensure it is a positive value. end
Result := Result.hash_code
end feature {NONE} -- Implementation
object: HASH_TABLE [JSON_VALUE, JSON_STRING]
feature {NONE} -- Implementation -- Value container
object: HASH_TABLE[JSON_VALUE,JSON_STRING] invariant
object_not_null: object /= Void
invariant
object_not_null: object /= Void end
end

View File

@@ -1,86 +1,89 @@
indexing indexing
description:"[ description:"[
A JSON_STRING represent a string in JSON. A JSON_STRING represent a string in JSON.
A string is a collection of zero or more Unicodes characters, wrapped in double A string is a collection of zero or more Unicodes characters, wrapped in double
quotes, using blackslash espaces. quotes, using blackslash espaces.
]" ]"
author: "Javier Velilla" author: "Javier Velilla"
date: "2008/08/24" date: "2008/08/24"
revision: "Revision 0.1" revision: "Revision 0.1"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)" license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
class class
JSON_STRING
JSON_STRING
inherit
inherit JSON_VALUE
redefine
JSON_VALUE is_equal
redefine end
is_equal
end create
make_json
create
feature {NONE} -- Initialization
make_json
make_json (an_item: STRING) is
feature -- Initialization -- Initialize.
require
make_json (an_item: STRING) is item_not_void: an_item /= Void
-- Initialize. do
require item := an_item
item_not_void: an_item /= Void end
do
item := an_item feature -- Access
end
item: STRING
-- Contents
feature -- Access
feature -- Visitor pattern
item: STRING
-- Contents accept (a_visitor: JSON_VISITOR) is
-- Accept `a_visitor'.
feature -- Visitor pattern -- (Call `visit_json_string' procedure on `a_visitor'.)
do
accept (a_visitor: JSON_VISITOR) is a_visitor.visit_json_string (Current)
-- Accept `a_visitor'. end
-- (Call `visit_json_string' procedure on `a_visitor'.)
do feature -- Comparison
a_visitor.visit_json_string (Current)
end is_equal (other: like Current): BOOLEAN is
-- Is JSON_STRING made of same character sequence as `other'
-- (possibly with a different capacity)?
feature -- Comparison do
Result := item.is_equal (other.item)
is_equal (other: like Current): BOOLEAN is end
-- Is JSON_STRING made of same character sequence as `other'
-- (possibly with a different capacity)? feature -- Change Element
do
Result := item.is_equal (other.item) append (a_string: STRING)is
end -- Add an_item
require
feature -- Change Element a_string_not_void: a_string /= Void
do
append (an_item: STRING)is item.append_string (a_string)
-- Add an_item end
do
item.append_string (an_item) feature -- Status report
end
hash_code: INTEGER is
-- Hash code value
feature -- Status report do
Result := item.hash_code
hash_code: INTEGER is end
-- Hash code value
do feature -- Status report
Result := item.hash_code
end debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
invariant do
Result := item
value_not_void: item /= Void end
end invariant
value_not_void: item /= Void
end

View File

@@ -1,36 +1,36 @@
indexing indexing
description:"[ description:"[
JSON_VALUE represent a value in JSON. JSON_VALUE represent a value in JSON.
A value can be A value can be
* a string in double quotes * a string in double quotes
* a number * a number
* boolean value(true, false ) * boolean value(true, false )
* null * null
* an object * an object
* an array * an array
]"
author: "Javier Velilla"
]" date: "2008/05/19"
author: "Javier Velilla" revision: "Revision 0.1"
date: "2008/05/19" license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
revision: "Revision 0.1"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
deferred class
JSON_VALUE
deferred class
JSON_VALUE inherit
HASHABLE
inherit
DEBUG_OUTPUT
HASHABLE
feature -- Visitor pattern
feature -- Visitor pattern
accept (a_visitor: JSON_VISITOR) is
accept (a_visitor: JSON_VISITOR) is -- Accept `a_visitor'.
-- Accept `a_visitor'. -- (Call `visit_*' procedure on `a_visitor'.)
-- (Call `visit_*' procedure on `a_visitor'.) require
require a_visitor_not_void: a_visitor /= Void
a_visitor_not_void: a_visitor /= Void deferred
deferred end
end
end end

View File

@@ -1,398 +1,438 @@
indexing indexing
description: "Parse serialized JSON data" description: "Parse serialized JSON data"
author: "jvelilla" author: "jvelilla"
date: "2008/08/24" date: "2008/08/24"
revision: "Revision 0.1" revision: "Revision 0.1"
class class
JSON_PARSER
JSON_PARSER
inherit inherit
JSON_READER JSON_READER
JSON_TOKENS JSON_TOKENS
create create
make_parser
make_parser
feature {NONE} -- Initialize
feature {NONE} -- Initialize
make_parser (a_json: STRING) is
make_parser (a_json: STRING) is -- Initialize.
-- Initialize. require
require json_not_empty: a_json /= Void and then not a_json.is_empty
json_not_empty: a_json /= Void and then not a_json.is_empty do
do make (a_json)
make (a_json) is_parsed := True
is_parsed := True create errors.make
create current_errors.make_empty end
end
feature -- Status report
feature -- Access is_parsed: BOOLEAN
-- Is parsed?
is_parsed: BOOLEAN
errors: LINKED_LIST [STRING]
current_errors: STRING -- Current errors
current_errors: STRING
feature -- Commands -- Current errors as string
do
parse_json: JSON_VALUE is create Result.make_empty
-- from
do errors.start
Result := parse until
if extra_elements then errors.after
is_parsed := false loop
end Result.append_string (errors.item + "%N")
end errors.forth
end
parse: JSON_VALUE is end
--
local feature -- Element change
c: CHARACTER
do report_error (e: STRING) is
if is_parsed then -- Report error `e'
skip_withe_spaces require
c := actual e_not_void: e /= Void
if c.is_equal (j_object_open) then do
Result := parse_object errors.force (e)
elseif c.is_equal (j_string) then end
Result := parse_string
elseif c.is_equal (j_array_open) then feature -- Commands
Result := parse_array
elseif c.is_digit or c.is_equal (j_minus) then parse_json: ?JSON_VALUE is
Result := parse_number -- Parse JSON data `representation'
elseif is_null then do
-- Result := parse
Result := create {JSON_NULL} if extra_elements then
next;next;next is_parsed := False
elseif is_true then end
Result := create {JSON_BOOLEAN}.make_boolean (true) end
next;next;next
elseif is_false then parse: ?JSON_VALUE is
Result := create {JSON_BOOLEAN}.make_boolean (false) -- Parse JSON data `representation'
next;next;next;next local
else c: CHARACTER
is_parsed := false do
current_errors.append ("JSON is not well formed in parse") if is_parsed then
Result := void skip_white_spaces
end c := actual
end inspect c
end when j_OBJECT_OPEN then
Result := parse_object
parse_object: JSON_OBJECT is when j_STRING then
-- object Result := parse_string
-- {} when j_ARRAY_OPEN then
-- {"key" : "value" [,]} Result := parse_array
else
local if c.is_digit or c = j_MINUS then
has_more: BOOLEAN Result := parse_number
l_json_string: JSON_STRING elseif is_null then
l_value: JSON_VALUE Result := create {JSON_NULL}
do next
create Result.make next
-- check if is an empty object {} next
next elseif is_true then
skip_withe_spaces Result := create {JSON_BOOLEAN}.make_boolean (True)
if actual.is_equal (j_object_close) then next
--is an empty object next
else next
-- a complex object {"key" : "value"} elseif is_false then
previous Result := create {JSON_BOOLEAN}.make_boolean (False)
from has_more := true until not has_more next
loop next
next next
skip_withe_spaces next
l_json_string := parse_string else
next is_parsed := False
skip_withe_spaces report_error ("JSON is not well formed in parse")
if actual.is_equal (':') then Result := Void
next end
skip_withe_spaces end
else end
is_parsed := false ensure
current_errors.append ("%N Input string is a not well formed JSON, expected: : found: " + actual.out +"%N") is_parsed_implies_result_not_void: is_parsed implies Result /= Void
has_more := false end
end
parse_object: JSON_OBJECT is
l_value := parse -- object
if is_parsed then -- {}
Result.put (l_value,l_json_string) -- {"key" : "value" [,]}
next local
skip_withe_spaces has_more: BOOLEAN
if actual.is_equal (j_object_close) then l_json_string: ?JSON_STRING
has_more := false l_value: ?JSON_VALUE
elseif not actual.is_equal (',') then do
has_more := false create Result.make
is_parsed := false -- check if is an empty object {}
current_errors.append ("JSON Object sintactically malformed expected , found: [" + actual.out + "] %N") next
end skip_white_spaces
else if actual = j_OBJECT_CLOSE then
has_more := false --is an empty object
-- explain the error else
end -- a complex object {"key" : "value"}
end previous
end from has_more := True until not has_more loop
end next
skip_white_spaces
parse_string: JSON_STRING is l_json_string := parse_string
-- next
local skip_white_spaces
has_more: BOOLEAN if actual = ':' then
l_json_string: STRING next
l_unicode: STRING skip_white_spaces
do else
create l_json_string.make_empty is_parsed := False
if actual.is_equal (j_string) then report_error ("%N Input string is a not well formed JSON, expected: : found: " + actual.out)
from has_more := False
has_more := true end
until not has_more
l_value := parse
loop if is_parsed and then (l_value /= Void and l_json_string /= Void) then
next Result.put (l_value, l_json_string)
if actual.is_equal (j_string) then next
has_more := false skip_white_spaces
elseif actual.is_equal ('%H') then if actual = j_OBJECT_CLOSE then
next has_more := False
if actual.is_equal ('u') then elseif actual /= ',' then
create l_unicode.make_from_string ("\u") has_more := False
l_unicode.append (read_unicode) is_parsed := False
if is_a_valid_unicode (l_unicode) then report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]")
l_json_string.append (l_unicode) end
else else
has_more := false has_more := False
is_parsed := false -- explain the error
current_errors.append ("Input String is not well formed JSON, expected a Unicode value, found [" + actual.out + " ] %N") end
end end
elseif (not special_characters.has (actual) and not special_controls.has (actual)) or actual.is_equal ('%N') then end
has_more := false end
is_parsed := false
current_errors.append ("Input String is not well formed JSON, found [" + actual.out + " ] %N") parse_string: ?JSON_STRING is
-- Parsed string
else local
l_json_string.append ("\") has_more: BOOLEAN
l_json_string.append (actual.out) l_json_string: STRING
l_unicode: STRING
end c: like actual
do
else create l_json_string.make_empty
if special_characters.has (actual) and not actual.is_equal ('/') then if actual = j_STRING then
has_more := false from
is_parsed := false has_more := True
current_errors.append ("Input String is not well formed JSON, found [" + actual.out + " ] %N") until
else not has_more
l_json_string.append (actual.out) loop
end next
end c := actual
end if c = j_STRING then
create Result.make_json (l_json_string) has_more := False
else elseif c = '%H' then
Result := void next
end c := actual
end if c = 'u' then
create l_unicode.make_from_string ("\u")
parse_array: JSON_ARRAY is l_unicode.append (read_unicode)
-- array c := actual
-- [] if is_a_valid_unicode (l_unicode) then
-- [elements [,]] l_json_string.append (l_unicode)
local else
flag: BOOLEAN has_more := False
l_value: JSON_VALUE is_parsed := False
do report_error ("Input String is not well formed JSON, expected a Unicode value, found [" + c.out + " ]")
create Result.make_array end
--check if is an empty array [] elseif (not is_special_character (c) and not is_special_control (c)) or c = '%N' then
next has_more := False
skip_withe_spaces is_parsed := False
if actual.is_equal (j_array_close) then report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
--is an empty array else
else l_json_string.append ("\")
previous l_json_string.append (c.out)
from end
flag := true else
until if is_special_character (c) and c /= '/' then
not flag has_more := False
loop is_parsed := False
next report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
skip_withe_spaces else
l_value := parse l_json_string.append_character (c)
if is_parsed then end
Result.add (l_value) end
next end
skip_withe_spaces create Result.make_json (l_json_string)
if not actual.is_equal (j_array_close) and not actual.is_equal (',')then else
flag := false Result := Void
is_parsed := false end
current_errors.append ("Array is not well formed JSON, found [" + actual.out + " ] %N") end
elseif actual.is_equal (j_array_close) then
flag := false parse_array: JSON_ARRAY is
end -- array
else -- []
flag := false -- [elements [,]]
current_errors.append ("Array is not well formed JSON, found [" + actual.out + " ] %N") local
end flag: BOOLEAN
end l_value: ?JSON_VALUE
end c: like actual
end do
create Result.make_array
parse_number: JSON_NUMBER is --check if is an empty array []
-- next
local skip_white_spaces
sb: STRING if actual = j_array_close then
flag: BOOLEAN --is an empty array
is_integer: BOOLEAN else
do previous
create sb.make_empty from
sb.append (actual.out) flag := True
until
from not flag
flag := true loop
until not flag next
loop skip_white_spaces
next l_value := parse
if not has_next or close_tokens.has (actual) or actual.is_equal (',') if is_parsed and then l_value /= Void then
or actual.is_equal ('%N') or actual.is_equal ('%R') then Result.add (l_value)
flag := false next
previous skip_white_spaces
else c := actual
sb.append (actual.out) if c = j_ARRAY_CLOSE then
end flag := False
end elseif c /= ',' then
flag := False
if is_a_valid_number (sb) then is_parsed := False
if sb.is_integer then report_error ("Array is not well formed JSON, found [" + c.out + " ]")
create Result.make_integer (sb.to_integer) end
is_integer := true else
elseif sb.is_double and not is_integer then flag := False
create Result.make_real (sb.to_double) report_error ("Array is not well formed JSON, found [" + actual.out + " ]")
end end
else end
is_parsed := false end
current_errors.append ("Expected a number, found: [ " + sb + " ]") end
end
end parse_number: ?JSON_NUMBER is
-- Parsed number
is_null: BOOLEAN is local
-- sb: STRING
local flag: BOOLEAN
l_null: STRING is_integer: BOOLEAN
l_string: STRING c: like actual
do do
l_null := "null" create sb.make_empty
l_string := json_substring (index,index + l_null.count - 1) sb.append_character (actual)
if l_string.is_equal (l_null) then
Result := true from
end flag := True
end until
not flag
is_false: BOOLEAN is loop
-- next
local c := actual
l_false: STRING if not has_next or is_close_token (c)
l_string: STRING or c = ',' or c = '%N' or c = '%R'
do then
l_false := "false" flag := False
l_string := json_substring (index,index + l_false.count - 1) previous
if l_string.is_equal (l_false) then else
Result := true sb.append_character (c)
end end
end end
is_true: BOOLEAN is if is_a_valid_number (sb) then
-- if sb.is_integer then
local create Result.make_integer (sb.to_integer)
l_true: STRING is_integer := True
l_string: STRING elseif sb.is_double and not is_integer then
do create Result.make_real (sb.to_double)
l_true := "true" end
l_string := json_substring (index,index + l_true.count - 1) else
if l_string.is_equal (l_true) then is_parsed := False
Result := true report_error ("Expected a number, found: [ " + sb + " ]")
end end
end end
read_unicode: STRING is is_null: BOOLEAN is
-- -- Word at index represents null?
local local
i: INTEGER l_null: STRING
do l_string: STRING
create Result.make_empty do
from l_null := null_id
i := 1 l_string := json_substring (index,index + l_null.count - 1)
until i > 4 or not has_next if l_string.is_equal (l_null) then
Result := True
loop end
next end
Result.append (actual.out)
i := i + 1 is_false: BOOLEAN is
end -- Word at index represents false?
end local
l_false: STRING
l_string: STRING
feature {NONE} -- Implementation do
l_false := false_id
is_a_valid_number (a_number: STRING): BOOLEAN is l_string := json_substring (index, index + l_false.count - 1)
-- is 'a_number' a valid number based on this regular expression if l_string.is_equal (l_false) then
-- "-?(?: 0|[1-9]\d+)(?: \.\d+)?(?: [eE][+-]?\d+)?\b"? Result := True
local end
word_set: RX_CHARACTER_SET end
regexp: RX_PCRE_REGULAR_EXPRESSION
number_regex: STRING is_true: BOOLEAN is
do -- Word at index represents true?
create regexp.make local
create word_set.make_empty l_true: STRING
a_number.right_adjust l_string: STRING
a_number.left_adjust do
word_set.add_string ("0123456789.eE+-") l_true := true_id
regexp.set_word_set (word_set) l_string := json_substring (index,index + l_true.count - 1)
number_regex := "-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?\b" if l_string.is_equal (l_true) then
regexp.compile (number_regex) Result := True
if regexp.matches (a_number) then end
if a_number.is_equal (regexp.captured_substring (0)) then end
Result := true
end read_unicode: STRING is
end -- Read unicode and return value
end local
i: INTEGER
is_a_valid_unicode (a_unicode: STRING): BOOLEAN is do
-- is 'a_unicode' a valid unicode based on this regular expression create Result.make_empty
-- "\\u[0-9a-fA-F]{4}" from
local i := 1
regexp: RX_PCRE_REGULAR_EXPRESSION until
unicode_regex: STRING i > 4 or not has_next
do loop
create regexp.make next
unicode_regex := "\\u[0-9a-fA-F]{4}" Result.append_character (actual)
regexp.compile (unicode_regex) i := i + 1
if regexp.matches (a_unicode) then end
Result := true end
check
is_valid: a_unicode.is_equal (regexp.captured_substring (0)) feature {NONE} -- Implementation
end
end is_a_valid_number (a_number: STRING): BOOLEAN is
end -- is 'a_number' a valid number based on this regular expression
-- "-?(?: 0|[1-9]\d+)(?: \.\d+)?(?: [eE][+-]?\d+)?\b"?
extra_elements: BOOLEAN is local
--has more elements? word_set: RX_CHARACTER_SET
do regexp: RX_PCRE_REGULAR_EXPRESSION
number_regex: STRING
if has_next then do
next create regexp.make
end create word_set.make_empty
from a_number.right_adjust
until a_number.left_adjust
not actual.is_equal (' ') or not actual.is_equal ('%R') or word_set.add_string ("0123456789.eE+-")
not actual.is_equal ('%U') or not actual.is_equal ('%T') regexp.set_word_set (word_set)
or not actual.is_equal ('%N') or not has_next number_regex := "-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?\b"
loop regexp.compile (number_regex)
next if regexp.matches (a_number) then
end Result := a_number.is_equal (regexp.captured_substring (0))
end
if has_next then end
Result := True
end is_a_valid_unicode (a_unicode: STRING): BOOLEAN is
-- is 'a_unicode' a valid unicode based on this regular expression
end -- "\\u[0-9a-fA-F]{4}"
local
regexp: RX_PCRE_REGULAR_EXPRESSION
end unicode_regex: STRING
do
create regexp.make
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
end
end
extra_elements: BOOLEAN is
-- has more elements?
local
c: like actual
do
if has_next then
next
end
from
c := actual
until
c /= ' ' or c /= '%R' or c /= '%U' or c /= '%T' or c /= '%N' or not has_next
loop
next
end
Result := has_next
end
feature {NONE} -- Constants
false_id: STRING is "false"
true_id: STRING is "false"
null_id: STRING is "null"
end

View File

@@ -1,116 +1,110 @@
indexing indexing
description: "Objects that ..."
description: "Objects that ..." author: "jvelilla"
author: "jvelilla" date: "2008/08/24"
date: "2008/08/24" revision: "0.1"
revision: "0.1"
class
class JSON_READER
JSON_READER create
make
create
feature {NONE} -- Initialization
make
make (a_json: STRING) is
feature -- Initialization -- Initialize Reader
do
make (a_json: STRING) is representation := a_json
-- index := 1
do end
representation := a_json
index := 1 feature -- Commands
end
read: CHARACTER is
-- Read character
feature -- Commands do
if not representation.is_empty then
read: CHARACTER is Result := representation.item (index)
-- end
do end
if not representation.is_empty then
Result := representation.item (index) next is
end -- Move to next index
end require
has_more_elements: has_next
has_next: BOOLEAN is do
-- index := index + 1
do ensure
if index <= representation.count then incremented: old index + 1 = index
Result := True end
end
end previous is
-- Move to previous index
has_previous: BOOLEAN is require
-- not_is_first: has_previous
do do
if index >=1 then index := index - 1
Result := True ensure
end incremented: old index - 1 = index
end end
next is skip_white_spaces is
-- -- Remove white spaces
require local
has_more_elements: has_next c: like actual
do do
index := index + 1 from
ensure c := actual
incremented: old index + 1 = index until
end (c /= ' ' and c /= '%N' and c /= '%R') or not has_next
loop
previous is next
-- c := actual
require end
not_is_first: has_previous end
do
index := index - 1 json_substring (start_index, end_index: INTEGER_32): STRING is
ensure -- JSON representation between `start_index' and `end_index'
incremented: old index - 1 = index do
end Result := representation.substring (start_index, end_index)
end
skip_withe_spaces is feature -- Status report
-- Remove withe spaces
do has_next: BOOLEAN is
from -- Has a next character?
until (actual /= ' ' and actual /= '%N' and actual /= '%R') or not has_next do
loop Result := index <= representation.count
next end
end
end has_previous: BOOLEAN is
-- Has a previous character?
json_substring (start_index, end_index: INTEGER_32): STRING is do
-- Result := index >= 1
do end
Result := representation.substring (start_index, end_index)
end feature -- Access
representation: STRING
feature -- Access -- Serialized representation of the original JSON string
representation: STRING feature {NONE} -- Implementation
-- Serialized representation of the original JSON string
actual: CHARACTER is
-- Current character or '%U' if none
feature {NONE} -- Implementation do
if index > representation.count then
actual: CHARACTER is Result := '%U'
-- Current character or '%U' if none else
do Result := representation.item (index)
if index > representation.count then end
Result := '%U' end
else
Result := representation.item (index) index: INTEGER
end -- Actual index
end
invariant
index: INTEGER representation_not_void: representation /= Void
-- Actual index
end
invariant
representation_not_void: representation /= Void
end

View File

@@ -1,53 +1,77 @@
indexing indexing
description: "" description: ""
author: "jvelilla" author: "jvelilla"
date: "2008/08/24" date: "2008/08/24"
revision: "0.1" revision: "0.1"
class class
JSON_TOKENS JSON_TOKENS
feature -- Access feature -- Access
J_OBJECT_OPEN:CHARACTER is '{'
J_ARRAY_OPEN:CHARACTER is '[' j_OBJECT_OPEN: CHARACTER is '{'
J_OBJECT_CLOSE:CHARACTER is '}' j_ARRAY_OPEN: CHARACTER is '['
J_ARRAY_CLOSE:CHARACTER is ']' j_OBJECT_CLOSE: CHARACTER is '}'
j_ARRAY_CLOSE: CHARACTER is ']'
J_STRING:CHARACTER is '"'
J_PLUS:CHARACTER is '+' j_STRING: CHARACTER is '"'
J_MINUS:CHARACTER is '-' j_PLUS: CHARACTER is '+'
J_DOT:CHARACTER is '.' j_MINUS: CHARACTER is '-'
j_DOT: CHARACTER is '.'
open_tokens:ARRAY[CHARACTER] is
-- Characters wich open a type feature -- Status report
once
Result:=<<J_OBJECT_OPEN,J_ARRAY_OPEN,J_STRING,J_PLUS,J_MINUS,J_DOT>> is_open_token (c: CHARACTER): BOOLEAN is
end -- Characters which open a type
do
close_tokens:ARRAY[CHARACTER] is inspect c
-- Characters wich close a type when j_OBJECT_OPEN, j_ARRAY_OPEN, j_STRING, j_PLUS, j_MINUS, j_DOT then
once Result := True
Result:=<<J_OBJECT_CLOSE,J_ARRAY_CLOSE,J_STRING >> else
end
end
special_characters:ARRAY[CHARACTER] is end
-- Control Characters
-- %F Form feed is_close_token (c: CHARACTER): BOOLEAN is
-- %H backslasH -- Characters which close a type
-- %N Newline do
-- %R carriage Return inspect c
-- %T horizontal Tab when j_OBJECT_CLOSE, j_ARRAY_CLOSE, j_STRING then
-- %B Backspace Result := True
-- / Solidus else
-- " Quotation
do end
Result:=<<'%F','%H','%N','%R','%T','%B','/','"'>> end
end
is_special_character (c: CHARACTER): BOOLEAN is
special_controls:ARRAY[CHARACTER] is -- Control Characters
--Control Characters -- %F Form feed
-- \b\f\n\r\t -- %H backslasH
do -- %N Newline
Result:=<<'b','f','n','r','t'>> -- %R carriage Return
end -- %T horizontal Tab
end -- %B Backspace
-- / Solidus
-- " Quotation
do
inspect c
when '%F', '%H', '%N', '%R', '%T', '%B', '/', '"' then
Result := True
else
end
end
is_special_control (c: CHARACTER): BOOLEAN is
--Control Characters
-- \b\f\n\r\t
do
inspect c
when 'b', 'f', 'n', 'r', 't' then
Result := True
else
end
end
end

View File

@@ -1,61 +1,59 @@
indexing indexing
description: description:
"JSON Visitor" "JSON Visitor"
pattern: "Visitor" pattern: "Visitor"
author: "Javier Velilla" author: "Javier Velilla"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)" license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
date: "2008/08/24" date: "2008/08/24"
revision: "Revision 0.1" revision: "Revision 0.1"
deferred class deferred class
JSON_VISITOR JSON_VISITOR
feature -- Visitor Pattern feature -- Visitor Pattern
visit_json_array (a_json_array: JSON_ARRAY) is visit_json_array (a_json_array: JSON_ARRAY) is
-- Visit `a_json_array'. -- Visit `a_json_array'.
require require
a_json_array_not_void: a_json_array /= Void a_json_array_not_void: a_json_array /= Void
deferred deferred
end end
visit_json_boolean (a_json_boolean: JSON_BOOLEAN) is visit_json_boolean (a_json_boolean: JSON_BOOLEAN) is
-- Visit `a_json_boolean'. -- Visit `a_json_boolean'.
require require
a_json_boolean_not_void: a_json_boolean /= Void a_json_boolean_not_void: a_json_boolean /= Void
deferred deferred
end end
visit_json_null (a_json_null: JSON_NULL) is visit_json_null (a_json_null: JSON_NULL) is
-- Visit `a_json_null'. -- Visit `a_json_null'.
require require
a_json_null_not_void: a_json_null /= Void a_json_null_not_void: a_json_null /= Void
deferred deferred
end end
visit_json_number (a_json_number: JSON_NUMBER) is
visit_json_number (a_json_number: JSON_NUMBER) is -- Visit `a_json_number'.
-- Visit `a_json_number'. require
require a_json_number_not_void: a_json_number /= Void
a_json_number_not_void: a_json_number /= Void deferred
deferred end
end
visit_json_object (a_json_object: JSON_OBJECT) is
visit_json_object (a_json_object: JSON_OBJECT) is -- Visit `a_json_object'.
-- Visit `a_json_object'. require
require a_json_object_not_void: a_json_object /= Void
a_json_object_not_void: a_json_object /= Void deferred
deferred end
end
visit_json_string (a_json_string: JSON_STRING) is
visit_json_string (a_json_string: JSON_STRING) is -- Visit `a_json_string'.
-- Visit `a_json_string'. require
require a_json_string_not_void: a_json_string /= Void
a_json_string_not_void: a_json_string /= Void deferred
deferred end
end
end
end

View File

@@ -1,101 +1,102 @@
indexing indexing
description: "PRINT_JSON_VISITOR Generates the JSON-String for a JSON_VALUE" description: "PRINT_JSON_VISITOR Generates the JSON-String for a JSON_VALUE"
author: "jvelilla" author: "jvelilla"
date: "2008/08/24" date: "2008/08/24"
revision: "0.1" revision: "0.1"
class class
PRINT_JSON_VISITOR PRINT_JSON_VISITOR
inherit inherit
JSON_VISITOR JSON_VISITOR
create make create make
feature -- Initialization feature -- Initialization
make is
-- Create a new instance make is
do -- Create a new instance
create to_json.make_empty do
end create to_json.make_empty
end
feature -- Access
feature -- Access
to_json:STRING
-- JSON representation to_json: STRING
feature -- Visitor Pattern -- JSON representation
visit_json_array (a_json_array: JSON_ARRAY) is feature -- Visitor Pattern
-- Visit `a_json_array'.
local visit_json_array (a_json_array: JSON_ARRAY) is
value:JSON_VALUE -- Visit `a_json_array'.
l_json_array:ARRAYED_LIST[JSON_VALUE] local
do value: JSON_VALUE
l_json_array:=a_json_array.array_representation l_json_array: ARRAYED_LIST [JSON_VALUE]
to_json.append("[") do
from l_json_array:=a_json_array.array_representation
l_json_array.start to_json.append ("[")
until from
l_json_array.off l_json_array.start
loop until
value:=l_json_array.item l_json_array.off
value.accept (Current) loop
l_json_array.forth value := l_json_array.item
if not l_json_array.after then value.accept (Current)
to_json.append(",") l_json_array.forth
end if not l_json_array.after then
end to_json.append(",")
to_json.append("]") end
end end
to_json.append ("]")
visit_json_boolean (a_json_boolean: JSON_BOOLEAN) is end
-- Visit `a_json_boolean'.
do visit_json_boolean (a_json_boolean: JSON_BOOLEAN) is
to_json.append (a_json_boolean.item.out) -- Visit `a_json_boolean'.
end do
to_json.append (a_json_boolean.item.out)
visit_json_null (a_json_null: JSON_NULL) is end
-- Visit `a_json_null'.
do visit_json_null (a_json_null: JSON_NULL) is
to_json.append ("null") -- Visit `a_json_null'.
end do
to_json.append ("null")
end
visit_json_number (a_json_number: JSON_NUMBER) is
-- Visit `a_json_number'. visit_json_number (a_json_number: JSON_NUMBER) is
do -- Visit `a_json_number'.
to_json.append (a_json_number.item) do
end to_json.append (a_json_number.item)
end
visit_json_object (a_json_object: JSON_OBJECT) is
-- Visit `a_json_object'. visit_json_object (a_json_object: JSON_OBJECT) is
local -- Visit `a_json_object'.
l_pairs: HASH_TABLE[JSON_VALUE,JSON_STRING] local
do l_pairs: HASH_TABLE[JSON_VALUE,JSON_STRING]
l_pairs:=a_json_object.map_representation do
to_json.append ("{") l_pairs := a_json_object.map_representation
from to_json.append ("{")
l_pairs.start from
until l_pairs.start
l_pairs.off until
loop l_pairs.off
l_pairs.key_for_iteration.accept (Current) loop
to_json.append (":") l_pairs.key_for_iteration.accept (Current)
l_pairs.item_for_iteration.accept (Current) to_json.append (":")
l_pairs.forth l_pairs.item_for_iteration.accept (Current)
if not l_pairs.after then l_pairs.forth
to_json.append (",") if not l_pairs.after then
end to_json.append (",")
end end
to_json.append ("}") end
end to_json.append ("}")
end
visit_json_string (a_json_string: JSON_STRING) is
-- Visit `a_json_string'. visit_json_string (a_json_string: JSON_STRING) is
do -- Visit `a_json_string'.
to_json.append ("%"") do
to_json.append (a_json_string.item) to_json.append ("%"")
to_json.append ("%"") to_json.append (a_json_string.item)
end to_json.append ("%"")
end
end
end