changeset 26:25aab2c2a695 draft

Improve performance by removing function calls from the hot path.
author Lewin Bormann <lbo@spheniscida.de>
date Tue, 21 May 2019 01:26:22 +0200
parents 9831b7c577a3
children 6e9cf2fb5f49
files pcombinators/json_test.py
diffstat 1 files changed, 32 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/pcombinators/json_test.py	Tue May 21 01:18:21 2019 +0200
+++ b/pcombinators/json_test.py	Tue May 21 01:26:22 2019 +0200
@@ -9,37 +9,39 @@
 from combinators import *
 from primitives import *
 
-def JString():
-    return Last(Skip(String('"')) + NoneInSet('"') + Skip(String('"')))
+JString = Last(Skip(String('"')) + NoneInSet('"') + Skip(String('"')))
+
+wrapl = lambda l: [l]
+
+# We moved out all the piece parsers out of functions to reduce allocation overhead.
+# It improves performance by roughly 2x.
+
+# LISTS
 
-def List():
-    wrapl = lambda l: [l]
-    # An entry is any value.
-    entry = Value()
-    # A mid entry is a value followed by a comma.
-    midentry = entry + Skip(String(','))
-    # A list is a [, followed by mid entries, followed by a final entry, and a
-    # closing ]. The list is wrapped in a list to prevent merging in other parsers.
-    return (
-            Skip(String('[')) +
-            Repeat(midentry, -1) +
-            entry +
-            Skip(String(']'))) >> wrapl # Wrap list inside another list to protect it from flattening.
+# An entry is any value.
+entry = Value()
+# A mid entry is a value followed by a comma.
+midentry = entry + Skip(String(','))
+# A list is a [, followed by mid entries, followed by a final entry, and a
+# closing ]. The list is wrapped in a list to prevent merging in other parsers.
+List = (Skip(String('[')) +
+        Repeat(midentry, -1) +
+        entry +
+        Skip(String(']'))) >> wrapl # Wrap list inside another list to protect it from flattening.
 
-def Dict():
-    wrapl = lambda l: [l]
-    # A separator is whitespace, a colon, and more whitespace (Whitespace() also accepts empty string)
-    separator = Skip((Whitespace() + String(":") + Whitespace()))
-    # Entry is a String followed by a separator and a value. Wrap the value in a list to prevent merging.
-    # The two-element list is converted to a tuple.
-    entry = (JString() + separator + (Value() >> wrapl)) >> (lambda l: tuple(l))
-    # A mid entry is followed by a comma.
-    midentry = entry + Skip(String(',') + Whitespace())
-    # A dict is a {, followed by entries, followed by a final entry, followed by a closing }
-    dct = Skip(String("{")) + Repeat(midentry, -1) + entry + Skip(String("}"))
-    # Convert the list of tuples into a dict.
-    fulldict = dct >> dict
-    return fulldict
+# DICTS
+
+# A separator is whitespace, a colon, and more whitespace (Whitespace() also accepts empty string)
+separator = Skip((Whitespace() + String(":") + Whitespace()))
+# Entry is a String followed by a separator and a value. Wrap the value in a list to prevent merging.
+# The two-element list is converted to a tuple.
+entry = (JString + separator + (Value() >> wrapl)) >> (lambda l: tuple(l))
+# A mid entry is followed by a comma.
+midentry = entry + Skip(String(',') + Whitespace())
+# A dict is a {, followed by entries, followed by a final entry, followed by a closing }
+dct = Skip(String("{")) + Repeat(midentry, -1) + entry + Skip(String("}"))
+# Convert the list of tuples into a dict.
+Dict = dct >> dict
 
 class Value(Parser):
     """Bare-bones, but fully functioning, JSON parser. Doesn't like escaped quotes.
@@ -54,4 +56,4 @@
          ParseState({"id":1,"name":"Foo","price":123,"tags":["Bar","Eek"],"stock":{"warehouse":300, "retail":20}}<>))
     """
     def parse(self, st):
-        return Last(Skip(Whitespace()) + (Dict() | List() | JString() | Float()) + Skip(Whitespace())).parse(st)
\ No newline at end of file
+        return Last(Skip(Whitespace()) + (Dict | List | JString | Float()) + Skip(Whitespace())).parse(st)
\ No newline at end of file