Etc / parsing / spjson.py

import simpleparse
from simpleparse.common import strings, numbers
from simpleparse.dispatchprocessor import *


# JSON grammar to pass to simpleparse
# adapted from:
# http://bitbucket.org/robla/jsonwidget-python/src/tip/jsonwidget/jsonorder.py
jsonbnf = r"""
file                := document
document            := ws, value, ws
>value<             := false / null / true / json_object / array / float / int / string_json
true                := "true"
false               := "false"
null                := "null"
string_json         := string_single_quote / string_double_quote
array               := "[", ws, ( value, (ws, ",", ws, value)* )?, ws, "]"
json_object         := "{", ws, ( member, ( ws, ",", ws, member )* )?, ws, "}"
member              := string_json, ws, ":", ws, value 
<ws>                := [ \t\n\r]*
"""


class JSONParser(object):
    """Supports loading Python objects from JSON strings."""
    def __init__(self): 
        self._parser = simpleparse.parser.Parser(jsonbnf, 'file')

    def loads(self, src):
        loader = JSONLoader()
        self._parser.parse(src, processor=loader)
        return loader.value

class JSONLoader(DispatchProcessor):
    """Processes a SimpleParse result tree into a Python object."""
    def document(self, parseinfo, src):
        tag, start, stop, subtree = parseinfo
        self.value = dispatch(self, subtree[0], src)

    def null(self, parseinfo, src):
        return None

    def true(self, parseinfo, src):
        return True
    
    def false(self, parseinfo, src):
        return False

    def json_object(self, parseinfo, src):
        tag, start, stop, subtree = parseinfo
        return dict(dispatchList(self, subtree, src))

    def member(self, parseinfo, src):
        tag, start, stop, (key, value) = parseinfo
        key = dispatch(self, key, src)
        value = dispatch(self, value, src)
        return (key, value)

    def string_json(self, parseinfo, src):
        return getString(parseinfo, src)[1:-1]

    def array(self, parseinfo, src):
        tag, start, stop, subtree = parseinfo
        return dispatchList(self, subtree, src)

    def int(self, parseinfo, src):
        return int(getString(parseinfo, src))

    def float(self, parseinfo, src):
        return float(getString(parseinfo, src))

if __name__ == '__main__':
    import timeit
    from codetalker.contrib.json import loads as ctloads

    parser = JSONParser()
    loads = parser.loads
    bigjson = open('large_doc.json').read()

    TRIALS = 25

    print "CodeTalker", timeit.timeit(
        'ctloads(bigjson)', 
        'from __main__ import ctloads, bigjson', 
        number=TRIALS,
    ) / TRIALS

    print "SimpleParse", timeit.timeit(
        'loads(bigjson)', 
        'from __main__ import loads, bigjson', 
        number=TRIALS,
    ) / TRIALS
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.