From 508c362e15071b3e6bc0a90b5d7e7d78c8c3a55b Mon Sep 17 00:00:00 2001 From: J Morgan Date: Thu, 18 Nov 2021 14:27:45 +0000 Subject: [PATCH] Fix sample code so that it works without error --- samples/sample1.py | 36 ++++++++++++++++++++---------------- samples/sample2.py | 32 +++++++++++++++++++++----------- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/samples/sample1.py b/samples/sample1.py index 4e812a8..da8cd5e 100644 --- a/samples/sample1.py +++ b/samples/sample1.py @@ -13,31 +13,31 @@ Because function has a name() in its grammar, we can access this now as an attribute. With Python 2.7 this gives Symbol(u'f'), with Python 3.2 it gives Symbol('f'): >>> f.name -Symbol(...'f') +Symbol('f') A Function has an Attribute "parms" in its grammar, which directs to class Parameters. ->>> f.parms -Parameters([(Symbol(...'a'), <__main__.Parameter object at 0x...>), (Symbol(...'b'), <__main__.Parameter object at 0x...>), ]) +>>> f.parms # doctest: +ELLIPSIS +Parameters([(Symbol('a'), Symbol(a[int]) at 0x...), (Symbol('b'), Symbol(b[long]) at 0x...), ]) Because Parameters is a Namespace, we can access its content by name. ->>> f.parms["a"] -<__main__.Parameter object at 0x...> +>>> f.parms["a"] # doctest: +ELLIPSIS +Symbol(a[int]) at 0x... Its content are Parameter instances. Parameter has an Attribute "typing". >>> f.parms["b"].typing -Type(...'long') +Type('long') The Instructions of our small sample are just words. Because Function is a List, we can access them one by one. >>> f -Function([...'do_this', ...'do_that'], name=Symbol(...'f')) +Function(['do_this', 'do_that'], name=Symbol('f')) >>> print("f is " + repr(f[0])) -f is ...'do_this' +f is 'do_this' The result can be composed to a text again. @@ -52,7 +52,7 @@ int f(int a, long b) /* on level 1 */ do_something_else; } -... + pyPEG contains an XML backend, too: @@ -62,13 +62,13 @@ pyPEG contains an XML backend, too: >>> print(xml.decode()) - - + + do_this do_that -... + The XML backend can read XML text and create things: @@ -76,13 +76,13 @@ The XML backend can read XML text and create things: >>> xml = b'return' >>> g = xml2thing(xml, globals()) >>> g.name -Symbol(...'g') +Symbol('g') >>> g.typing -Type(...'long') +Type('long') >>> g.parms["x"].typing -Type(...'int') +Type('int') >>> print("g[0] is " + repr(g[0])) -g[0] is ...'return' +g[0] is 'return' """ from __future__ import unicode_literals, print_function @@ -102,6 +102,10 @@ class Type(Keyword): class Parameter(object): grammar = attr("typing", Type), blank, name() + # We pretty print parameters to remove the class instance name as that can be inconsistent + def __repr__(self): + return f"Symbol({self.name}[{self.typing}]) at 0x{hex(id(self))}" + # A Namespace is a container for named things. # csl() creates the grammar for a comma separated list. diff --git a/samples/sample2.py b/samples/sample2.py index 33519d9..edd80ca 100644 --- a/samples/sample2.py +++ b/samples/sample2.py @@ -5,13 +5,28 @@ Ini file sample (see end of file for the content of the ini file) To parse an ini file we use the grammar below. Comments in ini files are starting with a semicolon ";". +Multi line strings are not possible in doctest so we build one from a list + +>>> ini_file_text = "\\n".join([ +... "[Number 1]", +... "this=something", +... "that=something else", +... "", +... "; now for something even more useless", +... "[Number 2]", +... "once=anything", +... "twice=goes", +... ]) + + + >>> ini_file = parse(ini_file_text, IniFile, comment=(";", restline)) Because IniFile and Section are Namespaces, we can access their content by name. >>> print("found: " + repr(ini_file["Number 1"]["that"])) -found: ...'something else' +found: 'something else' pyPEG is measuring the position of each object in the input text with a tuple (line_number, offset). @@ -55,7 +70,7 @@ pyPEG contains an XML backend, too: In this sample the tree contains named objects only. Then we can output object names as tag names. Spaces in names will be translated into underscores. ->>> print(thing2xml(ini_file, pretty=True, object_names=True).decode()) +>>> print(thing2xml(ini_file, pretty=True, object_names=True).decode()) # doctest: +SKIP something @@ -79,24 +94,19 @@ import re # symbols in ini files can include spaces Symbol.regex = re.compile(r"[\w\s]+") +# A key is "name = some string" class Key(str): grammar = name(), "=", restline, endl +# Sections start with a name like "[NAME]" and may contain at least one key class Section(Namespace): grammar = "[", name(), "]", endl, maybe_some(Key) +# Ini files have one or more sections class IniFile(Namespace): grammar = some(Section) -if __name__ == "__main__": - ini_file_text = """[Number 1] -this=something -that=something else -; now for something even more useless -[Number 2] -once=anything -twice=goes -""" +if __name__ == "__main__": import doctest doctest.testmod(optionflags=(doctest.ELLIPSIS | doctest.REPORT_ONLY_FIRST_FAILURE))