diff --git a/README.rst b/README.rst index 294d0ad..bd20570 100644 --- a/README.rst +++ b/README.rst @@ -306,17 +306,9 @@ A few things to notice: Multiple source files --------------------- -Most projects have more than one source file and you can parse them all in one -call. For example: - -.. code-block:: python - - parsed = fp.parse(["source.txt", "other_source.txt"], , (AssigmentBlock, Equality)) - -will produce a ``ParsedProject`` object with two elements. - -But in many cases, a file might refer to another that also need to be parsed -(e.g. an `#include` statement in c). **flexparser** provides the ``IncludeStatement`` +Most projects have more than one source file internally connected. +A file might refer to another that also need to be parsed (e.g. an +`#include` statement in c). **flexparser** provides the ``IncludeStatement`` base class specially for this purpose. .. code-block:: python @@ -404,6 +396,41 @@ Explicit Block classes parsed = fp.parse("source.txt", EntryBlock) + +Customizing parsing +------------------- + +In certain cases you might want to leave to the user some configuration +details. We have method for that!. Instead of overriding ``from_string`` +override ``from_string_and_config``. The second argument is an object +that can be given to the parser, which in turn will be passed to each +``ParsedStatement`` class. + +.. code-block:: python + + @dataclass(frozen=True) + class NumericAssigment(fp.ParsedStatement): + """Parses the following `this <- other` + """ + + lhs: str + rhs: numbers.Number + + @classmethod + def from_string_and_config(cls, s, config): + if "==" not in s: + # This means: I do not know how to parse it + # try with another ParsedStatement class. + return None + lhs, rhs = s.split("==") + return cls(lhs.strip(), config.numeric_type(rhs.strip())) + + class Config: + + numeric_type = float + + parsed = fp.parse("source.txt", NumericAssigment, Config) + ---- This project was started as a part of Pint_, the python units package. diff --git a/flexparser/__init__.py b/flexparser/__init__.py index 53c574c..4ea106b 100644 --- a/flexparser/__init__.py +++ b/flexparser/__init__.py @@ -2,9 +2,12 @@ flexparser ~~~~~~~~~ - Classes for persistent caching and invalidating cached objects, - which are built from a source object and a (potentially expensive) - conversion function. + Classes and functions to create parsers. + + The idea is quite simple. You write a class for every type of content + (called here ``ParsedStatement``) you need to parse. Each class should + have a ``from_string`` constructor. We used extensively the ``typing`` + module to make the output structure easy to use and less error prone. :copyright: 2022 by flexparser Authors, see AUTHORS for more details. :license: BSD, see LICENSE for more details. diff --git a/flexparser/flexparser.py b/flexparser/flexparser.py index 714aba1..c78cd95 100644 --- a/flexparser/flexparser.py +++ b/flexparser/flexparser.py @@ -2,12 +2,14 @@ flexparser.flexparser ~~~~~~~~~~~~~~~~~~~~~ - There are three type of + Classes and functions to create parsers. - - statements: single lines handled by the Definition.from_string method. - - line directives - - block directives: + The idea is quite simple. You write a class for every type of content + (called here ``ParsedStatement``) you need to parse. Each class should + have a ``from_string`` constructor. We used extensively the ``typing`` + module to make the output structure easy to use and less error prone. + For more information, take a look at https://github.com/hgrecco/flexparser :copyright: 2022 by flexparser Authors, see AUTHORS for more details. :license: BSD, see LICENSE for more details. @@ -1002,12 +1004,51 @@ def parse( spec: SpecT, config=None, *, - strip_spaces=True, + strip_spaces: bool = True, delimiters=None, - locator=default_locator, - prefer_resource_as_file=True, + locator: ty.Callable[[StrictLocationT, str], StrictLocationT] = default_locator, + prefer_resource_as_file: bool = True, ) -> ParsedProject: - """Parse sources into a ParsedProject.""" + """Parse sources into a ParsedProject dictionary. + + Parameters + ---------- + entry_point + file or resource, given as (package_name, resource_name). + spec + specification of the content to parse. Can be one of the following things: + - Parser class. + - Block or ParsedStatement derived class. + - Iterable of Block or ParsedStatement derived class. + - RootBlock derived class. + config + a configuration object that will be passed to `from_string_and_config` + classmethod. + strip_spaces : bool + if True, spaces will be stripped for each statement before calling + ``from_string_and_config``. + delimiters : dict + Sepecify how the source file is split into statements (See below). + locator : Callable + function that takes the current location and a target of an IncludeStatement + and returns a new location. + prefer_resource_as_file : bool + if True, resources will try to be located in the filesystem if + available. + + + Delimiters dictionary + --------------------- + The delimiters are specified with the keys of the delimiters dict. + The dict files can be used to further customize the iterator. Each + consist of a tuple of two elements: + 1. A value of the DelimiterMode to indicate what to do with the + delimiter string: skip it, attach keep it with previous or next string + 2. A boolean indicating if parsing should stop after fiSBT + encountering this delimiter. + + + """ if isinstance(spec, type) and issubclass(spec, Parser): CustomParser = spec