prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  nginxparser does not recognize 'if' statements
  E.g., this is unparseable by nginxparser:
  
  ```
  if ($http_origin ~* ^https://www\.example\.com) {
     add_header      Access-Control-Allow-Origin "$http_origin";
  }
  ```
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `letsencrypt_nginx/nginxparser.py`
  Content:
  ```
  1 """Very low-level nginx config parser based on pyparsing."""
  2 import string
  3 
  4 from pyparsing import (
  5     Literal, White, Word, alphanums, CharsNotIn, Forward, Group,
  6     Optional, OneOrMore, ZeroOrMore, pythonStyleComment)
  7 
  8 
  9 class RawNginxParser(object):
  10     # pylint: disable=expression-not-assigned
  11     """A class that parses nginx configuration with pyparsing."""
  12 
  13     # constants
  14     left_bracket = Literal("{").suppress()
  15     right_bracket = Literal("}").suppress()
  16     semicolon = Literal(";").suppress()
  17     space = White().suppress()
  18     key = Word(alphanums + "_/")
  19     value = CharsNotIn("{};,")
  20     location = CharsNotIn("{};," + string.whitespace)
  21     # modifier for location uri [ = | ~ | ~* | ^~ ]
  22     modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~")
  23 
  24     # rules
  25     assignment = (key + Optional(space + value) + semicolon)
  26     block = Forward()
  27 
  28     block << Group(
  29         Group(key + Optional(space + modifier) + Optional(space + location))
  30         + left_bracket
  31         + Group(ZeroOrMore(Group(assignment) | block))
  32         + right_bracket)
  33 
  34     script = OneOrMore(Group(assignment) | block).ignore(pythonStyleComment)
  35 
  36     def __init__(self, source):
  37         self.source = source
  38 
  39     def parse(self):
  40         """Returns the parsed tree."""
  41         return self.script.parseString(self.source)
  42 
  43     def as_list(self):
  44         """Returns the parsed tree as a list."""
  45         return self.parse().asList()
  46 
  47 
  48 class RawNginxDumper(object):
  49     # pylint: disable=too-few-public-methods
  50     """A class that dumps nginx configuration from the provided tree."""
  51     def __init__(self, blocks, indentation=4):
  52         self.blocks = blocks
  53         self.indentation = indentation
  54 
  55     def __iter__(self, blocks=None, current_indent=0, spacer=' '):
  56         """Iterates the dumped nginx content."""
  57         blocks = blocks or self.blocks
  58         for key, values in blocks:
  59             if current_indent:
  60                 yield spacer
  61             indentation = spacer * current_indent
  62             if isinstance(key, list):
  63                 yield indentation + spacer.join(key) + ' {'
  64                 for parameter in values:
  65                     if isinstance(parameter[0], list):
  66                         dumped = self.__iter__(
  67                             [parameter],
  68                             current_indent + self.indentation)
  69                         for line in dumped:
  70                             yield line
  71                     else:
  72                         dumped = spacer.join(parameter) + ';'
  73                         yield spacer * (
  74                             current_indent + self.indentation) + dumped
  75 
  76                 yield indentation + '}'
  77             else:
  78                 yield spacer * current_indent + key + spacer + values + ';'
  79 
  80     def as_string(self):
  81         """Return the parsed block as a string."""
  82         return '\n'.join(self)
  83 
  84 
  85 # Shortcut functions to respect Python's serialization interface
  86 # (like pyyaml, picker or json)
  87 
  88 def loads(source):
  89     """Parses from a string.
  90 
  91     :param str souce: The string to parse
  92     :returns: The parsed tree
  93     :rtype: list
  94 
  95     """
  96     return RawNginxParser(source).as_list()
  97 
  98 
  99 def load(_file):
  100     """Parses from a file.
  101 
  102     :param file _file: The file to parse
  103     :returns: The parsed tree
  104     :rtype: list
  105 
  106     """
  107     return loads(_file.read())
  108 
  109 
  110 def dumps(blocks, indentation=4):
  111     """Dump to a string.
  112 
  113     :param list block: The parsed tree
  114     :param int indentation: The number of spaces to indent
  115     :rtype: str
  116 
  117     """
  118     return RawNginxDumper(blocks, indentation).as_string()
  119 
  120 
  121 def dump(blocks, _file, indentation=4):
  122     """Dump to a file.
  123 
  124     :param list block: The parsed tree
  125     :param file _file: The file to dump to
  126     :param int indentation: The number of spaces to indent
  127     :rtype: NoneType
  128 
  129     """
  130     return _file.write(dumps(blocks, indentation))
  131
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/letsencrypt_nginx/nginxparser.py b/letsencrypt_nginx/nginxparser.py
  --- a/letsencrypt_nginx/nginxparser.py
  +++ b/letsencrypt_nginx/nginxparser.py
  @@ -3,7 +3,7 @@
   
   from pyparsing import (
       Literal, White, Word, alphanums, CharsNotIn, Forward, Group,
  -    Optional, OneOrMore, ZeroOrMore, pythonStyleComment)
  +    Optional, OneOrMore, Regex, ZeroOrMore, pythonStyleComment)
   
   
   class RawNginxParser(object):
  @@ -16,17 +16,21 @@
       semicolon = Literal(";").suppress()
       space = White().suppress()
       key = Word(alphanums + "_/")
  -    value = CharsNotIn("{};,")
  +    # Matches anything that is not a special character AND any chars in single
  +    # or double quotes
  +    value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+")
       location = CharsNotIn("{};," + string.whitespace)
       # modifier for location uri [ = | ~ | ~* | ^~ ]
       modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~")
   
       # rules
       assignment = (key + Optional(space + value) + semicolon)
  +    location_statement = Optional(space + modifier) + Optional(space + location)
  +    if_statement = Literal("if") + space + Regex(r"\(.+\)") + space
       block = Forward()
   
       block << Group(
  -        Group(key + Optional(space + modifier) + Optional(space + location))
  +        (Group(key + location_statement) ^ Group(if_statement))
           + left_bracket
           + Group(ZeroOrMore(Group(assignment) | block))
           + right_bracket)
  
verification_info: {"golden_diff": "diff --git a/letsencrypt_nginx/nginxparser.py b/letsencrypt_nginx/nginxparser.py\n--- a/letsencrypt_nginx/nginxparser.py\n+++ b/letsencrypt_nginx/nginxparser.py\n@@ -3,7 +3,7 @@\n \n from pyparsing import (\n     Literal, White, Word, alphanums, CharsNotIn, Forward, Group,\n-    Optional, OneOrMore, ZeroOrMore, pythonStyleComment)\n+    Optional, OneOrMore, Regex, ZeroOrMore, pythonStyleComment)\n \n \n class RawNginxParser(object):\n@@ -16,17 +16,21 @@\n     semicolon = Literal(\";\").suppress()\n     space = White().suppress()\n     key = Word(alphanums + \"_/\")\n-    value = CharsNotIn(\"{};,\")\n+    # Matches anything that is not a special character AND any chars in single\n+    # or double quotes\n+    value = Regex(r\"((\\\".*\\\")?(\\'.*\\')?[^\\{\\};,]?)+\")\n     location = CharsNotIn(\"{};,\" + string.whitespace)\n     # modifier for location uri [ = | ~ | ~* | ^~ ]\n     modifier = Literal(\"=\") | Literal(\"~*\") | Literal(\"~\") | Literal(\"^~\")\n \n     # rules\n     assignment = (key + Optional(space + value) + semicolon)\n+    location_statement = Optional(space + modifier) + Optional(space + location)\n+    if_statement = Literal(\"if\") + space + Regex(r\"\\(.+\\)\") + space\n     block = Forward()\n \n     block << Group(\n-        Group(key + Optional(space + modifier) + Optional(space + location))\n+        (Group(key + location_statement) ^ Group(if_statement))\n         + left_bracket\n         + Group(ZeroOrMore(Group(assignment) | block))\n         + right_bracket)\n", "issue": "nginxparser does not recognize 'if' statements\nE.g., this is unparseable by nginxparser:\n\n```\nif ($http_origin ~* ^https://www\\.example\\.com) {\n   add_header      Access-Control-Allow-Origin \"$http_origin\";\n}\n```\n\n", "before_files": [{"content": "\"\"\"Very low-level nginx config parser based on pyparsing.\"\"\"\nimport string\n\nfrom pyparsing import (\n    Literal, White, Word, alphanums, CharsNotIn, Forward, Group,\n    Optional, OneOrMore, ZeroOrMore, pythonStyleComment)\n\n\nclass RawNginxParser(object):\n    # pylint: disable=expression-not-assigned\n    \"\"\"A class that parses nginx configuration with pyparsing.\"\"\"\n\n    # constants\n    left_bracket = Literal(\"{\").suppress()\n    right_bracket = Literal(\"}\").suppress()\n    semicolon = Literal(\";\").suppress()\n    space = White().suppress()\n    key = Word(alphanums + \"_/\")\n    value = CharsNotIn(\"{};,\")\n    location = CharsNotIn(\"{};,\" + string.whitespace)\n    # modifier for location uri [ = | ~ | ~* | ^~ ]\n    modifier = Literal(\"=\") | Literal(\"~*\") | Literal(\"~\") | Literal(\"^~\")\n\n    # rules\n    assignment = (key + Optional(space + value) + semicolon)\n    block = Forward()\n\n    block << Group(\n        Group(key + Optional(space + modifier) + Optional(space + location))\n        + left_bracket\n        + Group(ZeroOrMore(Group(assignment) | block))\n        + right_bracket)\n\n    script = OneOrMore(Group(assignment) | block).ignore(pythonStyleComment)\n\n    def __init__(self, source):\n        self.source = source\n\n    def parse(self):\n        \"\"\"Returns the parsed tree.\"\"\"\n        return self.script.parseString(self.source)\n\n    def as_list(self):\n        \"\"\"Returns the parsed tree as a list.\"\"\"\n        return self.parse().asList()\n\n\nclass RawNginxDumper(object):\n    # pylint: disable=too-few-public-methods\n    \"\"\"A class that dumps nginx configuration from the provided tree.\"\"\"\n    def __init__(self, blocks, indentation=4):\n        self.blocks = blocks\n        self.indentation = indentation\n\n    def __iter__(self, blocks=None, current_indent=0, spacer=' '):\n        \"\"\"Iterates the dumped nginx content.\"\"\"\n        blocks = blocks or self.blocks\n        for key, values in blocks:\n            if current_indent:\n                yield spacer\n            indentation = spacer * current_indent\n            if isinstance(key, list):\n                yield indentation + spacer.join(key) + ' {'\n                for parameter in values:\n                    if isinstance(parameter[0], list):\n                        dumped = self.__iter__(\n                            [parameter],\n                            current_indent + self.indentation)\n                        for line in dumped:\n                            yield line\n                    else:\n                        dumped = spacer.join(parameter) + ';'\n                        yield spacer * (\n                            current_indent + self.indentation) + dumped\n\n                yield indentation + '}'\n            else:\n                yield spacer * current_indent + key + spacer + values + ';'\n\n    def as_string(self):\n        \"\"\"Return the parsed block as a string.\"\"\"\n        return '\\n'.join(self)\n\n\n# Shortcut functions to respect Python's serialization interface\n# (like pyyaml, picker or json)\n\ndef loads(source):\n    \"\"\"Parses from a string.\n\n    :param str souce: The string to parse\n    :returns: The parsed tree\n    :rtype: list\n\n    \"\"\"\n    return RawNginxParser(source).as_list()\n\n\ndef load(_file):\n    \"\"\"Parses from a file.\n\n    :param file _file: The file to parse\n    :returns: The parsed tree\n    :rtype: list\n\n    \"\"\"\n    return loads(_file.read())\n\n\ndef dumps(blocks, indentation=4):\n    \"\"\"Dump to a string.\n\n    :param list block: The parsed tree\n    :param int indentation: The number of spaces to indent\n    :rtype: str\n\n    \"\"\"\n    return RawNginxDumper(blocks, indentation).as_string()\n\n\ndef dump(blocks, _file, indentation=4):\n    \"\"\"Dump to a file.\n\n    :param list block: The parsed tree\n    :param file _file: The file to dump to\n    :param int indentation: The number of spaces to indent\n    :rtype: NoneType\n\n    \"\"\"\n    return _file.write(dumps(blocks, indentation))\n", "path": "letsencrypt_nginx/nginxparser.py"}], "after_files": [{"content": "\"\"\"Very low-level nginx config parser based on pyparsing.\"\"\"\nimport string\n\nfrom pyparsing import (\n    Literal, White, Word, alphanums, CharsNotIn, Forward, Group,\n    Optional, OneOrMore, Regex, ZeroOrMore, pythonStyleComment)\n\n\nclass RawNginxParser(object):\n    # pylint: disable=expression-not-assigned\n    \"\"\"A class that parses nginx configuration with pyparsing.\"\"\"\n\n    # constants\n    left_bracket = Literal(\"{\").suppress()\n    right_bracket = Literal(\"}\").suppress()\n    semicolon = Literal(\";\").suppress()\n    space = White().suppress()\n    key = Word(alphanums + \"_/\")\n    # Matches anything that is not a special character AND any chars in single\n    # or double quotes\n    value = Regex(r\"((\\\".*\\\")?(\\'.*\\')?[^\\{\\};,]?)+\")\n    location = CharsNotIn(\"{};,\" + string.whitespace)\n    # modifier for location uri [ = | ~ | ~* | ^~ ]\n    modifier = Literal(\"=\") | Literal(\"~*\") | Literal(\"~\") | Literal(\"^~\")\n\n    # rules\n    assignment = (key + Optional(space + value) + semicolon)\n    location_statement = Optional(space + modifier) + Optional(space + location)\n    if_statement = Literal(\"if\") + space + Regex(r\"\\(.+\\)\") + space\n    block = Forward()\n\n    block << Group(\n        (Group(key + location_statement) ^ Group(if_statement))\n        + left_bracket\n        + Group(ZeroOrMore(Group(assignment) | block))\n        + right_bracket)\n\n    script = OneOrMore(Group(assignment) | block).ignore(pythonStyleComment)\n\n    def __init__(self, source):\n        self.source = source\n\n    def parse(self):\n        \"\"\"Returns the parsed tree.\"\"\"\n        return self.script.parseString(self.source)\n\n    def as_list(self):\n        \"\"\"Returns the parsed tree as a list.\"\"\"\n        return self.parse().asList()\n\n\nclass RawNginxDumper(object):\n    # pylint: disable=too-few-public-methods\n    \"\"\"A class that dumps nginx configuration from the provided tree.\"\"\"\n    def __init__(self, blocks, indentation=4):\n        self.blocks = blocks\n        self.indentation = indentation\n\n    def __iter__(self, blocks=None, current_indent=0, spacer=' '):\n        \"\"\"Iterates the dumped nginx content.\"\"\"\n        blocks = blocks or self.blocks\n        for key, values in blocks:\n            if current_indent:\n                yield spacer\n            indentation = spacer * current_indent\n            if isinstance(key, list):\n                yield indentation + spacer.join(key) + ' {'\n                for parameter in values:\n                    if isinstance(parameter[0], list):\n                        dumped = self.__iter__(\n                            [parameter],\n                            current_indent + self.indentation)\n                        for line in dumped:\n                            yield line\n                    else:\n                        dumped = spacer.join(parameter) + ';'\n                        yield spacer * (\n                            current_indent + self.indentation) + dumped\n\n                yield indentation + '}'\n            else:\n                yield spacer * current_indent + key + spacer + values + ';'\n\n    def as_string(self):\n        \"\"\"Return the parsed block as a string.\"\"\"\n        return '\\n'.join(self)\n\n\n# Shortcut functions to respect Python's serialization interface\n# (like pyyaml, picker or json)\n\ndef loads(source):\n    \"\"\"Parses from a string.\n\n    :param str souce: The string to parse\n    :returns: The parsed tree\n    :rtype: list\n\n    \"\"\"\n    return RawNginxParser(source).as_list()\n\n\ndef load(_file):\n    \"\"\"Parses from a file.\n\n    :param file _file: The file to parse\n    :returns: The parsed tree\n    :rtype: list\n\n    \"\"\"\n    return loads(_file.read())\n\n\ndef dumps(blocks, indentation=4):\n    \"\"\"Dump to a string.\n\n    :param list block: The parsed tree\n    :param int indentation: The number of spaces to indent\n    :rtype: str\n\n    \"\"\"\n    return RawNginxDumper(blocks, indentation).as_string()\n\n\ndef dump(blocks, _file, indentation=4):\n    \"\"\"Dump to a file.\n\n    :param list block: The parsed tree\n    :param file _file: The file to dump to\n    :param int indentation: The number of spaces to indent\n    :rtype: NoneType\n\n    \"\"\"\n    return _file.write(dumps(blocks, indentation))\n", "path": "letsencrypt_nginx/nginxparser.py"}]}