Permalink
Browse files

json parser and tests

  • Loading branch information...
aviks committed Sep 20, 2012
1 parent 8394156 commit e5a410b86f20a52316fdf64cf3688d0d8916f382
Showing with 869 additions and 0 deletions.
  1. +206 −0 extras/json.jl
  2. +50 −0 test/json.jl
  3. +613 −0 test/json_samples.jl
View
@@ -0,0 +1,206 @@
+#JSON Parser
+#Modified and Adapted from http://www.mathworks.com/matlabcentral/fileexchange/23393
+#Original BSD Licence, (c) 2011, François Glineur
+
+
+module Json
+
+import Base.*
+
+export parse_json
+
+
+function parse_json(strng::String)
+
+ pos = 1
+ len = length(strng)
+
+ function parse_object()
+ parse_char('{')
+ object = Dict{String, Any}()
+ if next_char() != '}'
+ while true
+ str = parse_string()
+ if isempty(str)
+ error("Name of value cannot be empty at position $pos: $(errpos())")
+ end
+ parse_char(':')
+ val = parse_value()
+ object[str] = val
+ if next_char() == '}'
+ break
+ end
+ parse_char(',')
+ end
+ end
+ parse_char('}')
+ return object
+ end
+
+ function parse_array()
+ parse_char('[')
+ object = Any[]
+ if next_char() != ']'
+ while true
+ val = parse_value()
+ push(object, val)
+ if next_char() == ']'
+ break
+ end
+ parse_char(',')
+ end
+ end
+ parse_char(']')
+ return object
+ end
+
+ function parse_char(c::Char)
+ skip_whitespace()
+ if pos > len || strng[pos] != c
+ error("Expected $c at position $pos: $(errpos())")
+ else
+ pos = nextind(strng, pos)
+ skip_whitespace()
+ end
+ end
+
+ function next_char()
+ skip_whitespace()
+ if pos > len
+ error("Unclosed braces at end of file")
+ else
+ c = strng[pos]
+ end
+ end
+
+ function skip_whitespace()
+ while pos <= len && isspace(strng[pos])
+ pos = nextind(strng, pos)
+ end
+ end
+
+ function parse_string()
+ if next_char() != '"'
+ error("String starting with \" expected at position $pos: $(errpos())")
+ else
+ pos = pos + 1
+ end
+ str = ""
+ while pos <= len
+ nc = strng[pos]
+ if nc == '"'
+ pos = nextind(strng, pos)
+ return string(str)
+ elseif nc == '\\'
+ if pos+1 > len
+ error("End of file reached right after escape character")
+ end
+ pos = nextind(strng, pos)
+ anc = strng[pos]
+ if anc == '"' || anc == '\\' || anc == '/'
+ str = strcat(str, strng[pos])
+ pos = nextind(strng, pos)
+ elseif anc == 'b' || anc == 'f'|| anc == 'n' || anc == 'r' || anc == 't'
+ str = strcat(str, unescape_string(strcat('\\', string[pos])))
+ pos = nextind(strng, pos)
+ elseif anc == 'u'
+ startpos = prevind(strng, pos)
+ endpos = movpos(4)
+ if endpos > len
+ error("End of file reached in escaped unicode character")
+ end
+
+ str = strcat(str, unescape_string(strng[startpos:endpos]))
+ pos = nextind(strng, endpos)
+ end
+ else #This can be optimised if we have a preselected list of string terminators
+ str = strcat(str,strng[pos])
+ pos = nextind(strng, pos)
+ end
+ end
+ error("End of file while expecting end of string")
+ end
+
+ function parse_number()
+ num_regex = r"^[\w]?[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?[\w]?"
+ m = match(num_regex, strng[pos:min(len,pos+40)])
+ if m==nothing
+ error("Error reading number at position $pos")
+ end
+ delta = m.offset + length(m.match)
+ pos = pos + delta -1
+ return float(m.match)
+ end
+
+ function parse_value()
+ nc = next_char()
+ if nc == '"'
+ val = parse_string()
+ return val
+ elseif nc == '['
+ val = parse_array()
+ return val
+ elseif nc == '{'
+ val = parse_object()
+ return val
+ elseif nc == '-' || nc == '0' || nc == '1' || nc == '2' || nc == '3' || nc == '4' || nc == '5' || nc == '6' || nc == '7' || nc == '8' || nc == '9'
+ val = parse_number()
+ return val
+ elseif nc == 't'
+ endpos = movpos(3)
+ if endpos <= len && strng[pos:endpos] == "true"
+ val = true
+ pos = nextind(strng, endpos)
+ return val
+ end
+ elseif nc == 'f'
+ endpos = movpos( 4)
+ if endpos <= len && strng[pos:endpos] == "false"
+ val = false
+ pos = nextind(strng, endpos)
+ return val
+ end
+ elseif nc == 'n'
+ endpos = movpos( 3)
+ if endpos <= len && strng[pos:endpos] == "null"
+ val = nothing
+ pos = nextind(strng, endpos)
+ return val
+ end
+ end
+ error("Value expected at position $pos: $(errpos())" )
+ end
+
+
+ function isspace(c::Char)
+ c==' ' || c=='\n' || c=='\t'
+ end
+
+ function errpos()
+ if pos+20<len
+ return "$(strng[pos:pos+20])..."
+ else
+ return "strng[pos:len]"
+ end
+ end
+
+ function movpos(x::Int)
+ endpos = pos
+ for i=1:x; endpos = nextind(strng, endpos); end
+ return endpos
+ end
+
+ if pos <= len
+ nc = next_char()
+ if nc == '{'
+ return parse_object()
+ elseif nc == '['
+ return parse_array()
+ else
+ error("Outer level structure must be an object or an array")
+ end
+ end
+
+end
+
+end
View
@@ -0,0 +1,50 @@
+load("json.jl")
+import Json.*;
+
+load("test/json_samples.jl")
+
+
+@assert parse_json(a) != nothing
+@assert parse_json(b) != nothing
+@assert parse_json(c) != nothing
+@assert parse_json(d) != nothing
+
+j=parse_json(e)
+@assert j!= nothing
+typeof(j) == Dict{String, Any}
+@assert length(j) == 1
+typeof(j["menu"]) == Dict{String, Any}
+@assert length(j["menu"]) == 2
+@assert j["menu"]["header"] == "SVG\tViewerα"
+@assert typeof(j["menu"]["items"]) == Array{Any,1}
+@assert length(j["menu"]["items"]) == 22
+@assert j["menu"]["items"][3] == nothing
+@assert j["menu"]["items"][2]["id"] == "OpenNew"
+@assert j["menu"]["items"][2]["label"] == "Open New"
+
+
+
+@assert parse_json(gmaps) != nothing
+@assert parse_json(colors1) != nothing
+@assert parse_json(colors2) != nothing
+@assert parse_json(colors3) != nothing
+@assert parse_json(twitter) != nothing
+@assert parse_json(facebook) != nothing
+
+k=parse_json(flickr)
+@assert k!= nothing
+@assert k["totalItems"] == 222
+@assert k["items"][1]["description"][12] == '\"'
+@assert parse_json(youtube) != nothing
+@assert parse_json(iphone) != nothing
+@assert parse_json(customer) != nothing
+@assert parse_json(product) != nothing
+@assert parse_json(interop) != nothing
+
+u=parse_json(unicode)
+@assert u!=nothing
+@assert u["অলিম্পিকস"]["রেকর্ড"][2]["Marathon"] == "জনি হেইস"
+
+#Uncomment while doing timing tests
+@time for i=1:100 ; parse_json(d) ; end
+
Oops, something went wrong.

0 comments on commit e5a410b

Please sign in to comment.