aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.gitlab-ci.yml10
-rw-r--r--INSTALL.md2
-rw-r--r--MANIFEST.in17
-rw-r--r--README.md37
-rwxr-xr-xcli.py26
-rw-r--r--docs/builtin.rst32
-rw-r--r--docs/extending.rst168
-rw-r--r--docs/grammar.rst127
-rw-r--r--docs/index.rst49
-rw-r--r--docs/json.rst128
-rw-r--r--docs/qface_concept.jpgbin0 -> 153970 bytes
-rw-r--r--docs/qface_concept.pngbin24584 -> 0 bytes
-rw-r--r--docs/usage.rst68
-rw-r--r--examples/interfaces/echo.qface2
-rw-r--r--interfaces/org.qface.meta.qface81
-rw-r--r--qface/__about__.py6
-rw-r--r--qface/builtin/qtcpp/__init__.py0
-rw-r--r--qface/builtin/qtcpp/log.yaml18
-rwxr-xr-xqface/builtin/qtcpp/qtcpp.py81
-rw-r--r--qface/builtin/qtcpp/templates/__init__.py0
-rw-r--r--qface/builtin/qtcpp/templates/abstractinterface.cpp77
-rw-r--r--qface/builtin/qtcpp/templates/abstractinterface.h53
-rw-r--r--qface/builtin/qtcpp/templates/docs.pri32
-rw-r--r--qface/builtin/qtcpp/templates/generated.pri33
-rw-r--r--qface/builtin/qtcpp/templates/interface.cpp50
-rw-r--r--qface/builtin/qtcpp/templates/interface.h24
-rw-r--r--qface/builtin/qtcpp/templates/module.cpp82
-rw-r--r--qface/builtin/qtcpp/templates/module.h41
-rw-r--r--qface/builtin/qtcpp/templates/plugin-online.qdocconf19
-rw-r--r--qface/builtin/qtcpp/templates/plugin-project.qdocconf27
-rw-r--r--qface/builtin/qtcpp/templates/plugin.cpp26
-rw-r--r--qface/builtin/qtcpp/templates/plugin.h18
-rw-r--r--qface/builtin/qtcpp/templates/plugin.pro47
-rw-r--r--qface/builtin/qtcpp/templates/plugin.qdocconf21
-rw-r--r--qface/builtin/qtcpp/templates/qmake.conf5
-rw-r--r--qface/builtin/qtcpp/templates/qmldir3
-rw-r--r--qface/builtin/qtcpp/templates/struct.cpp112
-rw-r--r--qface/builtin/qtcpp/templates/struct.h45
-rw-r--r--qface/builtin/qtcpp/templates/structmodel.cpp106
-rw-r--r--qface/builtin/qtcpp/templates/structmodel.h40
-rw-r--r--qface/builtin/qtcpp/templates/variantmodel.cpp102
-rw-r--r--qface/builtin/qtcpp/templates/variantmodel.h38
-rw-r--r--qface/builtin/qtqml/__init__.py0
-rw-r--r--qface/builtin/qtqml/log.yaml18
-rwxr-xr-xqface/builtin/qtqml/qtqml.py67
-rw-r--r--qface/builtin/qtqml/templates/AbstractInterface.qml27
-rw-r--r--qface/builtin/qtqml/templates/Interface.qml7
-rw-r--r--qface/builtin/qtqml/templates/Module.qml24
-rw-r--r--qface/builtin/qtqml/templates/__init__.py0
-rw-r--r--qface/builtin/qtqml/templates/module.js18
-rw-r--r--qface/builtin/qtqml/templates/private_qmldir4
-rw-r--r--qface/builtin/qtqml/templates/public_qmldir4
-rw-r--r--qface/contrib/__init__.py (renamed from qface/builtin/__init__.py)0
-rw-r--r--qface/contrib/logging.py28
-rw-r--r--qface/filters.py46
-rw-r--r--qface/generator.py255
-rw-r--r--qface/helper/doc.py12
-rw-r--r--qface/helper/qtcpp.py241
-rw-r--r--qface/helper/qtqml.py19
-rw-r--r--qface/idl/domain.py210
-rw-r--r--qface/idl/listener.py28
-rw-r--r--qface/idl/parser/T.g415
-rw-r--r--qface/idl/parser/T.tokens66
-rw-r--r--qface/idl/parser/TLexer.py273
-rw-r--r--qface/idl/parser/TLexer.tokens66
-rw-r--r--qface/idl/parser/TListener.py20
-rw-r--r--qface/idl/parser/TParser.py1000
-rw-r--r--qface/idl/parser/TVisitor.py12
-rw-r--r--qface/templates/qface/qtcpp.j2103
-rw-r--r--qface/watch.py18
-rw-r--r--requirements.txt5
-rw-r--r--setup.py24
-rw-r--r--tests/in/com.pelagicore.ivi.tuner.qface21
-rw-r--r--tests/in/org.example.echo.qface2
-rw-r--r--tests/in/org.example.failing.qface5
-rw-r--r--tests/test_comments.py6
-rw-r--r--tests/test_generator.py10
-rw-r--r--tests/test_json.py54
-rw-r--r--tests/test_parser.py63
-rw-r--r--tests/test_qtcpp_helper.py50
81 files changed, 2508 insertions, 2167 deletions
diff --git a/.gitignore b/.gitignore
index 07d32c1..ada7038 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@ build/*
dist/*
.coverage
+.vscode
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..154e14a
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,10 @@
+image: "python:3.5"
+
+stages:
+ - test
+
+test:
+ stage: test
+ script:
+ - pip install -r requirements.txt
+ - ./cli.py test_ci
diff --git a/INSTALL.md b/INSTALL.md
index 4863afc..5a48911 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -22,7 +22,7 @@ Installs qface as an "editable" package. Means updates on the local git repo are
To install the python dependencies use
cd qface
- pip3 install -r requirements
+ pip3 install -r requirements.txt
pip3 install -e .
For updating the grammar you also need antlr4 (see http://www.antlr.org).
diff --git a/MANIFEST.in b/MANIFEST.in
index 10543f7..064b9f8 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,5 +1,12 @@
-include LICENSE.GPLV3
-include qface/builtin/qtcpp/templates/*
-include qface/builtin/qtcpp/log.yaml
-include qface/builtin/qtqml/templates/*
-include qface/builtin/qtqml/log.yaml
+include LICENSE
+include README.md
+
+graft qface/templates
+
+global-exclude *.so
+global-exclude *.pyc
+global-exclude *~
+global-exclude \#*
+global-exclude .git*
+global-exclude .DS_Store
+
diff --git a/README.md b/README.md
index d0eb57e..201cc93 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,10 @@ QFace is written out of the learnings of using IDLs in other large projects. Oft
Please see the INSTALL and USAGE guides for more information.
+## Documentation
+
+Documentation is hosted at [readthedocs](http://qface.readthedocs.io/en/latest/).
+
## Install
To install the qface library you need to have python3 and pip installed.
@@ -22,6 +26,39 @@ To install the qface library you need to have python3 and pip installed.
pip3 install qface
```
+## Install Development Version
+
+### Prerequisites
+
+To install the development version you need to clone the repository and ensure you have checkout the develop branch.
+
+```sh
+git clone git@github.com:Pelagicore/qface.git
+cd qface
+git checkout develop
+```
+
+The installation requires the python package manager called (pip) using the python 3 version. You can try:
+
+```sh
+python3 --version
+pip3 --version
+```
+
+### Installation
+
+Use the editable option of pip to install an editable version.
+
+```sh
+cd qface
+pip3 install --editable .
+```
+
+This reads the `setup.py` document and installs the package as reference to this repository. So all changes will be immediatly reflected in the installation.
+
+To update the installation just simple pull from the git repository.
+
+
## Download
If you are looking for the examples and the builtin generators you need to download the code.
diff --git a/cli.py b/cli.py
index 09863a2..feab43a 100755
--- a/cli.py
+++ b/cli.py
@@ -14,13 +14,13 @@ import logging.config
from livereload import Server, shell
-here = os.path.dirname(__file__)
+here = Path(__file__).abspath().dirname()
-logging.config.dictConfig(yaml.load(open(os.path.join(here, 'log.yaml'))))
+logging.config.dictConfig(yaml.load((here / 'log.yaml').open()))
logger = logging.getLogger(__name__)
-os.environ['PYTHONPATH'] = os.getcwd()
+os.environ['PYTHONPATH'] = Path.getcwd()
def sh(cmd, all=False, **kwargs):
@@ -167,21 +167,31 @@ def uninstall():
@cli.command()
def upload():
- Path('build').rmtree_p()
- dist = Path('dist')
- dist.rmtree_p()
- dist.makedirs_p()
- sh('python3 setup.py bdist_wheel')
sh('twine upload dist/*')
Path('build').rmtree_p()
@cli.command()
+def pack():
+ Path('build').rmtree_p()
+ Path('dist').rmtree_p()
+ sh('python3 setup.py bdist_wheel')
+ sh('unzip -l dist/*.whl')
+
+
+@cli.command()
def docs_serve():
server = Server()
server.watch('docs/*.rst', shell('make html', cwd='docs'))
server.serve(root='docs/_build/html', open_url=True)
+@cli.command()
+def clean():
+ Path('build').rmtree_p()
+ Path('dist').rmtree_p()
+ Path('qface.egg-info').rmtree_p()
+
+
if __name__ == '__main__':
cli()
diff --git a/docs/builtin.rst b/docs/builtin.rst
index 94bb0b6..a24f424 100644
--- a/docs/builtin.rst
+++ b/docs/builtin.rst
@@ -1,9 +1,31 @@
-Builtin Generators
+Generator Examples
==================
+QFace does provide soem real world generators which are hosted as separated projects. Their purpose is merely to showcase how to write a code generator with QFace. They are working and complete examples of a general purpose generators.
-.. toctree::
- :maxdepth: 1
+`qface-qtcpp`_
- qtcpp
- qtqml
+ The QtCPP generator generates a Qt C++ plugin with a QML API ready to be used in your project.
+
+ Hosted at: https://github.com/Pelagicore/qface-qtcpp
+
+`qface-qtqml`_
+
+ The QtQml generator generates a QML only API which ready to be used.
+
+ Hosted at: https://github.com/Pelagicore/qface-qtqml
+
+`qface-qtro`_
+
+ The RO (RemoteObjects) generator generates a client and server project using the Qt5 QtRemoteObejcts library
+
+ Hosted at: https://github.com/Pelagicore/qface-qtro
+
+
+From the QML user interface perspective the QtCPP and QtQML generators bth provide the same API and are interchangeable.
+
+
+
+.. _qface-qtcpp: https://github.com/Pelagicore/qface-qtcpp
+.. _qface-qtqml: https://github.com/Pelagicore/qface-qtqml
+.. _qface-qtro: https://github.com/Pelagicore/qface-qtro \ No newline at end of file
diff --git a/docs/extending.rst b/docs/extending.rst
index 74aa761..5252ed0 100644
--- a/docs/extending.rst
+++ b/docs/extending.rst
@@ -1,10 +1,12 @@
-===============
-Extending QFace
-===============
+*********
+Extending
+*********
-QFace is easy to use and easy to extend. Your generator is just a small python script using the qface library.
+QFace is easy to use and easy to extend. Your generator is just a small python
+script using the qface library.
-The script iterates over the domain model and writes files using a template language.
+The script iterates over the domain model and writes files using a template
+language.
See template engine documentation:
@@ -20,15 +22,20 @@ See template engine documentation:
# parse the interface files
system = FileSystem.parse(input)
# setup the generator
- generator = Generator(searchpath='templates')
+ generator = Generator(search_path='templates')
# create a context object
ctx = {'output': output, 'system': system}
# apply the context on the template and write the output to file
generator.write('{{output}}/modules.csv', 'modules.csv', ctx)
-This script reads the input directory returns a system object from the domain model. This is used as the root object for the code generation inside the template.
+This script reads the input directory returns a system object from the domain
+model. This is used as the root object for the code generation inside the
+template. The context object is applied to the file path as also on the named
+template document. The output of the template is then written to the given file
+path.
-Below is a simple template which geenrates a CSV document of all interfaces, structs and enums.
+Below is a simple template which generates a CSV document of all interfaces,
+structs and enums.
.. code-block:: jinja
@@ -44,4 +51,147 @@ Below is a simple template which geenrates a CSV document of all interfaces, str
{% endfor -%}
{% endfor %}
-The template iterates over the domain objects and generates text which is written into a file. The file name is also adjustable using the same template language.
+The template code iterates over the domain objects and generates text using a
+mixture of output blocks ``{{}}`` and control blocks ``{%%}``.
+
+
+Rule Base Generation
+====================
+
+The `RuleGenerator` allows you to extract the documentation rules into an external yaml file. This makes the python script more compact.
+
+
+.. code-block:: python
+
+ from qface.generator import FileSystem, RuleGenerator
+ from path import Path
+
+ here = Path(__file__).dirname()
+
+ def generate(input, output):
+ # parse the interface files
+ system = FileSystem.parse(input)
+ # setup the generator
+ generator = RuleGenerator(search_path=here/'templates', destination=output)
+ generator.process_rules(here/'docs.yaml', system)
+
+The rules document is divided into several targets. Each target can have an own destination. A target is typical for example and `app`, `client` or `server`. Each target can have rules for the different symbols (system, module, interface, struct, enum). An each rule finally consists of a destination modifier, additional context and a documents collection.
+
+.. code-block:: python
+
+ <target>:
+ <symbol>:
+ context: {}
+ destination: ''
+ documents:
+ <target>:<source>
+
+* ``<target>`` is a name of the current target (e.g. client, server, plugin)
+* ``<symbol>`` must be either system, module, interface, struct or enum
+
+
+Here is an example (``docs.yaml``)
+
+.. code-block:: yaml
+
+ global:
+ destination: '{{dst}}'
+ system:
+ documents:
+ '{{project}}.pro': 'project.pro'
+ '.qmake.conf': 'qmake.conf'
+ 'CMakeLists.txt': 'CMakeLists.txt'
+ plugin:
+ destination: '{{dst}}/plugin'
+ module:
+ context: {'module_name': '{{module|identifier}}'}
+ documents:
+ '{{module_name}}.pro': 'plugin/plugin.pro'
+ 'CMakeLists.txt': 'plugin/CMakeLists.txt'
+ 'plugin.cpp': 'plugin/plugin.cpp'
+ 'plugin.h': 'plugin/plugin.h'
+ 'qmldir': 'plugin/qmldir'
+ interface:
+ documents:
+ '{{interface|lower}}.h': 'plugin/interface.h'
+ '{{interface|lower}}.cpp': 'plugin/interface.cpp'
+ struct:
+ documents:
+ '{{struct|lower}}.h': 'plugin/struct.h'
+ '{{struct|lower}}.cpp': 'plugin/struct.cpp'
+
+
+The rule generator adds the ``dst``, ``project`` as also the corresponding symbols to the context automatically. On each level you are able to change the destination or update the context.
+
+
+.. rubric:: Features
+
+The rules document allows to conditional write files based on a feature set. The feature set must be a set of tags indicating the features which will then be checked in the ``when`` section of a rule. The ``when`` tag needs to be a list of feature switched.
+
+The features are passed to the generator in your custom generator code. The existence of a feature tells the rules engine to check if a ``when`` section exists conditionally execute this rule.
+
+.. code-block:: yaml
+
+ plugin:
+ when: [plugin_enabled]
+ destination: '{{dst}}/plugin'
+ module:
+ ...
+
+Here the plugin rule will only be run when the feature set contains a 'plugin_enabled' string.
+
+.. rubric:: Preserving Documents
+
+Documents can be moved to the ``preserve`` tag to prevent them to be overwritten. The rules documents has an own marker for this called ``preserve``. This is the same dictionary of target/source documents which shall be be marked preserved by the generator.
+
+
+.. code-block:: yaml
+
+ plugin:
+ interface:
+ documents:
+ '{{interface|lower}}.h': 'plugin/interface.h'
+ preserve:
+ '{{interface|lower}}.cpp': 'plugin/interface.cpp'
+
+In the example above the preserve listed documents will not be overwritten during a second generator run and can be edited by the user.
+
+.. rubric:: Destination and Source
+
+The ``destination`` tag allows you to specify a prefix for the target destination of the document. It should always contain the ``{{dst}}`` variable to be placed inside the project folder.
+
+The ``source`` tag specifies a prefix for the templates resolving. If the template name starts with a ``/`` the prefix will be ignored.
+
+Destination and source tags are allowed on the target level as also on each system, module and other symbol levels. A tag on a parent symbol will be the default for the child symbols.
+
+.. rubric:: Implicit symbol hierarchy
+
+This is the implicit logical hierarchy taken into account:
+
+.. code-block:: xml
+
+ <target>
+ <system>
+ <module>
+ <interface>
+ <struct>
+ <enum>
+
+Typical you place the destination prefix on the module level if your destination depends on the module symbol. For generic templates you would place the destination on the system level. On the system level you can not use child symbols (such as the module) as at this time these symbols are not known yet.
+
+Parsing Documentation Comments
+==============================
+
+The comments are provided as raw text to the template engine. You need to parse using the `parse_doc` tag and the you can inspect the documentation object.
+
+See below for a simple example
+
+.. code-block:: html
+
+ {% with doc = property.comment|parse_doc %}
+ \brief {{doc.brief}}
+
+ {{doc.description}}
+ {% endwith %}
+
+Each tag in the JavaDoc styled comment, will be converted into a property of the object returned by `parse_doc`. All lines without a tag will be merged into the description tag.
diff --git a/docs/grammar.rst b/docs/grammar.rst
index e76912d..a8048ea 100644
--- a/docs/grammar.rst
+++ b/docs/grammar.rst
@@ -2,7 +2,7 @@
Grammar
=======
-QFace (Qt interface language) is an Interface Description Languge (IDL). While it is primarily designed to define an interface between Qt, QML and C++, it is intended to be flexible enough also to be used in other contexts.
+QFace (Qt interface language) is an Interface Description Language (IDL). While it is primarily designed to define an interface between Qt, QML and C++, it is intended to be flexible enough also to be used in other contexts.
The grammar of QFace is well defined and is based on the concepts of modules as larger collection of information.
@@ -60,20 +60,104 @@ An interface is a collection of properties, operation and signals. Properties ca
signal error(string message);
}
+QFace allows to extends interfaces using the ``extends`` keyword after the interface name.
+
+.. code-block:: js
+
+ interface Station {
+ void reset();
+ signal error(string message);
+ }
+
+ interface WeatherStation extends Station {
+ real temperature;
+ }
+
+.. note::
+
+ For the sake of simplicity as an API designer you should carefully evaluate if this is required. The typical way in QFace to allow extension is normally to write your own code-generator and use type annotations.
+
+
+ .. code-block:: js
+
+ @station
+ interface WeatherStation {
+ real temperature;
+ }
+
+ The API reader does not need to know the internals of the API. The station behavior would be automatically attached by the custom generator.
+
+
+
Struct
======
+The struct resembles a data container. It consist of a set of fields where each field has a data type and a name.
+
+.. code-block:: js
+
+ struct Error {
+ string message;
+ int code;
+ };
+
+Structs can also be nested. A struct can be used everywhere where a type can be used.
+
+.. code-block:: js
+
+ interface WeatherStation {
+ real temperature;
+ Error lastError;
+ void reset();
+ signal error(Error error);
+ }
+
+
+
Enum/Flag
=========
-Types
------
+An enum and flag is an enumeration type. The value of each member is automatically assigned if missing.
-Types are either local and can be references simply by its name, or they are from external module in this case they need to be referenced with the fully qualified name (``module + '.' + name``). A type can be an interface, struct, enum or flag.
+.. code-block:: js
-A module consist of either one or more interfaces, structs and enums/flags. They can come in any number or combination. The interface is the only type which can contain operations and signals. The struct is merely a container to transport structured data. An enum/flag allows the user to encode information used inside the struct or interface as datatype.
+ enum State {
+ Null,
+ Loading,
+ Ready,
+ Error
+ }
+
+The value assignment for the enum type is sequential beginning from 0. To specify the exact value you can assign a value to the member.
+
+.. code-block:: js
+
+ enum State {
+ Null = 0,
+ Loading = 1,
+ Ready = 2,
+ Error = 3
+ }
+
+The flag type defines an enumeration type where these different values are treated as a bit mask. The values are in the sequence of the 2^n.
+
+.. code-block:: js
+
+ flag Cell {
+ Null,
+ Box,
+ Wall,
+ Figure
+ }
+
+
+
+Types
+=====
-The QFace does not allow to extend interfaces. It is by design kept simple.
+Types are either local and can be references simply by its name, or they are from external module in this case they need to be referenced with the fully qualified name (``<module>.<symbol>``). A type can be an interface, struct, enum or flag. It is also possible to reference the inner members of the symbols with the fragment syntax (``<module>.<symbol>#<fragment>``).
+
+A module consist of either one or more interfaces, structs and enums/flags. They can come in any number or combination. The interface is the only type which can contain properties, operations and signals. The struct is merely a container to transport structured data. An enum/flag allows the user to encode information used inside the struct or interface as data-type.
Below is an example of a QFace file.
@@ -135,3 +219,34 @@ Below is an example of a QFace file.
common.TimeStamp modified;
}
+
+Annotations
+===========
+
+Annotation allow the writer to add meta data to an interface document. It uses the `@` notation followed by valid YAML one line content.
+
+.. code-block:: js
+
+ @singleton: true
+ @config: { port: 1234 }
+ interface Echo {
+ }
+
+More information on annotations can be found in the annotations chapter.
+
+Comments
+========
+
+Comments use the JavaDoc convention of using an `@` sign as prefix with the keyword followed by the required parameters.
+
+.. code-block::java
+
+ /**
+ * @brief The last echo message
+ */
+
+Currently only brief, description, see and deprecated are supported doc tags.
+
+The QtCPP built-in generator generates valid Qt documentation out of these comments.
+
+
diff --git a/docs/index.rst b/docs/index.rst
index c83de6d..ed5f38a 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -2,7 +2,9 @@
QFace
=====
-QFace is a flexible Qt API generator. It uses a common IDL format (called QFace interface document) to define an API. QFace comes with a set of predefined generators to generate QML Plugins. QFace can be easily extended with your own generator.
+QFace is a flexible API generator inspired by the Qt API idioms. It uses a common IDL format (called QFace interface document) to define an API. QFace is optimized to write a custom generator based on the common IDL format.
+
+There exists already several code generators for common use cases. These can be used as is or can be used as a base for a custom generator.
.. toctree::
:maxdepth: 1
@@ -13,14 +15,39 @@ QFace is a flexible Qt API generator. It uses a common IDL format (called QFace
grammar
annotations
yaml
+ json
domain
extending
api
+
+Features
+========
+
+The list fo features is plit between features which are based on the choosen IDL and features wich are provided by the generator itself.
+
+.. rubric:: IDL Features
+
+- Common modern IDL
+- Scalable through modules
+- Structure through structs, enums, flags
+- Interface API with properties, operations and signals
+- Annotations using YAML syntax
+- Documentable IDL
+
+.. rubric:: Generator Features
+
+- Easy to install using python package manager
+- Designed to be extended
+- Well defined domain objects
+- Template based code generator
+- Simple rule based code builder
+- Well documented
+
Quick Start
===========
-QFace is a generator framework but also comes with several reference code generator.
+QFace is a generator framework and is bundled with several reference code generator.
To install qface you need to have python3 installed and typically also pip3
@@ -28,7 +55,7 @@ To install qface you need to have python3 installed and typically also pip3
pip3 install qface
-This installs the python qface library and the two reference generator qface-qtcpp and qface-qtqml.
+This installs the python qface library onto your system.
You can verify that you have qface installed with
@@ -97,22 +124,10 @@ And a "org.example.txt" file named after the module should be generated.
* :doc:`domain`
* :doc:`api`
-Builtin Generators
+Bundled Generators
------------------
-The built-in generators qface-qtcpp and qface-qtqml will generator cpp / qml code from the interface files. The generated code is source code compatible and can be used with the same QML based user interface
-
-.. code-block:: bash
-
- mkdir cpp-out
- qface-qtcpp sample.qface cpp-out
-
- mkdir qml-out
- qface-qtqml sample.qface qml-out
-
-The generators can run with one or more input files or folders and generate code for one or more modules. In case of the qtcpp generator the code needs to be open with QtCreator and compiled and installed.
-
-For the QML code the code must just made available to the QML import path.
+QFace has some gnerators which are bundled with the QFace library. They live in their own reposiutories. These generators are documented in the repositories.
.. rubric:: See Also
diff --git a/docs/json.rst b/docs/json.rst
new file mode 100644
index 0000000..ca7d9e5
--- /dev/null
+++ b/docs/json.rst
@@ -0,0 +1,128 @@
+****************
+JSON Meta Export
+****************
+
+QFace allows you to easily export the domain model as a JSON document. This enables you to parse the domain information to be
+used with other tooling.
+
+Inside your generator you need to register the filter first
+
+.. code-block:: python
+
+ from qface.filters import jsonify
+
+
+ generator = Generator(search_path=search_path)
+ generator.register_filter('jsonify', jsonify)
+
+Then inside the template you can transform any symbol into a JSON string using the ``jsonify`` filter.
+
+.. code-block:: jinja
+
+ {{module|jsonify}}
+
+Depending on your need you might want to create a JSON document from the whole system or from each interface or you are just
+interested on a JSON representation of an enumeration. The portion of the domain model exported to JSON really depends on your custom code generator and on which doamin element you apply the ``jsonify`` filter.
+
+JSON Format
+===========
+
+Taking the example QFace document
+
+.. code-block:: thrift
+
+ module org.example 1.0;
+
+ interface Echo {
+ readonly string currentMessage;
+ void echo(Message message);
+ }
+
+ struct Message {
+ string text;
+ }
+
+ enum Status {
+ Null,
+ Loading,
+ Ready,
+ Error
+ }
+
+
+The following JSON output is generated
+
+.. code-block:: json
+
+ {
+ "name": "org.example",
+ "version": "1.0",
+ "interfaces": [
+ {
+ "name": "Echo",
+ "properties": [
+ {
+ "name": "currentMessage",
+ "type": {
+ "name": "string",
+ "primitive": true
+ },
+ "readonly": true
+ }
+ ],
+ "operations": [
+ {
+ "name": "echo",
+ "parameters": [
+ {
+ "name": "message",
+ "type": {
+ "name": "Message",
+ "complex": true
+ }
+ }
+ ]
+ }
+ ],
+ "signals": []
+ }
+ ],
+ "structs": [
+ {
+ "name": "Message",
+ "fields": [
+ {
+ "name": "text",
+ "type": {
+ "name": "string",
+ "primitive": true
+ }
+ }
+ ]
+ }
+ ],
+ "enums": [
+ {
+ "name": "Status",
+ "enum": true,
+ "members": [
+ {
+ "name": "Null",
+ "value": 0
+ },
+ {
+ "name": "Loading",
+ "value": 1
+ },
+ {
+ "name": "Ready",
+ "value": 2
+ },
+ {
+ "name": "Error",
+ "value": 3
+ }
+ ]
+ }
+ ]
+ }
diff --git a/docs/qface_concept.jpg b/docs/qface_concept.jpg
new file mode 100644
index 0000000..0fde3a2
--- /dev/null
+++ b/docs/qface_concept.jpg
Binary files differ
diff --git a/docs/qface_concept.png b/docs/qface_concept.png
deleted file mode 100644
index eb31dbd..0000000
--- a/docs/qface_concept.png
+++ /dev/null
Binary files differ
diff --git a/docs/usage.rst b/docs/usage.rst
index af0e06b..7105bfa 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -7,64 +7,32 @@ Concept
QFace requires one or more IDL files as input file and a generator to produce output files. The IDL files are named QFace interface documents.
-.. image:: qface_concept.png
+.. figure:: qface_concept.jpg
-There are several ways to call the generator.
-
-
-Invocation
-==========
-
-Direct Invocation
------------------
-
-You can call the generator directly by using the provided script. All generators should at minimum expect a series of inputs and one output path. This is normally recommended for production.
-
-.. code-block:: sh
-
- ./csv.py src dst
-
-Via qface invokation
---------------------
-
-You can invoke your generator using the qface helper script. This allows you also to use some specific developer support. It is recommended way during generator development.
-
-To use an existing generator just provide the path to the generator script.
-
-.. code-block:: sh
-
- qface generate --generator ./csvgen.py input output
-
-
-To use live reloading on changes just use the reload option:
-
-
-.. code-block:: sh
-
- qface generate --generator ./csvgen.py input output --reload
-
-This will observe the generator folder and the input folder for changes and re-run the generator.
-
-Configuration Invokation
-------------------------
-
-You can also create a YAML configuration file (for example csv.yaml):
+To use qface you need to write your own generator. A generatopr is a small python script which reads the qface document and write code using a generator.
+.. code-block:: python
-.. code-block:: yaml
+ # gen.py
+ from qface.generator import FileSystem, Generator
- generator: ./csvgen.py
- input: input
- output: output
- reload: false
+ def generate(input, output):
+ # parse the interface files
+ system = FileSystem.parse(input)
+ # setup the generator
+ generator = Generator(search_path='templates')
+ # create a context object
+ ctx = {'output': output, 'system': system}
+ # apply the context on the template and write the output to file
+ generator.write('{{output}}/modules.csv', 'modules.csv', ctx)
+ # call the generation function
+ generate('sample.qface', 'out')
-And then call the client with:
.. code-block:: sh
- qface generate --config csv.yaml
-
+ python3 gen.py
Code Generation Principle
@@ -99,4 +67,4 @@ This script reads the input directory returns a system object form the domain mo
{% endfor -%}
{% endfor %}
-The template iterates over the domain objects and generates text which is written into a file. Using the generator write method ``generator.write(path, template, context)`` the output file path can also be specified using the template syntax .
+The template iterates over the domain objects and generates text which is written into a file. Using the generator write method ``generator.write(path, template, context)`` the output file path can also be specified using the template syntax .
diff --git a/examples/interfaces/echo.qface b/examples/interfaces/echo.qface
index 894b77c..95ed42f 100644
--- a/examples/interfaces/echo.qface
+++ b/examples/interfaces/echo.qface
@@ -7,7 +7,7 @@ interface Echo {
/**
* @brief The last echo message.
*/
- string currentMessage;
+ readonly string currentMessage;
/**
* @brief Returns the passed in message
*/
diff --git a/interfaces/org.qface.meta.qface b/interfaces/org.qface.meta.qface
new file mode 100644
index 0000000..ae496fb
--- /dev/null
+++ b/interfaces/org.qface.meta.qface
@@ -0,0 +1,81 @@
+ module org.qface.meta 1.0
+
+interface MetaBuilder {
+ ESystem system;
+ void load(string path);
+ void store(string path);
+}
+
+struct EType {
+ bool isComplex
+ bool isPrimitive;
+ bool isString;
+ bool isBool;
+ bool isInt;
+ bool isReal;
+ bool isList;
+ bool isModel;
+ string name;
+}
+
+struct ESystem {
+ list<EModule> modules;
+}
+
+struct EModule {
+ list<EInterface> interfaces;
+ list<EStruct> structs;
+ list<EEnum> enums;
+ list<EFlag> flags;
+}
+
+struct EInterface {
+ string name;
+ list<EProperty> properties;
+ list<EOperation> operations;
+ list<ESignal> signals;
+}
+
+struct EProperty {
+ string name
+ EType type
+}
+
+struct EOperation {
+ string name;
+ EType type;
+ list<EParameter> parameters;
+}
+
+struct ESignal {
+ string name;
+ list<EParameter> parameters;
+}
+
+struct EStruct {
+ string name;
+ list<EField> fields;
+}
+
+struct EField {
+ string name;
+ EType type;
+}
+
+struct Enum {
+ string name
+ model<EEnumMember> members;
+}
+
+struct EEnumMember {
+ int value;
+ string name;
+}
+
+struct EFlag {
+ string name
+ model<EEnumMember> members;
+}
+
+
+
diff --git a/qface/__about__.py b/qface/__about__.py
index 6c54abd..e63ff15 100644
--- a/qface/__about__.py
+++ b/qface/__about__.py
@@ -8,8 +8,8 @@ except NameError:
__title__ = "qface"
__summary__ = "A generator framework based on a common modern IDL"
-__uri__ = "https://pelagicore.github.io/qface/"
-__version__ = "1.1"
+__url__ = "https://pelagicore.github.io/qface/"
+__version__ = "1.9.1"
__author__ = "JRyannel"
__author_email__ = "qface-generator@googlegroups.com"
-__copyright__ = "2017 Pelagicore"
+__copyright__ = "2019 Pelagicore"
diff --git a/qface/builtin/qtcpp/__init__.py b/qface/builtin/qtcpp/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/qface/builtin/qtcpp/__init__.py
+++ /dev/null
diff --git a/qface/builtin/qtcpp/log.yaml b/qface/builtin/qtcpp/log.yaml
deleted file mode 100644
index 21b5bba..0000000
--- a/qface/builtin/qtcpp/log.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-version: 1
-formatters:
- simple:
- format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
-handlers:
- console:
- class: logging.StreamHandler
- level: INFO
- formatter: simple
- stream: ext://sys.stdout
-loggers:
- qface.generator:
- level: WARN
- handlers: [console]
- propagate: no
-root:
- level: DEBUG
- handlers: [console]
diff --git a/qface/builtin/qtcpp/qtcpp.py b/qface/builtin/qtcpp/qtcpp.py
deleted file mode 100755
index 283b8f6..0000000
--- a/qface/builtin/qtcpp/qtcpp.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) Pelagicore AB 2016
-
-import click
-import logging
-import logging.config
-import yaml
-from path import Path
-
-from qface.generator import FileSystem, Generator
-from qface.helper.qtcpp import Filters
-from qface.helper.doc import parse_doc
-from qface.watch import monitor
-
-
-here = Path(__file__).dirname()
-
-logging.config.dictConfig(yaml.load(open(here / 'log.yaml')))
-
-log = logging.getLogger(__file__)
-
-
-def run(src, dst):
- log.debug('run {0} {1}'.format(src, dst))
- system = FileSystem.parse(src)
- generator = Generator(search_path=here / 'templates')
- generator.register_filter('returnType', Filters.returnType)
- generator.register_filter('parameterType', Filters.parameterType)
- generator.register_filter('defaultValue', Filters.defaultValue)
- generator.register_filter('parse_doc', parse_doc)
- ctx = {'dst': dst}
- for module in system.modules:
- log.debug('generate code for module %s', module)
- ctx.update({'module': module})
- dst = generator.apply('{{dst}}/{{module|lower|replace(".", "-")}}', ctx)
- generator.destination = dst
- generator.write('qmldir', 'qmldir', ctx, preserve=True)
- generator.write('plugin.cpp', 'plugin.cpp', ctx, preserve=True)
- generator.write('plugin.h', 'plugin.h', ctx, preserve=True)
- generator.write('{{module|lower|replace(".", "-")}}.pro', 'plugin.pro', ctx, preserve=True)
- generator.write('generated/generated.pri', 'generated.pri', ctx)
- generator.write('generated/qml{{module.module_name|lower}}module.h', 'module.h', ctx)
- generator.write('generated/qml{{module.module_name|lower}}module.cpp', 'module.cpp', ctx)
- generator.write('generated/qmlvariantmodel.h', 'variantmodel.h', ctx)
- generator.write('generated/qmlvariantmodel.cpp', 'variantmodel.cpp', ctx)
- generator.write('docs/plugin.qdocconf', 'plugin.qdocconf', ctx)
- generator.write('docs/plugin-project.qdocconf', 'plugin-project.qdocconf', ctx)
- generator.write('docs/docs.pri', 'docs.pri', ctx)
- generator.write('.qmake.conf', 'qmake.conf', ctx)
- for interface in module.interfaces:
- log.debug('generate code for interface %s', interface)
- ctx.update({'interface': interface})
- generator.write('qml{{interface|lower}}.h', 'interface.h', ctx, preserve=True)
- generator.write('qml{{interface|lower}}.cpp', 'interface.cpp', ctx, preserve=True)
- generator.write('generated/qmlabstract{{interface|lower}}.h', 'abstractinterface.h', ctx)
- generator.write('generated/qmlabstract{{interface|lower}}.cpp', 'abstractinterface.cpp', ctx)
- for struct in module.structs:
- log.debug('generate code for struct %s', struct)
- ctx.update({'struct': struct})
- generator.write('generated/qml{{struct|lower}}.h', 'struct.h', ctx)
- generator.write('generated/qml{{struct|lower}}.cpp', 'struct.cpp', ctx)
- generator.write('generated/qml{{struct|lower}}model.h', 'structmodel.h', ctx)
- generator.write('generated/qml{{struct|lower}}model.cpp', 'structmodel.cpp', ctx)
-
-
-@click.command()
-@click.option('--reload/--no-reload', default=False)
-@click.argument('src', nargs=-1, type=click.Path(exists=True))
-@click.argument('dst', nargs=1, type=click.Path(exists=True))
-def app(src, dst, reload):
- """Takes several files or directories as src and generates the code
- in the given dst directory."""
- if reload:
- script = Path(__file__).abspath()
- monitor(script, src, dst)
- else:
- run(src, dst)
-
-
-if __name__ == '__main__':
- app()
diff --git a/qface/builtin/qtcpp/templates/__init__.py b/qface/builtin/qtcpp/templates/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/qface/builtin/qtcpp/templates/__init__.py
+++ /dev/null
diff --git a/qface/builtin/qtcpp/templates/abstractinterface.cpp b/qface/builtin/qtcpp/templates/abstractinterface.cpp
deleted file mode 100644
index 3a70cb6..0000000
--- a/qface/builtin/qtcpp/templates/abstractinterface.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-{% set class = 'QmlAbstract{0}'.format(interface) %}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-
-#include "{{class|lower}}.h"
-
-#include <QtQml>
-
-/*!
- \qmltype {{interface}}
- \inqmlmodule {{module}}
-{% with doc = interface.comment|parse_doc %}
- \brief {{doc.brief}}
-
- {{doc.description}}
-{% endwith %}
-*/
-{{class}}::{{class}}(QObject *parent)
- : QObject(parent)
-{% for property in interface.properties %}
- , m_{{property}}({{property|defaultValue}})
-{% endfor %}
-{
-}
-
-
-{{class}}::~{{class}}()
-{
-}
-
-{% for property in interface.properties %}
-/*!
- \qmlproperty {{property.type}} {{interface}}::{{property}}
-{% with doc = property.comment|parse_doc %}
- \brief {{doc.brief}}
-
- {{doc.description}}
-{% endwith %}
-*/
-
-void {{class}}::set{{property|upperfirst}}({{ property|parameterType }})
-{
- if(m_{{property}} == {{property}}) {
- return;
- }
- m_{{property}} = {{property}};
- emit {{property}}Changed();
-}
-
-{{property|returnType}} {{class}}::{{property}}() const
-{
- return m_{{property}};
-}
-{% endfor %}
-
-{%- for operation in interface.operations %}
-/*!
- \qmlmethod {{operation.type}} {{interface}}::{{operation}}({{operation.parameters|map('parameterType')|join(', ')}})
-{% with doc = operation.comment|parse_doc %}
- \brief {{doc.brief}}
- {{doc.description}}
-{% endwith %}
-*/
-{{operation|returnType}} {{class}}::{{operation}}({{operation.parameters|map('parameterType')|join(', ')}})
-{
- {% for parameter in operation.parameters %}
- Q_UNUSED({{parameter.name}});
- {% endfor %}
- qWarning() << "{{class}}::{{operation}}(...) not implemented";
- return {{operation|defaultValue}};
-}
-{% endfor %}
-
-
diff --git a/qface/builtin/qtcpp/templates/abstractinterface.h b/qface/builtin/qtcpp/templates/abstractinterface.h
deleted file mode 100644
index 5335632..0000000
--- a/qface/builtin/qtcpp/templates/abstractinterface.h
+++ /dev/null
@@ -1,53 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-{% set class = 'QmlAbstract{0}'.format(interface) %}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-
-#pragma once
-
-#include <QtCore>
-
-#include "qml{{module.module_name|lower}}module.h"
-
-class {{class}} : public QObject
-{
- Q_OBJECT
-{% for property in interface.properties %}
- Q_PROPERTY({{property|returnType}} {{property}} READ {{property}} {% if not property.is_readonly %}
-WRITE set{{property|upperfirst}} {% endif %}NOTIFY {{property}}Changed)
-{% endfor %}
-
-public:
- {{class}}(QObject *parent = nullptr);
- ~{{class}}();
-
-public Q_SLOTS:
-{% for operation in interface.operations %}
- virtual {{operation|returnType}} {{operation}}({{operation.parameters|map('parameterType')|join(', ')}});
-{% endfor %}
-
-public:
-{% for property in interface.properties %}
- virtual void set{{property|upperfirst}}({{ property|parameterType }});
-{% endfor %}
-
-public:
-{% for property in interface.properties %}
- virtual {{property|returnType}} {{property}}() const;
-{% endfor %}
-
-Q_SIGNALS:
-{% for signal in interface.signals %}
- void {{signal}}({{signal.parameters|map('parameterType')|join(', ')}});
-{% endfor %}
-{% for property in interface.properties %}
- void {{property}}Changed();
-{% endfor %}
-
-protected:
-{% for property in interface.properties %}
- {{property|returnType}} m_{{property}};
-{% endfor %}
-};
diff --git a/qface/builtin/qtcpp/templates/docs.pri b/qface/builtin/qtcpp/templates/docs.pri
deleted file mode 100644
index f6a3e81..0000000
--- a/qface/builtin/qtcpp/templates/docs.pri
+++ /dev/null
@@ -1,32 +0,0 @@
-exists($$[QT_INSTALL_BINS]/qdoc):exists($$[QT_INSTALL_BINS]/qhelpgenerator) {
- check_qdoc = "qdoc/qhelpgenerator in $$[QT_INSTALL_BINS]"
- QDOC = $$[QT_INSTALL_BINS]/qdoc
- QHELPGENERATOR = $$[QT_INSTALL_BINS]/qhelpgenerator
-} else {
- check_qdoc = "qdoc/qhelpgenerator in PATH"
- QDOC = qdoc
- QHELPGENERATOR = qhelpgenerator
-}
-
-defineReplace(cmdEnv) {
- !equals(QMAKE_DIR_SEP, /): 1 ~= s,^(.*)$,(set \\1) &&,g
- return("$$1")
-}
-
-defineReplace(qdoc) {
- return("$$cmdEnv(OUTDIR=$$1 QMLLIVE_VERSION=$$VERSION QMLLIVE_VERSION_TAG=$$VERSION_TAG QT_INSTALL_DOCS=$$[QT_INSTALL_DOCS/src]) $$QDOC")
-}
-
-html-docs.commands = $$qdoc($$BUILD_DIR/doc/html) $$PWD/plugin.qdocconf
-html-docs.files = $$BUILD_DIR/doc/html
-
-docs.depends = html-docs
-
-QMAKE_EXTRA_TARGETS += html-docs docs
-
-
-OTHER_FILES += \
- $$PWD/*.qdocconf \
- $$PWD/*.qdoc \
- $$PWD/examples/*.qdoc \
- $$PWD/images/*.png
diff --git a/qface/builtin/qtcpp/templates/generated.pri b/qface/builtin/qtcpp/templates/generated.pri
deleted file mode 100644
index 7457474..0000000
--- a/qface/builtin/qtcpp/templates/generated.pri
+++ /dev/null
@@ -1,33 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-#############################################################################
-## This is an auto-generated file.
-## Do not edit! All changes made to it will be lost.
-#############################################################################
-
-QT += qml quick
-CONFIG += c++11
-
-HEADERS += \
- $$PWD/qml{{module.module_name|lower}}module.h \
-{% for interface in module.interfaces %}
- $$PWD/qmlabstract{{interface|lower}}.h \
-{% endfor %}
-{% for struct in module.structs %}
- $$PWD/qml{{struct|lower}}.h \
- $$PWD/qml{{struct|lower}}model.h \
-{% endfor %}
- $$PWD/qmlvariantmodel.h
-
-
-SOURCES += \
- $$PWD/qml{{module.module_name|lower}}module.cpp \
-{% for interface in module.interfaces %}
- $$PWD/qmlabstract{{interface|lower}}.cpp \
-{% endfor %}
-{% for struct in module.structs %}
- $$PWD/qml{{struct|lower}}.cpp \
- $$PWD/qml{{struct|lower}}model.cpp \
-{% endfor %}
- $$PWD/qmlvariantmodel.cpp
-
-
diff --git a/qface/builtin/qtcpp/templates/interface.cpp b/qface/builtin/qtcpp/templates/interface.cpp
deleted file mode 100644
index 3e86be0..0000000
--- a/qface/builtin/qtcpp/templates/interface.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-{% set class = 'Qml{0}'.format(interface) %}
-/*
- * This is a preserved file and can be edited.
- * All changes will not be override.
- */
-
-#include "{{class|lower}}.h"
-
-#include <QtQml>
-
-
-/*!
- \inqmlmodule {{module}} 1.0
- */
-
-QObject* {{class|lower}}_singletontype_provider(QQmlEngine*, QJSEngine*)
-{
- return new {{class}}();
-}
-
-
-/*!
- \qmltype {{interface}}
- \inqmlmodule {{module}}
-{% with doc = interface.comment|parse_doc %}
- \brief {{doc.brief}}
-
- {{doc.description}}
-{% endwith %}
-*/
-
-{{interface.comment}}
-{{class}}::{{class}}(QObject *parent)
- : QmlAbstract{{interface}}(parent)
-{
-}
-
-{{class}}::~{{class}}()
-{
-}
-
-void {{class}}::registerQmlTypes(const QString& uri, int majorVersion, int minorVersion)
-{
- {% if 'singleton' in interface.tags %}
- qmlRegisterSingletonType<{{class}}>(uri.toLatin1(), majorVersion, minorVersion, "{{interface}}", {{class|lower}}_singletontype_provider);
- {% else %}
- qmlRegisterType<{{class}}>(uri.toLatin1(), majorVersion, minorVersion, "{{interface}}");
- {% endif %}
-}
diff --git a/qface/builtin/qtcpp/templates/interface.h b/qface/builtin/qtcpp/templates/interface.h
deleted file mode 100644
index 6ada967..0000000
--- a/qface/builtin/qtcpp/templates/interface.h
+++ /dev/null
@@ -1,24 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-{% set class = 'Qml{0}'.format(interface) %}
-/*
- * This is a preserved file and can be edited.
- * All changes will not be override.
- */
-
-
-#pragma once
-
-#include <QtCore>
-
-#include "generated/qml{{module.module_name|lower}}module.h"
-#include "generated/qmlabstract{{interface|lower}}.h"
-
-class {{class}} : public QmlAbstract{{interface}}
-{
- Q_OBJECT
-public:
- {{class}}(QObject *parent = nullptr);
- virtual ~{{class}}();
-
- static void registerQmlTypes(const QString& uri, int majorVersion=1, int minorVersion=0);
-};
diff --git a/qface/builtin/qtcpp/templates/module.cpp b/qface/builtin/qtcpp/templates/module.cpp
deleted file mode 100644
index af2d2f1..0000000
--- a/qface/builtin/qtcpp/templates/module.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-{% set class = 'Qml{0}Module'.format(module.module_name) %}
-
-
-#include "{{class|lower}}.h"
-
-#include <QtQml>
-
-/*!
- \qmlmodule {{module}} 1.0
-{% with doc = module.comment|parse_doc %}
-
- {{doc.brief}}
-
-
- {{doc.description}}
-{% endwith %}
- */
-
-
-/*!
- \qmltype {{module.module_name}}Module
- \inqmlmodule {{module}}
- \brief API to access module functionality
-
- Provides the enumerations and data type factories for
- this module.
-*/
-QObject* {{class|lower}}_singletontype_provider(QQmlEngine*, QJSEngine*)
-{
- return new {{class}}();
-}
-
-{{class}}::{{class}}(QObject *parent)
- : QObject(parent)
-{
-}
-
-{% for struct in module.structs %}
-/*!
- \qmlmethod {{struct}} {{module.module_name}}Module::create{{struct}}()
- \brief Creates a default constructed data object from type {{struct}}
-*/
-Qml{{struct}} {{class}}::create{{struct}}()
-{
- return Qml{{struct}}();
-}
-{% endfor %}
-
-void {{class}}::registerTypes()
-{
- {% for struct in module.structs %}
- qRegisterMetaType<Qml{{struct}}>();
- {% endfor %}
- {% for enum in module.enums %}
- qRegisterMetaType<{{class}}::{{enum}}>();
- {% endfor %}
-}
-
-void {{class}}::registerQmlTypes(const QString& uri, int majorVersion, int minorVersion)
-{
- {% for struct in module.structs %}
- qmlRegisterUncreatableType<Qml{{struct}}Model>(uri.toLatin1(), majorVersion, minorVersion, "{{struct}}Model", "Model can not be instantiated from QML");
- {% endfor %}
- qmlRegisterSingletonType<{{class}}>(uri.toLatin1(), majorVersion, minorVersion, "{{module.module_name}}Module", {{class|lower}}_singletontype_provider);
-}
-
-
-{% for enum in module.enums %}
-/**
- * \qmlproperty enumeration {{module.module_name}}Module::{{enum}}
- * \list
- {% for member in enum.members %}
- * \li {{member}}
- {% endfor %}
- * \endlist
- */
-{% endfor %} \ No newline at end of file
diff --git a/qface/builtin/qtcpp/templates/module.h b/qface/builtin/qtcpp/templates/module.h
deleted file mode 100644
index 5e9ff6f..0000000
--- a/qface/builtin/qtcpp/templates/module.h
+++ /dev/null
@@ -1,41 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-{% set class = 'Qml{0}Module'.format(module.module_name) %}
-
-#pragma once
-
-#include <QtCore>
-
-#include "qmlvariantmodel.h"
-{% for struct in module.structs %}
-#include "qml{{struct|lower}}.h"
-#include "qml{{struct|lower}}model.h"
-{% endfor %}
-
-class {{class}} : public QObject {
- Q_OBJECT
-public:
- {{class}}(QObject *parent = nullptr);
-
-{% for enum in module.enums %}
- {% set comma = joiner(",") %}
- enum {{enum}} {
- {%- for member in enum.members -%}
- {{ comma() }}
- {{member.name}} = {{member.value}}
- {%- endfor %}
-
- };
- Q_ENUM({{enum}})
-{% endfor %}
-
-{% for struct in module.structs %}
- Q_INVOKABLE Qml{{struct}} create{{struct}}();
-{% endfor %}
-
- static void registerTypes();
- static void registerQmlTypes(const QString& uri, int majorVersion = 1, int minorVersion = 0);
-};
diff --git a/qface/builtin/qtcpp/templates/plugin-online.qdocconf b/qface/builtin/qtcpp/templates/plugin-online.qdocconf
deleted file mode 100644
index 771cdae..0000000
--- a/qface/builtin/qtcpp/templates/plugin-online.qdocconf
+++ /dev/null
@@ -1,19 +0,0 @@
-HTML.footer = \
- " </div>\n" \
- " <p class=\"copy-notice\">\n" \
- " <acronym title=\"Copyright\">&copy;</acronym> 2016 Pelagicore AG.\n" \
- " Documentation contributions included herein are the copyrights of\n" \
- " their respective owners. " \
- " The documentation provided herein is licensed under the terms of the" \
- " <a href=\"http://www.gnu.org/licenses/fdl.html\">GNU Free Documentation" \
- " License version 1.3</a> as published by the Free Software Foundation. " \
- " Qt and respective logos are trademarks of The Qt Company Ltd. " \
- " in Finland and/or other countries worldwide. All other trademarks are property\n" \
- " of their respective owners. </p>\n"
-
-include($QT_INSTALL_DOCS/global/qt-html-templates-online.qdocconf)
-
-# Add an .html file with sidebar content, used in the online style
-# HTML.stylesheets += style/qt5-sidebar.html
-
-include(plugin-project.qdocconf)
diff --git a/qface/builtin/qtcpp/templates/plugin-project.qdocconf b/qface/builtin/qtcpp/templates/plugin-project.qdocconf
deleted file mode 100644
index 0a846cb..0000000
--- a/qface/builtin/qtcpp/templates/plugin-project.qdocconf
+++ /dev/null
@@ -1,27 +0,0 @@
-{% set module_name = module|lower|replace(".", "_")%}
-project = {{module}}
-description = {{module|upper}} Reference Documentation
-version = 1.0
-
-sources.fileextensions = "*.cpp *.qdoc *.mm *.qml"
-headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx"
-
-examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp *.qml"
-examples.imageextensions = "*.png *.jpeg *.jpg *.gif *.mng"
-
-outputdir = html
-
-exampledirs = ../examples ../src
-
-headerdirs = \
- .. \
- ../generated
-
-sourcedirs = \
- .. \
- ../generated
-
-imagedirs = images
-
-navigation.landingpage = "{{module}}"
-buildversion = "{{module_name}} 1.0"
diff --git a/qface/builtin/qtcpp/templates/plugin.cpp b/qface/builtin/qtcpp/templates/plugin.cpp
deleted file mode 100644
index aa8fb9a..0000000
--- a/qface/builtin/qtcpp/templates/plugin.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-{% set module_name = 'Qml{0}Module'.format(module.module_name) %}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-
-#include "plugin.h"
-
-#include <qqml.h>
-
-#include "generated/{{module_name|lower}}.h"
-
-{% for interface in module.interfaces %}
-#include "qml{{interface|lower}}.h"
-{% endfor %}
-
-void Plugin::registerTypes(const char *uri)
-{
- {{module_name}}::registerTypes();
- // @uri {{module|lower}}
- {{module_name}}::registerQmlTypes(uri, 1, 0);
-{% for interface in module.interfaces %}
- Qml{{interface}}::registerQmlTypes(uri, 1, 0);
-{% endfor %}
-}
diff --git a/qface/builtin/qtcpp/templates/plugin.h b/qface/builtin/qtcpp/templates/plugin.h
deleted file mode 100644
index 1952c35..0000000
--- a/qface/builtin/qtcpp/templates/plugin.h
+++ /dev/null
@@ -1,18 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-
-#pragma once
-
-#include <QtQml>
-
-class Plugin : public QQmlExtensionPlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
-
-public:
- void registerTypes(const char *uri);
-};
diff --git a/qface/builtin/qtcpp/templates/plugin.pro b/qface/builtin/qtcpp/templates/plugin.pro
deleted file mode 100644
index 4984015..0000000
--- a/qface/builtin/qtcpp/templates/plugin.pro
+++ /dev/null
@@ -1,47 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-
-## This is a preserved file and can be edited.
-## All changes will not be override.
-
-TEMPLATE = lib
-QT += qml quick
-CONFIG += qt plugin c++11
-TARGET = $$qtLibraryTarget({{module|lower}})
-
-uri = {{module}}
-
-
-HEADERS += \
-{% for interface in module.interfaces %}
- qml{{interface|lower}}.h \
-{% endfor %}
- plugin.h
-
-
-SOURCES += \
-{% for interface in module.interfaces %}
- qml{{interface|lower}}.cpp \
-{% endfor %}
- plugin.cpp
-
-
-include( generated/generated.pri )
-include( docs/docs.pri )
-
-DISTFILES = qmldir
-
-!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
- copy_qmldir.target = $$OUT_PWD/qmldir
- copy_qmldir.depends = $$_PRO_FILE_PWD_/qmldir
- copy_qmldir.commands = $(COPY_FILE) \"$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)\"
- QMAKE_EXTRA_TARGETS += copy_qmldir
- PRE_TARGETDEPS += $$copy_qmldir.target
-}
-
-qmldir.files = qmldir
-unix {
- installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)
- qmldir.path = $$installPath
- target.path = $$installPath
- INSTALLS += target qmldir
-}
diff --git a/qface/builtin/qtcpp/templates/plugin.qdocconf b/qface/builtin/qtcpp/templates/plugin.qdocconf
deleted file mode 100644
index a45a34b..0000000
--- a/qface/builtin/qtcpp/templates/plugin.qdocconf
+++ /dev/null
@@ -1,21 +0,0 @@
-include($QT_INSTALL_DOCS/global/qt-html-templates-offline.qdocconf)
-include(plugin-project.qdocconf)
-
-HTML.footer = \
- " </div>\n" \
- " </div>\n" \
- " </div>\n" \
- " </div>\n" \
- "</div>\n" \
- "<div class=\"footer\">\n" \
- " <p>\n" \
- " <acronym title=\"Copyright\">&copy;</acronym> 2016 Pelagicore AG.\n" \
- " Documentation contributions included herein are the copyrights of\n" \
- " their respective owners.<br>" \
- " The documentation provided herein is licensed under the terms of the" \
- " <a href=\"http://www.gnu.org/licenses/fdl.html\">GNU Free Documentation" \
- " License version 1.3</a> as published by the Free Software Foundation.<br>" \
- " Qt and respective logos are trademarks of The Qt Company Ltd. " \
- " in Finland and/or other countries worldwide. All other trademarks are property\n" \
- " of their respective owners. </p>\n" \
- "</div>\n"
diff --git a/qface/builtin/qtcpp/templates/qmake.conf b/qface/builtin/qtcpp/templates/qmake.conf
deleted file mode 100644
index 03d3435..0000000
--- a/qface/builtin/qtcpp/templates/qmake.conf
+++ /dev/null
@@ -1,5 +0,0 @@
-SOURCE_DIR=$$PWD
-BUILD_DIR=$$shadowed($$PWD)
-QMAKEFEATURES=$$SOURCE_DIR/qmake-features
-
-VERSION = 1.0.0
diff --git a/qface/builtin/qtcpp/templates/qmldir b/qface/builtin/qtcpp/templates/qmldir
deleted file mode 100644
index 9fe5d2b..0000000
--- a/qface/builtin/qtcpp/templates/qmldir
+++ /dev/null
@@ -1,3 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-module {{module}}
-plugin {{module}} \ No newline at end of file
diff --git a/qface/builtin/qtcpp/templates/struct.cpp b/qface/builtin/qtcpp/templates/struct.cpp
deleted file mode 100644
index 86f358c..0000000
--- a/qface/builtin/qtcpp/templates/struct.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-{% set class = 'Qml{0}'.format(struct) %}
-{% set ampersand = joiner(" &&") %}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-
-#include "{{class|lower}}.h"
-
-
-class {{class}}Data : public QSharedData
-{
-public:
- {{class}}Data()
- : QSharedData()
- {% for field in struct.fields %}
- , {{field}}({{field|defaultValue}})
- {% endfor %}
- {
- }
- {{class}}Data(const {{class}}Data &other)
- : QSharedData(other)
- {% for field in struct.fields %}
- , {{field}}(other.{{field}})
- {% endfor %}
- {
- }
-
-public:
-{% for field in struct.fields %}
- {{field|returnType}} {{field}};
-{% endfor %}
-};
-
-// Class
-
-/*!
- \qmltype {{struct}}
- \inqmlmodule {{module}}
-{% with doc = struct.comment|parse_doc %}
- \brief {{doc.brief}}
-
- \note This is a none creatable data object
-
- Use the module factory method \l {{module.module_name}}Module::create{{struct}} to create
- an instance.
-
- {{doc.description}}
-{% endwith %}
-*/
-
-{{class}}::{{class}}()
- : d(new {{class}}Data)
-{
-}
-
-{{class}}::{{class}}(const {{class}} &other)
- : d(other.d)
-{
-}
-
-{{class}}::~{{class}}()
-{
-}
-
-{% for field in struct.fields %}
-/*!
- \qmlproperty {{field.type}} {{struct}}::{{field}} (field)
-{% with doc = field.comment|parse_doc %}
- \brief {{doc.brief}}
-
- \note A none notifiable property
-
- {{doc.description}}
-{% endwith %}
-*/
-void {{class}}::set{{field|upperfirst}}({{field|parameterType}})
-{
- d->{{field}} = {{field}};
-}
-{{field|returnType}} {{class}}::{{field}}() const
-{
- return d->{{field}};
-}
-
-{% endfor %}
-
-
-
-{{class}} {{class}}::clone()
-{
- {{class}} other(*this);
- other.d.detach();
- return other;
-}
-
-bool {{class}}::operator==(const {{class}} &other) const
-{
- return (
- {%- for field in struct.fields %}{{ ampersand() }}
- {{field}}() == other.{{field}}()
- {%- endfor %}
- );
-}
-
-{{class}} &{{class}}::operator=(const {{class}} &other)
-{
- d = other.d;
- return *this;
-}
-
diff --git a/qface/builtin/qtcpp/templates/struct.h b/qface/builtin/qtcpp/templates/struct.h
deleted file mode 100644
index 7c6a4e6..0000000
--- a/qface/builtin/qtcpp/templates/struct.h
+++ /dev/null
@@ -1,45 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-{% set class = 'Qml{0}'.format(struct) %}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-
-#pragma once
-
-#include <QtCore>
-
-
-class {{class}}Data;
-
-class {{class}}
-{
- Q_GADGET
-{% for field in struct.fields %}
- Q_PROPERTY({{field|returnType}} {{field}} READ {{field}} WRITE set{{field|upperfirst}})
-{% endfor %}
-
-public:
- {{class}}();
- {{class}}(const {{class}} &other);
- ~{{class}}();
-
- Q_INVOKABLE {{class}} clone();
-
- bool operator==(const {{class}} &other) const;
- {{class}} &operator=(const {{class}} &other);
-
-{% for field in struct.fields %}
- void set{{field|upperfirst}}({{field|parameterType}});
- {{field|returnType}} {{field}}() const;
-
-{% endfor %}
-
-
-private:
- QExplicitlySharedDataPointer <{{class}}Data> d;
-};
-
-Q_DECLARE_METATYPE({{class}})
-
-
diff --git a/qface/builtin/qtcpp/templates/structmodel.cpp b/qface/builtin/qtcpp/templates/structmodel.cpp
deleted file mode 100644
index 2759dae..0000000
--- a/qface/builtin/qtcpp/templates/structmodel.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-{% set class = 'Qml{0}Model'.format(struct) %}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-
-#include "{{class|lower}}.h"
-
-{{class}}::{{class}}(QObject *parent)
- : QAbstractListModel(parent)
-{
- {% for field in struct.fields %}
- m_roleNames.insert(Roles::{{field|upperfirst}}, QByteArray("{{field}}"));
- {% endfor %}
-}
-
-int {{class}}::count() const
-{
- return m_data.count();
-}
-
-Qml{{struct}} {{class}}::get(int index)
-{
- return m_data.value(index);
-}
-
-int {{class}}::rowCount(const QModelIndex &parent) const
-{
- Q_UNUSED(parent)
- return m_data.count();
-}
-
-QVariant {{class}}::data(const QModelIndex &index, int role) const
-{
- if(index.row() < 0 || index.row() >= count()) {
- return QVariant();
- }
- const Qml{{struct}} &{{struct|lower}} = m_data.at(index.row());
- switch(role) {
- {% for field in struct.fields %}
- case Roles::{{field|upperfirst}}:
- return QVariant::fromValue({{struct|lower}}.{{field}}());
- {% endfor %}
- }
- return QVariant();
-}
-
-QHash<int, QByteArray> {{class}}::roleNames() const
-{
- return m_roleNames;
-}
-
-
-void {{class}}::insert(int row, const Qml{{struct}} &{{struct|lower}})
-{
- if (row < 0)
- row = 0;
- if (row >= m_data.count())
- row = m_data.count();
-
- beginInsertRows(QModelIndex(), row, row);
- m_data.insert(row, {{struct|lower}});
- endInsertRows();
- emit countChanged(count());
-}
-
-void {{class}}::reset(const QList<Qml{{struct}}> data)
-{
- beginResetModel();
- m_data = data;
- endResetModel();
-}
-
-void {{class}}::append(const Qml{{struct}} &{{struct|lower}})
-{
- insert(m_data.count(), {{struct|lower}});
-}
-
-void {{class}}::update(int row, const Qml{{struct}} &{{struct|lower}})
-{
- if(row < 0 || row >= m_data.count()) {
- return;
- }
- m_data[row] = {{struct|lower}};
- const QModelIndex &index = createIndex(row, 0);
- emit dataChanged(index, index);
-}
-
-void {{class}}::remove(int row)
-{
- if(row < 0 || row >= m_data.count()) {
- return;
- }
- beginRemoveRows(QModelIndex(), row, row);
- m_data.removeAt(row);
- endRemoveRows();
-}
-
-void {{class}}::clear()
-{
- beginResetModel();
- m_data.clear();
- endResetModel();
-}
-
diff --git a/qface/builtin/qtcpp/templates/structmodel.h b/qface/builtin/qtcpp/templates/structmodel.h
deleted file mode 100644
index ab02b25..0000000
--- a/qface/builtin/qtcpp/templates/structmodel.h
+++ /dev/null
@@ -1,40 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-{% set class = 'Qml{0}Model'.format(struct) %}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-
-#pragma once
-
-#include <QtCore>
-
-#include "qml{{struct|lower}}.h"
-
-class {{class}} : public QAbstractListModel
-{
- Q_OBJECT
- Q_PROPERTY(int count READ count NOTIFY countChanged)
-public:
- enum Roles { {{struct.fields|map('upperfirst')|join(', ')}} };
- {{class}}(QObject *parent = nullptr);
- Q_INVOKABLE Qml{{struct}} get(int index);
- int count() const;
- void insert(int row, const Qml{{struct}} &{{struct|lower}});
- void append(const Qml{{struct}} &{{struct|lower}});
- void update(int row, const Qml{{struct}} &{{struct|lower}});
- void remove(int row);
- void reset(const QList<Qml{{struct}}> data);
- void clear();
-public: // from QAbstractListModel
- virtual int rowCount(const QModelIndex &parent) const;
- virtual QVariant data(const QModelIndex &index, int role) const;
- virtual QHash<int, QByteArray> roleNames() const;
-Q_SIGNALS:
- void countChanged(int count);
-private:
- QList<Qml{{struct}}> m_data;
- QHash<int, QByteArray> m_roleNames;
-};
-
-
diff --git a/qface/builtin/qtcpp/templates/variantmodel.cpp b/qface/builtin/qtcpp/templates/variantmodel.cpp
deleted file mode 100644
index 6e197f4..0000000
--- a/qface/builtin/qtcpp/templates/variantmodel.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-{% set class = 'QmlVariantModel' %}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-
-#include "{{class|lower}}.h"
-
-{{class}}::{{class}}(QObject *parent)
- : QAbstractListModel(parent)
-{
- m_roleNames.insert(Roles::ModelData, QByteArray("modelData"));
-}
-
-int {{class}}::count() const
-{
- return m_data.count();
-}
-
-QVariant {{class}}::get(int index)
-{
- return m_data.value(index);
-}
-
-int {{class}}::rowCount(const QModelIndex &parent) const
-{
- Q_UNUSED(parent)
- return m_data.count();
-}
-
-QVariant {{class}}::data(const QModelIndex &index, int role) const
-{
- if(index.row() < 0 || index.row() >= count()) {
- return QVariant();
- }
- const QVariant &entry = m_data.at(index.row());
- switch(role) {
- case Roles::ModelData:
- return entry;
- }
- return QVariant();
-}
-
-QHash<int, QByteArray> {{class}}::roleNames() const
-{
- return m_roleNames;
-}
-
-
-void {{class}}::insert(int row, const QVariant &entry)
-{
- if (row < 0)
- row = 0;
- if (row >= m_data.count())
- row = m_data.count();
-
- beginInsertRows(QModelIndex(), row, row);
- m_data.insert(row, entry);
- endInsertRows();
- emit countChanged(count());
-}
-
-void {{class}}::reset(const QVariantList entries)
-{
- beginResetModel();
- m_data = entries;
- endResetModel();
-}
-
-void {{class}}::append(const QVariant &entry)
-{
- insert(m_data.count(), entry);
-}
-
-void {{class}}::update(int row, const QVariant &entry)
-{
- if(row < 0 || row >= m_data.count()) {
- return;
- }
- m_data[row] = entry;
- const QModelIndex &index = createIndex(row, 0);
- emit dataChanged(index, index);
-}
-
-void {{class}}::remove(int row)
-{
- if(row < 0 || row >= m_data.count()) {
- return;
- }
- beginRemoveRows(QModelIndex(), row, row);
- m_data.removeAt(row);
- endRemoveRows();
-}
-
-void {{class}}::clear()
-{
- beginResetModel();
- m_data.clear();
- endResetModel();
-}
-
diff --git a/qface/builtin/qtcpp/templates/variantmodel.h b/qface/builtin/qtcpp/templates/variantmodel.h
deleted file mode 100644
index 3f1bbd3..0000000
--- a/qface/builtin/qtcpp/templates/variantmodel.h
+++ /dev/null
@@ -1,38 +0,0 @@
-{# Copyright (c) Pelagicore AB 2016 #}
-{% set class = 'QmlVariantModel' %}
-/****************************************************************************
-** This is an auto-generated file.
-** Do not edit! All changes made to it will be lost.
-****************************************************************************/
-
-#pragma once
-
-#include <QtCore>
-
-class {{class}} : public QAbstractListModel
-{
- Q_OBJECT
- Q_PROPERTY(int count READ count NOTIFY countChanged)
-public:
- enum Roles { ModelData = Qt::UserRole };
- {{class}}(QObject *parent = nullptr);
- Q_INVOKABLE QVariant get(int index);
- int count() const;
- void insert(int row, const QVariant &entry);
- void append(const QVariant &entry);
- void update(int row, const QVariant &entry);
- void remove(int row);
- void reset(const QVariantList entries);
- void clear();
-public: // from QAbstractListModel
- virtual int rowCount(const QModelIndex &parent) const;
- virtual QVariant data(const QModelIndex &index, int role) const;
- virtual QHash<int, QByteArray> roleNames() const;
-Q_SIGNALS:
- void countChanged(int count);
-private:
- QVariantList m_data;
- QHash<int, QByteArray> m_roleNames;
-};
-
-
diff --git a/qface/builtin/qtqml/__init__.py b/qface/builtin/qtqml/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/qface/builtin/qtqml/__init__.py
+++ /dev/null
diff --git a/qface/builtin/qtqml/log.yaml b/qface/builtin/qtqml/log.yaml
deleted file mode 100644
index 21b5bba..0000000
--- a/qface/builtin/qtqml/log.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-version: 1
-formatters:
- simple:
- format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
-handlers:
- console:
- class: logging.StreamHandler
- level: INFO
- formatter: simple
- stream: ext://sys.stdout
-loggers:
- qface.generator:
- level: WARN
- handlers: [console]
- propagate: no
-root:
- level: DEBUG
- handlers: [console]
diff --git a/qface/builtin/qtqml/qtqml.py b/qface/builtin/qtqml/qtqml.py
deleted file mode 100755
index 1d00d74..0000000
--- a/qface/builtin/qtqml/qtqml.py
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) Pelagicore AB 2016
-
-import click
-import logging
-import logging.config
-import yaml
-from path import Path
-
-from qface.generator import FileSystem, Generator
-from qface.helper.qtqml import Filters
-from qface.watch import monitor
-
-
-here = Path(__file__).dirname()
-
-logging.config.dictConfig(yaml.load(open(here / 'log.yaml')))
-
-log = logging.getLogger(__file__)
-
-
-def run(src, dst):
- log.debug('run {0} {1}'.format(src, dst))
- system = FileSystem.parse(src)
- generator = Generator(search_path=here / 'templates')
- generator.register_filter('defaultValue', Filters.defaultValue)
- generator.register_filter('propertyType', Filters.propertyType)
- ctx = {'dst': dst}
- for module in system.modules:
- module_name = module.module_name
- module_path = '/'.join(module.name_parts)
- plugin_name = "".join(module.name_parts[:2])
- ctx.update({
- 'module': module,
- 'module_name': module_name,
- 'module_path': module_path,
- 'plugin_name': plugin_name,
- })
- generator.destination = generator.apply("{{dst}}/{{module_path}}", ctx)
- generator.write('private/{{module_name}}Module.js', 'module.js', ctx)
- generator.write('qmldir', 'public_qmldir', ctx)
- generator.write('private/qmldir', 'private_qmldir', ctx)
-
- for interface in module.interfaces:
- ctx.update({
- 'interface': interface,
- })
- generator.write('private/Abstract{{interface}}.qml', 'AbstractInterface.qml', ctx)
- generator.write('{{interface}}.qml', 'Interface.qml', ctx, preserve=True)
-
-
-@click.command()
-@click.option('--reload/--no-reload', default=False)
-@click.argument('src', nargs=-1, type=click.Path(exists=True))
-@click.argument('dst', nargs=1, type=click.Path(exists=True))
-def app(src, dst, reload):
- """Takes several files or directories as src and generates the code
- in the given dst directory."""
- if reload:
- script = Path(__file__).abspath()
- monitor(script, src, dst)
- else:
- run(src, dst)
-
-
-if __name__ == '__main__':
- app()
diff --git a/qface/builtin/qtqml/templates/AbstractInterface.qml b/qface/builtin/qtqml/templates/AbstractInterface.qml
deleted file mode 100644
index b28d6b7..0000000
--- a/qface/builtin/qtqml/templates/AbstractInterface.qml
+++ /dev/null
@@ -1,27 +0,0 @@
-import QtQml 2.2
-import QtQml.Models 2.2
-
-import "."
-
-{{interface.comment}}
-QtObject {
- id: root
-{% for property in interface.properties %}
- {{property.comment}}
- {%+ if property.is_readonly %}readonly {% endif %}property {{property|propertyType}} {{property}} : {{property|defaultValue}}
-{% endfor %}
-{% for operation in interface.operations %}
- {{operation.comment}}
- property var {{operation}} : function({{operation.parameters|join(', ')}}) {}
-{% endfor %}
-
-{% for signal in interface.signals %}
- signal {{signal}}(
- {%- for parameter in signal.parameters %}
- {{- parameter.type|propertyType }} {{ parameter.name -}}
- {% if not loop.last %}, {% endif %}
- {% endfor -%}
- )
-{% endfor %}
-
-}
diff --git a/qface/builtin/qtqml/templates/Interface.qml b/qface/builtin/qtqml/templates/Interface.qml
deleted file mode 100644
index 2dc9d5f..0000000
--- a/qface/builtin/qtqml/templates/Interface.qml
+++ /dev/null
@@ -1,7 +0,0 @@
-import QtQml 2.2
-
-import "private"
-
-Abstract{{interface}} {
- id: root
-}
diff --git a/qface/builtin/qtqml/templates/Module.qml b/qface/builtin/qtqml/templates/Module.qml
deleted file mode 100644
index 7ededf2..0000000
--- a/qface/builtin/qtqml/templates/Module.qml
+++ /dev/null
@@ -1,24 +0,0 @@
-pragma Singleton
-
-import QtQml 2.2
-
-/**
- * {{module.comment}}
- */
-QtObject {
- id: root
-
- {% for enum in module.enums %}
- // Enum: {{enum}}
- {% for member in enum.members %}
- readonly property int {{member}}: {{member.value}}
- {% endfor %}
-
- {% endfor %}
-
- {% for struct in module.structs %}
- function create{{struct}}() {
- return {};
- }
- {% endfor %}
-}
diff --git a/qface/builtin/qtqml/templates/__init__.py b/qface/builtin/qtqml/templates/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/qface/builtin/qtqml/templates/__init__.py
+++ /dev/null
diff --git a/qface/builtin/qtqml/templates/module.js b/qface/builtin/qtqml/templates/module.js
deleted file mode 100644
index 551f5c3..0000000
--- a/qface/builtin/qtqml/templates/module.js
+++ /dev/null
@@ -1,18 +0,0 @@
-.pragma library
-
-{% for enum in module.enums %}
-// Enum: {{enum}}
-{% for member in enum.members %}
-var {{member}} = {{member.value}};
-{% endfor %}
-{% endfor %}
-
-{% for struct in module.structs %}
-function create{{struct}}() {
- return {
- {% for field in struct.fields %}
- {{field}} : {{field | defaultValue}},
- {% endfor %}
- };
-}
-{% endfor %}
diff --git a/qface/builtin/qtqml/templates/private_qmldir b/qface/builtin/qtqml/templates/private_qmldir
deleted file mode 100644
index 152af67..0000000
--- a/qface/builtin/qtqml/templates/private_qmldir
+++ /dev/null
@@ -1,4 +0,0 @@
-{{module_name}}Module 1.0 {{module_name}}Module.js
-{% for interface in module.interfaces %}
-Abstract{{interface}} 1.0 Abstract{{interface}}.qml
-{% endfor %}
diff --git a/qface/builtin/qtqml/templates/public_qmldir b/qface/builtin/qtqml/templates/public_qmldir
deleted file mode 100644
index fc465a7..0000000
--- a/qface/builtin/qtqml/templates/public_qmldir
+++ /dev/null
@@ -1,4 +0,0 @@
-{{module_name}}Module 1.0 private/{{module_name}}Module.js
-{% for interface in module.interfaces %}
-{{interface}} 1.0 {{interface}}.qml
-{% endfor %}
diff --git a/qface/builtin/__init__.py b/qface/contrib/__init__.py
index e69de29..e69de29 100644
--- a/qface/builtin/__init__.py
+++ b/qface/contrib/__init__.py
diff --git a/qface/contrib/logging.py b/qface/contrib/logging.py
new file mode 100644
index 0000000..6b7625c
--- /dev/null
+++ b/qface/contrib/logging.py
@@ -0,0 +1,28 @@
+import yaml
+import logging
+import logging.config
+import coloredlogs
+from path import Path
+import os
+
+
+def basic_log(level):
+ logging.basicConfig(level=level)
+ coloredlogs.install(level=level)
+ print('Fall back to basic logging')
+
+
+def setup_log(path='logging.yaml', level=logging.INFO, env_key='QFACE_LOG_CFG'):
+ path = Path(os.getenv(env_key, path))
+ if path.exists():
+ try:
+ config = yaml.safe_load(path.text())
+ logging.config.dictConfig(config)
+ coloredlogs.install()
+ except Exception as e:
+ print(e)
+ print('Error in logging configuration. Fall back to defaults.')
+ basic_log(level)
+ else:
+ basic_log(level)
+ print('Failed to load logging config file.')
diff --git a/qface/filters.py b/qface/filters.py
new file mode 100644
index 0000000..de424a4
--- /dev/null
+++ b/qface/filters.py
@@ -0,0 +1,46 @@
+import json
+import hashlib
+
+
+def jsonify(symbol):
+ """ returns json format for symbol """
+ try:
+ # all symbols have a toJson method, try it
+ return json.dumps(symbol.toJson(), indent=' ')
+ except AttributeError:
+ pass
+ return json.dumps(symbol, indent=' ')
+
+
+def upper_first(s):
+ """ uppercase first letter """
+ s = str(s)
+ return s[0].upper() + s[1:]
+
+
+def lower_first(s):
+ s = str(s)
+ return s[0].lower() + s[1:]
+
+
+def hash(symbol, hash_type='sha1'):
+ """ create a hash code from symbol """
+ code = hashlib.new(hash_type)
+ code.update(str(symbol).encode('utf-8'))
+ return code.hexdigest()
+
+
+def path(symbol):
+ """ replaces '.' with '/' """
+ return str(symbol).replace('.', '/')
+
+
+filters = {
+ 'jsonify': jsonify,
+ 'upper_first': upper_first,
+ 'lower_first': lower_first,
+ 'upperfirst': upper_first,
+ 'lowerfirst': lower_first,
+ 'hash': hash,
+ 'path': path,
+}
diff --git a/qface/generator.py b/qface/generator.py
index db1235c..eb7b24a 100644
--- a/qface/generator.py
+++ b/qface/generator.py
@@ -1,14 +1,18 @@
+
# Copyright (c) Pelagicore AB 2016
-from jinja2 import Environment, FileSystemLoader, Template
+from jinja2 import Environment, Template, Undefined, StrictUndefined
+from jinja2 import FileSystemLoader, PackageLoader, ChoiceLoader
+from jinja2 import TemplateSyntaxError, TemplateNotFound, TemplateError
from path import Path
from antlr4 import FileStream, CommonTokenStream, ParseTreeWalker
-from antlr4.error import DiagnosticErrorListener
+from antlr4.error import DiagnosticErrorListener, ErrorListener
import shelve
import logging
import hashlib
import yaml
import click
+import sys, os
from .idl.parser.TLexer import TLexer
from .idl.parser.TParser import TParser
@@ -16,7 +20,9 @@ from .idl.parser.TListener import TListener
from .idl.domain import System
from .idl.listener import DomainListener
from .utils import merge
+from .filters import filters
+from jinja2.debug import make_traceback as _make_traceback
try:
from yaml import CLoader as Loader, CDumper as Dumper
@@ -26,28 +32,61 @@ except ImportError:
logger = logging.getLogger(__name__)
-"""
-Provides an API for accessing the file system and controlling the generator
-"""
+def template_error_handler(traceback):
+ exc_type, exc_obj, exc_tb = traceback.exc_info
+ error = exc_obj
+ if isinstance(exc_type, TemplateError):
+ error = exc_obj.message
+ message = '{0}:{1}: error: {2}'.format(exc_tb.tb_frame.f_code.co_filename, exc_tb.tb_lineno, error)
+ click.secho(message, fg='red', err=True)
+
+
+class TestableUndefined(StrictUndefined):
+ """Return an error for all undefined values, but allow testing them in if statements"""
+ def __bool__(self):
+ return False
+
+
+class ReportingErrorListener(ErrorListener.ErrorListener):
+ """ Provides an API for accessing the file system and controlling the generator """
+ def __init__(self, document):
+ self.document = document
+ def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
+ msg = '{0}:{1}:{2} {2}'.format(self.document, line, column, msg)
+ click.secho(msg, fg='red')
+ raise ValueError(msg)
-def upper_first_filter(s):
- s = str(s)
- return s[0].upper() + s[1:]
+ def reportAmbiguity(self, recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs):
+ click.secho('ambiguity', fg='red')
+
+ def reportAttemptingFullContext(self, recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs):
+ click.secho('reportAttemptingFullContext', fg='red')
+
+ def reportContextSensitivity(self, recognizer, dfa, startIndex, stopIndex, prediction, configs):
+ click.secho('reportContextSensitivity', fg='red')
class Generator(object):
"""Manages the templates and applies your context data"""
- def __init__(self, search_path: str):
- if search_path:
- search_path = Path(search_path).expand()
- self.env = Environment(
- loader=FileSystemLoader(search_path),
- trim_blocks=True,
- lstrip_blocks=True
- )
- self.env.filters['upperfirst'] = upper_first_filter
+ strict = False
+ """ enables strict code generation """
+
+ def __init__(self, search_path, context={}):
+ loader = ChoiceLoader([
+ FileSystemLoader(search_path),
+ PackageLoader('qface')
+ ])
+ self.env = Environment(
+ loader=loader,
+ trim_blocks=True,
+ lstrip_blocks=True,
+ )
+ self.env.exception_handler = template_error_handler
+ self.env.filters.update(filters)
self._destination = Path()
+ self._source = ''
+ self.context = context
@property
def destination(self):
@@ -55,37 +94,86 @@ class Generator(object):
return self._destination
@destination.setter
- def destination(self, dst: str):
- self._destination = Path(dst)
+ def destination(self, dst):
+ if dst:
+ self._destination = Path(self.apply(dst, self.context))
+
+ @property
+ def source(self):
+ """source prefix for template lookup"""
+ return self._source
- def get_template(self, name: str):
+ @source.setter
+ def source(self, source):
+ if source:
+ self._source = source
+
+ @property
+ def filters(self):
+ return self.env.filters
+
+ @filters.setter
+ def filters(self, filters):
+ self.env.filters.update(filters)
+
+ def get_template(self, name):
"""Retrieves a single template file from the template loader"""
- return self.env.get_template(name)
+ source = name
+ if name and name[0] is '/':
+ source = name[1:]
+ elif self.source is not None:
+ source = '/'.join((self.source, name))
+ return self.env.get_template(source)
- def render(self, name: str, context: dict):
+ def render(self, name, context):
"""Returns the rendered text from a single template file from the
template loader using the given context data"""
+ if Generator.strict:
+ self.env.undefined = TestableUndefined
+ else:
+ self.env.undefined = Undefined
template = self.get_template(name)
return template.render(context)
- def apply(self, template: str, context: dict):
+ def apply(self, template, context):
"""Return the rendered text of a template instance"""
return self.env.from_string(template).render(context)
- def write(self, file_path: str, template: str, context: dict, preserve=False):
+ def write(self, file_path, template, context={}, preserve=False, force=False):
"""Using a template file name it renders a template
into a file given a context
"""
+ if not context:
+ context = self.context
+ error = False
+ try:
+ self._write(file_path, template, context, preserve, force)
+ except TemplateSyntaxError as exc:
+ message = '{0}:{1}: error: {2}'.format(exc.filename, exc.lineno, exc.message)
+ click.secho(message, fg='red', err=True)
+ error = True
+ except TemplateNotFound as exc:
+ message = '{0}: error: Template not found'.format(exc.name)
+ click.secho(message, fg='red', err=True)
+ error = True
+ except TemplateError as exc:
+ # Just return with an error, the generic template_error_handler takes care of printing it
+ error = True
+
+ if error and Generator.strict:
+ sys.exit(1)
+
+ def _write(self, file_path: Path, template: str, context: dict, preserve: bool = False, force: bool = False):
path = self.destination / Path(self.apply(file_path, context))
path.parent.makedirs_p()
logger.info('write {0}'.format(path))
data = self.render(template, context)
- if self._has_different_content(data, path):
+ if self._has_different_content(data, path) or force:
if path.exists() and preserve:
- click.secho('preserve changed file: {0}'.format(path), fg='blue')
+ click.secho('preserve: {0}'.format(path), fg='blue')
else:
- click.secho('write changed file: {0}'.format(path), fg='blue')
- path.open('w').write(data)
+ click.secho('create: {0}'.format(path), fg='blue')
+ path.open('w', encoding='utf-8').write(data)
def _has_different_content(self, data, path):
if not path.exists():
@@ -99,11 +187,90 @@ class Generator(object):
self.env.filters[name] = callback
+class RuleGenerator(Generator):
+ """Generates documents based on a rule YAML document"""
+ def __init__(self, search_path: str, destination:Path, context:dict={}, features:set=set()):
+ super().__init__(search_path, context)
+ self.context.update({
+ 'dst': destination,
+ 'project': Path(destination).name,
+ 'features': features,
+ })
+ self.destination = '{{dst}}'
+ self.features = features
+
+ def process_rules(self, path: Path, system: System):
+ """writes the templates read from the rules document"""
+ self.context.update({
+ 'system': system,
+ })
+ document = FileSystem.load_yaml(path, required=True)
+ for module, rules in document.items():
+ click.secho('process: {0}'.format(module), fg='green')
+ self._process_rules(rules, system)
+
+ def _process_rules(self, rules: dict, system: System):
+ """ process a set of rules for a target """
+ self._source = None # reset the template source
+ if not self._shall_proceed(rules):
+ return
+ self.context.update(rules.get('context', {}))
+ self.destination = rules.get('destination', '{{dst}}')
+ self.source = rules.get('source', None)
+ self._process_rule(rules.get('system', None), {'system': system})
+ for module in system.modules:
+ self._process_rule(rules.get('module', None), {'module': module})
+ for interface in module.interfaces:
+ self._process_rule(rules.get('interface', None), {'interface': interface})
+ for struct in module.structs:
+ self._process_rule(rules.get('struct', None), {'struct': struct})
+ for enum in module.enums:
+ self._process_rule(rules.get('enum', None), {'enum': enum})
+
+ def _process_rule(self, rule: dict, context: dict):
+ """ process a single rule """
+ if not rule or not self._shall_proceed(rule):
+ return
+ self.context.update(context)
+ self.context.update(rule.get('context', {}))
+ self.destination = rule.get('destination', None)
+ self.source = rule.get('source', None)
+ for target, source in rule.get('documents', {}).items():
+ self.write(target, source)
+ for target, source in rule.get('preserve', {}).items():
+ self.write(target, source, preserve=True)
+
+ def _shall_proceed(self, obj):
+ conditions = obj.get('when', [])
+ if not conditions:
+ return True
+ if not isinstance(conditions, list):
+ conditions = [conditions]
+ result = self.features.intersection(set(conditions))
+ return bool(len(result))
+
+
class FileSystem(object):
"""QFace helper functions to work with the file system"""
+ strict = False
+ """ enables strict parsing """
@staticmethod
def parse_document(document: Path, system: System = None):
+ error = False
+ try:
+ return FileSystem._parse_document(document, system)
+ except FileNotFoundError as e:
+ click.secho('{0}: error: file not found'.format(document), fg='red', err=True)
+ error = True
+ except ValueError as e:
+ click.secho('Error parsing document {0}'.format(document), fg='red', err=True)
+ error = True
+ if error and FileSystem.strict:
+ sys.exit(-1)
+
+ @staticmethod
+ def _parse_document(document: Path, system: System = None):
"""Parses a document and returns the resulting domain system
:param path: document path to parse
@@ -111,19 +278,19 @@ class FileSystem(object):
"""
logger.debug('parse document: {0}'.format(document))
stream = FileStream(str(document), encoding='utf-8')
- system = FileSystem._parse_stream(stream, system)
+ system = FileSystem._parse_stream(stream, system, document)
FileSystem.merge_annotations(system, document.stripext() + '.yaml')
return system
@staticmethod
- def _parse_stream(stream, system: System = None):
+ def _parse_stream(stream, system: System = None, document=None):
logger.debug('parse stream')
system = system or System()
lexer = TLexer(stream)
stream = CommonTokenStream(lexer)
parser = TParser(stream)
- parser.addErrorListener(DiagnosticErrorListener.DiagnosticErrorListener())
+ parser.addErrorListener(ReportingErrorListener(document))
tree = parser.documentSymbol()
walker = ParseTreeWalker()
walker.walk(DomainListener(system), tree)
@@ -134,14 +301,10 @@ class FileSystem(object):
"""Read a YAML document and for each root symbol identifier
updates the tag information of that symbol
"""
- if not document.exists():
+ if not Path(document).exists():
return
- meta = {}
- try:
- meta = yaml.load(document.text(), Loader=Loader)
- except yaml.YAMLError as exc:
- click.secho(exc, fg='red')
- click.secho('merge tags from {0}'.format(document), fg='blue')
+ meta = FileSystem.load_yaml(document)
+ click.secho('merge: {0}'.format(document.name), fg='blue')
for identifier, data in meta.items():
symbol = system.lookup(identifier)
if symbol:
@@ -181,3 +344,19 @@ class FileSystem(object):
if use_cache:
cache[identifier] = system
return system
+
+ @staticmethod
+ def load_yaml(document: Path, required=False):
+ document = Path(document)
+ if not document.exists():
+ if required:
+ click.secho('yaml document does not exists: {0}'.format(document), fg='red', err=True)
+ return {}
+ try:
+ return yaml.load(document.text(), Loader=Loader)
+ except yaml.YAMLError as exc:
+ error = document
+ if hasattr(exc, 'problem_mark'):
+ error = '{0}:{1}'.format(error, exc.problem_mark.line+1)
+ click.secho('{0}: error: {1}'.format(error, str(exc)), fg='red', err=True)
+ return {}
diff --git a/qface/helper/doc.py b/qface/helper/doc.py
index c999227..2b1df51 100644
--- a/qface/helper/doc.py
+++ b/qface/helper/doc.py
@@ -1,9 +1,8 @@
import re
-
translate = None
"""
-The translare function used for transalting inline tags. The
+The translate function used for translating inline tags. The
function will be called with tag, value arguments.
Example:
@@ -22,7 +21,7 @@ class DocObject:
The documentation object passed into the template engine
"""
def __init__(self):
- self.brief = str()
+ self.brief = []
self.description = []
self.see = []
self.deprecated = False
@@ -37,6 +36,8 @@ class DocObject:
setattr(self, name, str(value))
elif attr_type is list:
getattr(self, name).append(value)
+ else:
+ print('documentation tag @{0} not supported'.format(name))
@staticmethod
def _translate(name, value):
@@ -55,6 +56,8 @@ class DocObject:
def parse_doc(s):
+ """ parse a comment in the format of JavaDoc and returns an object, where each JavaDoc tag
+ is a property of the object. """
if not s:
return
doc = DocObject()
@@ -77,5 +80,6 @@ def parse_doc(s):
doc.add_tag(tag, value)
elif tag: # append to previous matched tag
doc.add_tag(tag, line)
+ else: # append any loose lines to description
+ doc.add_tag('description', line)
return doc
-
diff --git a/qface/helper/qtcpp.py b/qface/helper/qtcpp.py
index 7e8f3ca..2c64e74 100644
--- a/qface/helper/qtcpp.py
+++ b/qface/helper/qtcpp.py
@@ -1,16 +1,14 @@
"""
Provides helper functionality specificially for Qt C++/QML code generators
"""
-
-
-def upper_first(s):
- s = str(s)
- return s[0].upper() + s[1:]
+import qface.idl.domain as domain
+from jinja2 import environmentfilter
+from ..filters import upper_first
class Filters(object):
"""provides a set of filters to be used with the template engine"""
- classPrefix = 'Qml'
+ classPrefix = ''
@staticmethod
def className(symbol):
@@ -20,105 +18,236 @@ class Filters(object):
@staticmethod
def defaultValue(symbol):
prefix = Filters.classPrefix
- t = symbol.type # type: qface.domain.TypeSymbol
+ t = symbol.type
if t.is_primitive:
if t.is_int:
- return '0'
+ return 'int(0)'
if t.is_bool:
- return 'false'
+ return 'bool(false)'
if t.is_string:
return 'QString()'
if t.is_real:
- return '0.0'
- if t.is_variant:
+ return 'qreal(0.0)'
+ if t.is_var:
return 'QVariant()'
elif t.is_void:
return ''
elif t.is_enum:
- module_name = t.reference.module.module_name
value = next(iter(t.reference.members))
- return '{0}{1}Module::{2}'.format(prefix, module_name, value)
- elif symbol.type.is_list:
- nested = Filters.returnType(symbol.type.nested)
+ return '{0}::{0}Enum::{1}'.format(symbol.type, value)
+ elif symbol.kind == 'enum':
+ value = next(iter(symbol.members))
+ return '{0}::{1}'.format(symbol, value)
+ elif t.is_flag:
+ return '0'
+ elif t.is_list:
+ nested = Filters.returnType(t.nested)
return 'QVariantList()'.format(nested)
- elif symbol.type.is_struct:
- return '{0}{1}()'.format(prefix, symbol.type)
- elif symbol.type.is_model:
- nested = symbol.type.nested
- if nested.is_primitive:
- return 'new {0}VariantModel(this)'.format(prefix)
- elif nested.is_complex:
- return 'new {0}{1}Model(this)'.format(prefix, nested)
- return 'XXX'
+ elif t.is_struct:
+ return '{0}{1}()'.format(prefix, t)
+ elif t.is_model:
+ return 'new VariantModel(this)'
+ elif t.is_interface:
+ return 'nullptr'
+ raise Exception("Unknown symbol type" + repr(symbol))
@staticmethod
def parameterType(symbol):
prefix = Filters.classPrefix
- module_name = symbol.module.module_name
if symbol.type.is_enum:
- return '{0}{1}Module::{2} {3}'.format(prefix, module_name, symbol.type, symbol)
+ return '{0}::{0}Enum {1}'.format(symbol.type, symbol)
if symbol.type.is_void or symbol.type.is_primitive:
- if symbol.type.name == 'string':
+ if symbol.type.is_string:
return 'const QString &{0}'.format(symbol)
- if symbol.type.name == 'var':
+ if symbol.type.is_var:
return 'const QVariant &{0}'.format(symbol)
- if symbol.type.name == 'real':
+ if symbol.type.is_real:
return 'qreal {0}'.format(symbol)
+ if symbol.type.is_bool:
+ return 'bool {0}'.format(symbol)
+ if symbol.type.is_int:
+ return 'int {0}'.format(symbol)
return '{0} {1}'.format(symbol.type, symbol)
elif symbol.type.is_list:
nested = Filters.returnType(symbol.type.nested)
return 'const QVariantList &{1}'.format(nested, symbol)
elif symbol.type.is_model:
- nested = symbol.type.nested
- if nested.is_primitive:
- return '{0}VariantModel *{1}'.format(prefix, symbol)
- elif nested.is_complex:
- return '{0}{1}Model *{2}'.format(prefix, nested, symbol)
- else:
- return 'const {0}{1} &{2}'.format(prefix, symbol.type, symbol)
- return 'XXX'
+ return 'VariantModel *{0}'.format(symbol)
+ elif symbol.type.is_complex:
+ if symbol.type.is_interface:
+ return '{0}Base *{1}'.format(symbol.type, symbol)
+ else:
+ return 'const {0}{1} &{2}'.format(prefix, symbol.type, symbol)
+ raise Exception("Unknown symbol type")
@staticmethod
def returnType(symbol):
prefix = Filters.classPrefix
- module_name = symbol.module.module_name
- if symbol.type.is_enum:
- return '{0}{1}Module::{2}'.format(prefix, module_name, symbol.type)
+ t = symbol.type
+ if t.is_enum:
+ return '{0}::{0}Enum'.format(symbol.type)
if symbol.type.is_void or symbol.type.is_primitive:
- if symbol.type.name == 'string':
+ if t.is_string:
return 'QString'
- if symbol.type.name == 'var':
+ if t.is_var:
return 'QVariant'
- if symbol.type.name == 'real':
+ if t.is_real:
return 'qreal'
- return symbol.type.name
+ if t.is_int:
+ return 'int'
+ if t.is_bool:
+ return 'bool'
+ if t.is_void:
+ return 'void'
+ print(t)
+ assert False
elif symbol.type.is_list:
nested = Filters.returnType(symbol.type.nested)
return 'QVariantList'.format(nested)
elif symbol.type.is_model:
- nested = symbol.type.nested
- if nested.is_primitive:
- return '{0}VariantModel *'.format(prefix)
- elif nested.is_complex:
- return '{0}{1}Model *'.format(prefix, nested)
- else:
- return '{0}{1}'.format(prefix, symbol.type)
- return 'XXX'
+ return 'VariantModel *'
+ elif symbol.type.is_complex:
+ if symbol.type.is_interface:
+ return '{0}Base *'.format(symbol.type)
+ else:
+ return '{0}{1}'.format(prefix, symbol.type)
+ raise Exception("Unknown symbol type")
+
+ @staticmethod
+ def header_dependencies(symbol):
+ types = symbol.dependencies
+ lines = []
+ for t in types:
+ if t.is_primitive:
+ continue
+ if t.is_model:
+ lines.append('class VariantModel;')
+ if t.is_interface:
+ lines.append('class {0};'.format(t))
+ if t.is_struct:
+ lines.append('#include "{0}.h"'.format(t))
+ return "\n".join(lines)
+
+ @staticmethod
+ def source_dependencies(symbol):
+ types = symbol.dependencies
+ lines = []
+ module_name = symbol.module.module_name
+ if not symbol.kind == 'module':
+ lines.append('#include "{0}module.h"'.format(module_name.lower()))
+ for t in types:
+ if t.is_primitive:
+ continue
+ if t.is_model:
+ lines.append('#include "variantmodel.h"')
+ if t.is_interface:
+ lines.append('#include "{0}.h"'.format(t.name.lower()))
+ return "\n".join(lines)
@staticmethod
def open_ns(symbol):
''' generates a open namespace from symbol namespace x { y { z {'''
- blocks = ['{0} {{'.format(x) for x in symbol.module.name_parts]
- return 'namespace {0}'.format(str.join(' ', blocks))
+ blocks = ['namespace {0} {{'.format(x) for x in symbol.module.name_parts]
+ return ' '.join(blocks)
@staticmethod
def close_ns(symbol):
'''generates a closing names statement from a symbol'''
- return ' '.join(['}' for x in symbol.module.name_parts])
+ closing = ' '.join(['}' for x in symbol.module.name_parts])
+ name = '::'.join(symbol.module.name_parts)
+ return '{0} // namespace {1}'.format(closing, name)
@staticmethod
def using_ns(symbol):
'''generates a using namespace x::y::z statement from a symbol'''
id = '::'.join(symbol.module.name_parts)
- return 'using namespace {0}'.format(id)
+ return 'using namespace {0};'.format(id)
+
+ @staticmethod
+ def ns(symbol):
+ '''generates a namespace x::y::z statement from a symbol'''
+ if symbol.type and symbol.type.is_primitive:
+ return ''
+ return '{0}::'.format('::'.join(symbol.module.name_parts))
+
+ @staticmethod
+ def fqn(symbol):
+ '''generates a fully qualified name from symbol'''
+ return '{0}::{1}'.format(Filters.ns(symbol), symbol.name)
+
+ @staticmethod
+ def signalName(s):
+ if isinstance(s, domain.Property):
+ return '{0}Changed'.format(s)
+ return s
+
+ @staticmethod
+ @environmentfilter
+ def parameters(env, s, filter=None, spaces=True):
+ if not filter:
+ filter = Filters.parameterType
+ elif isinstance(filter, str):
+ filter = env.filters[filter]
+ args = []
+ indent = ', '
+ if not spaces:
+ indent = ','
+ if isinstance(s, domain.Operation):
+ args = s.parameters
+ elif isinstance(s, domain.Signal):
+ args = s.parameters
+ elif isinstance(s, domain.Struct):
+ args = s.fields
+ elif isinstance(s, domain.Property):
+ args = [s]
+ return indent.join([filter(a) for a in args])
+ @staticmethod
+ @environmentfilter
+ def signature(env, s, expand=False, filter=None):
+ if not filter:
+ filter = Filters.returnType
+ elif isinstance(filter, str):
+ filter = env.filters[filter]
+ if isinstance(s, domain.Operation):
+ args = s.parameters
+ elif isinstance(s, domain.Signal):
+ args = s.parameters
+ elif isinstance(s, domain.Property):
+ args = [s] # for <property>Changed(<type>)
+ elif isinstance(s, domain.Struct):
+ args = s.fields
+ else:
+ args = []
+ if expand:
+ return ', '.join(['{0} {1}'.format(filter(a), a.name) for a in args])
+ return ','.join([filter(a) for a in args])
+
+ @staticmethod
+ def identifier(s):
+ return str(s).lower().replace('.', '_')
+
+ @staticmethod
+ def path(s):
+ return str(s).replace('.', '/')
+
+ @staticmethod
+ def get_filters():
+ return {
+ 'defaultValue': Filters.defaultValue,
+ 'returnType': Filters.returnType,
+ 'parameterType': Filters.parameterType,
+ 'open_ns': Filters.open_ns,
+ 'close_ns': Filters.close_ns,
+ 'using_ns': Filters.using_ns,
+ 'ns': Filters.ns,
+ 'fqn': Filters.fqn,
+ 'signalName': Filters.signalName,
+ 'parameters': Filters.parameters,
+ 'signature': Filters.signature,
+ 'identifier': Filters.identifier,
+ 'path': Filters.path,
+ 'className': Filters.className,
+ 'source_dependencies': Filters.source_dependencies,
+ 'header_dependencies': Filters.header_dependencies,
+ }
diff --git a/qface/helper/qtqml.py b/qface/helper/qtqml.py
index 819000a..e29311f 100644
--- a/qface/helper/qtqml.py
+++ b/qface/helper/qtqml.py
@@ -3,6 +3,11 @@ Provides helper functionality specificially for Qt5 QML code generators
"""
+def upper_first(s):
+ s = str(s)
+ return s[0].upper() + s[1:]
+
+
class Filters(object):
"""provides a set of filters to be used with the template engine"""
classPrefix = ''
@@ -14,15 +19,19 @@ class Filters(object):
@staticmethod
def defaultValue(symbol):
- module = symbol.module.module_name
+ module = upper_first(symbol.module.module_name)
t = symbol.type
if t.is_primitive:
if t.name == 'int':
return '0'
+ elif t.name == 'real':
+ return "0.0"
elif t.name == 'bool':
return 'false'
elif t.name == 'string':
return "''"
+ elif t.name == 'var':
+ return "undefined"
elif t.is_enum:
value = next(iter(t.reference.members))
return '{0}Module.{1}'.format(module, value)
@@ -50,3 +59,11 @@ class Filters(object):
return 'ListModel'
return t
+ @staticmethod
+ def path(s):
+ return str(s).replace('.', '/')
+
+ @staticmethod
+ def identifier(s):
+ return str(s).lower().replace('.', '_')
+
diff --git a/qface/idl/domain.py b/qface/idl/domain.py
index c774c16..fc0ec2c 100644
--- a/qface/idl/domain.py
+++ b/qface/idl/domain.py
@@ -78,6 +78,11 @@ class System(object):
type_name = parts[1]
return (module_name, type_name, fragment_name)
+ def toJson(self):
+ o = OrderedDict()
+ o['modules'] = [o.toJson() for o in self.modules]
+ return o
+
class NamedElement(object):
def __init__(self, name, module: 'Module'):
@@ -97,12 +102,18 @@ class NamedElement(object):
@property
def qualified_name(self):
- '''return the fully qualified name (`module + "." + name`)'''
+ '''return the fully qualified name (`<module>.<name>`)'''
if self.module == self:
return self.module.name
else:
return '{0}.{1}'.format(self.module.name, self.name)
+ def toJson(self):
+ o = OrderedDict()
+ if self.name:
+ o['name'] = self.name
+ return o
+
class Symbol(NamedElement):
"""A symbol represents a base class for names elements"""
@@ -113,7 +124,10 @@ class Symbol(NamedElement):
self._tags = dict()
self._contentMap = ChainMap()
+ self._dependencies = set()
self.type = TypeSymbol('', self)
+ self.kind = self.__class__.__name__.lower()
+ """ the associated type information """
@property
def system(self):
@@ -125,25 +139,41 @@ class Symbol(NamedElement):
return self._tags
def add_tag(self, tag):
+ """ add a tag to the tag list """
if tag not in self._tags:
self._tags[tag] = dict()
def add_attribute(self, tag, name, value):
+ """ add an attribute (nam, value pair) to the named tag """
self.add_tag(tag)
d = self._tags[tag]
d[name] = value
def tag(self, name):
+ """ return tag by name """
return self._tags[name]
def attribute(self, tag, name):
+ """ return attribute by tag and attribute name """
if tag in self._tags and name in self._tags[tag]:
return self._tags[tag][name]
@property
def contents(self):
+ """ return general list of symbol contents """
return self._contentMap.values()
+ @property
+ def dependencies(self):
+ if not self._dependencies:
+ self._dependencies = [x.type for x in self.contents]
+ return self._dependencies
+
+ def toJson(self):
+ o = super().toJson()
+ if self.type.is_valid:
+ o['type'] = self.type.toJson()
+ return o
class TypeSymbol(NamedElement):
@@ -152,11 +182,17 @@ class TypeSymbol(NamedElement):
super().__init__(name, parent.module)
log.debug('TypeSymbol()')
self.parent = parent
+ """ the parent symbol of this type """
self.is_void = False # type:bool
+ """ if type represents the void type """
self.is_primitive = False # type:bool
+ """ if type represents a primitive type """
self.is_complex = False # type:bool
+ """ if type represents a complex type """
self.is_list = False # type:bool
+ """ if type represents a list of nested types """
self.is_model = False # type:bool
+ """ if type represents a model of nested types """
self.nested = None
"""nested type if symbol is list or model"""
self.__reference = None
@@ -165,7 +201,10 @@ class TypeSymbol(NamedElement):
@property
def is_valid(self):
'''checks if type is a valid type'''
- return self.is_primitive or self.is_complex
+ return (self.is_primitive and self.name) \
+ or (self.is_complex and self.name) \
+ or (self.is_list and self.nested) \
+ or (self.is_model and self.nested)
@property
def is_bool(self):
@@ -188,19 +227,34 @@ class TypeSymbol(NamedElement):
return self.is_primitive and self.name == 'string'
@property
- def is_enum(self):
- '''checks if type is complex and enum'''
+ def is_var(self):
+ '''checks if type is primitive and var'''
+ return self.is_primitive and self.name == 'var'
+
+ @property
+ def is_enumeration(self):
+ '''checks if type is complex and instance of type Enum'''
return self.is_complex and isinstance(self.reference, Enum)
@property
+ def is_enum(self):
+ '''checks if type is an enumeration and reference is enum'''
+ return self.is_enumeration and self.reference.is_enum
+
+ @property
+ def is_flag(self):
+ '''checks if type is an enumeration and reference is flag '''
+ return self.is_enumeration and self.reference.is_flag
+
+ @property
def is_struct(self):
'''checks if type is complex and struct'''
return self.is_complex and isinstance(self.reference, Struct)
@property
- def is_variant(self):
- '''checks if type is primitive and string'''
- return self.is_primitive and self.name == 'var'
+ def is_interface(self):
+ '''checks if type is interface'''
+ return self.is_complex and isinstance(self.reference, Interface)
@property
def reference(self):
@@ -218,8 +272,25 @@ class TypeSymbol(NamedElement):
@property
def type(self):
+ """ return the type information. In this case: self """
return self
+ def toJson(self):
+ o = super().toJson()
+ if self.is_void:
+ o['void'] = self.is_void
+ if self.is_primitive:
+ o['primitive'] = self.is_primitive
+ if self.is_complex:
+ o['complex'] = self.is_complex
+ if self.is_list:
+ o['list'] = self.is_list
+ if self.is_model:
+ o['model'] = self.is_model
+ if self.nested:
+ o['nested'] = self.nested.toJson()
+ return o
+
class Module(Symbol):
"""Module is a namespace for types, e.g. interfaces, enums, structs"""
@@ -270,8 +341,19 @@ class Module(Symbol):
return self.name.split('.')
@property
+ def majorVersion(self):
+ """ returns the major version number of the version information """
+ return self.version.split('.')[0]
+
+ @property
+ def minorVersion(self):
+ """ returns the minor version number of the version information """
+ return self.version.split('.')[1]
+
+ @property
def module_name(self):
- return self.name.split('.')[-1].capitalize()
+ """ returns the last part of the module uri """
+ return self.name.split('.')[-1]
def lookup(self, name: str, fragment: str = None):
'''lookup a symbol by name. If symbol is not local
@@ -283,6 +365,14 @@ class Module(Symbol):
return symbol
return self.system.lookup(name)
+ def toJson(self):
+ o = super().toJson()
+ o['version'] = self.version
+ o['interfaces'] = [s.toJson() for s in self.interfaces]
+ o['structs'] = [s.toJson() for s in self.structs]
+ o['enums'] = [s.toJson() for s in self.enums]
+ return o
+
class Interface(Symbol):
"""A interface is an object with operations, properties and signals"""
@@ -294,6 +384,7 @@ class Interface(Symbol):
self._operationMap = OrderedDict() # type: dict[str, Operation]
self._signalMap = OrderedDict() # type: dict[str, Signal]
self._contentMap = ChainMap(self._propertyMap, self._operationMap, self._signalMap)
+ self._extends = None
@property
def properties(self):
@@ -310,6 +401,18 @@ class Interface(Symbol):
'''returns ordered list of signals'''
return self._signalMap.values()
+ @property
+ def extends(self):
+ ''' returns the symbol defined by the extends interface attribute '''
+ return self.module.lookup(self._extends)
+
+ def toJson(self):
+ o = super().toJson()
+ o['properties'] = [s.toJson() for s in self.properties]
+ o['operations'] = [s.toJson() for s in self.operations]
+ o['signals'] = [s.toJson() for s in self.signals]
+ return o
+
class Operation(Symbol):
"""An operation inside a interface"""
@@ -317,14 +420,28 @@ class Operation(Symbol):
super().__init__(name, interface.module)
log.debug('Operation()')
self.interface = interface
+ """ the interface the operation is part of """
self.interface._operationMap[name] = self
self._parameterMap = self._contentMap = OrderedDict() # type: dict[Parameter]
+ self.is_const = False # type: bool
+ """reflects is the operation was declared as const operation"""
+
+ @property
+ def qualified_name(self):
+ '''return the fully qualified name (`<module>.<interface>#<operation>`)'''
+ return '{0}.{1}#{2}'.format(self.module.name, self.interface.name, self.name)
@property
def parameters(self):
'''returns ordered list of parameters'''
return self._parameterMap.values()
+ def toJson(self):
+ o = super().toJson()
+ o['parameters'] = [s.toJson() for s in self.parameters]
+ o['type'] = self.type.toJson()
+ return o
+
class Signal(Symbol):
"""A signal inside an interface"""
@@ -336,10 +453,20 @@ class Signal(Symbol):
self._parameterMap = self._contentMap = OrderedDict() # type: dict[Parameter]
@property
+ def qualified_name(self):
+ '''return the fully qualified name (`module + "." + name`)'''
+ return '{0}.{1}#{2}'.format(self.module.name, self.interface.name, self.name)
+
+ @property
def parameters(self):
'''returns ordered list of parameters'''
return self._parameterMap.values()
+ def toJson(self):
+ o = super().toJson()
+ o['parameters'] = [s.toJson() for s in self.parameters]
+ return o
+
class Parameter(Symbol):
"""An operation parameter"""
@@ -357,7 +484,40 @@ class Property(Symbol):
log.debug('Property()')
self.interface = interface
self.interface._propertyMap[name] = self
- self.is_readonly = False
+ self.readonly = False
+ self.const = False
+
+ @property
+ def is_model(self):
+ ''' true if type is a model '''
+ return self.type.is_model
+
+ @property
+ def is_primitive_model(self):
+ ''' true if type is a model of nested primitive types '''
+ return self.type.is_model and self.type.nested.is_primitive
+
+ @property
+ def is_complex_model(self):
+ ''' true if type is a model of nested complex types '''
+ return self.type.is_model and self.type.nested.is_complex
+
+ @property
+ def qualified_name(self):
+ '''return the fully qualified name (`<module>.<interface>#<property>`)'''
+ return '{0}.{1}#{2}'.format(self.module.name, self.interface.name, self.name)
+
+ @property
+ def writeable(self):
+ return not self.readonly and not self.const
+
+ def toJson(self):
+ o = super().toJson()
+ if self.readonly:
+ o['readonly'] = True
+ if self.const:
+ o['const'] = True
+ return o
class Struct(Symbol):
@@ -366,13 +526,18 @@ class Struct(Symbol):
super().__init__(name, module)
log.debug('Struct()')
self.module._structMap[name] = self
- self._fieldMap = self._contentMap = OrderedDict() # type: dict[str, Field]
+ self._fieldMap = self._contentMap = OrderedDict()
@property
def fields(self):
'''returns ordered list of members'''
return self._fieldMap.values()
+ def toJson(self):
+ o = super().toJson()
+ o['fields'] = [s.toJson() for s in self.fields]
+ return o
+
class Field(Symbol):
"""A member in a struct"""
@@ -382,6 +547,12 @@ class Field(Symbol):
self.struct = struct # type:Struct
self.struct._fieldMap[name] = self
+ @property
+ def qualified_name(self):
+ '''return the fully qualified name (`<module>.<struct>#<field>`)'''
+ return '{0}.{1}#{2}'.format(self.module.name, self.struct.name, self.name)
+
+
class Enum(Symbol):
"""An enum (flag) inside a module"""
@@ -398,6 +569,15 @@ class Enum(Symbol):
'''returns ordered list of members'''
return self._memberMap.values()
+ def toJson(self):
+ o = super().toJson()
+ if self.is_enum:
+ o['enum'] = self.is_enum
+ if self.is_flag:
+ o['flag'] = self.is_flag
+ o['members'] = [s.toJson() for s in self.members]
+ return o
+
class EnumMember(Symbol):
"""A enum value"""
@@ -407,3 +587,13 @@ class EnumMember(Symbol):
self.enum = enum
self.enum._memberMap[name] = self
self.value = 0
+
+ def qualified_name(self):
+ '''return the fully qualified name (`<module>.<enum>#<member>`)'''
+ return '{0}.{1}#{2}'.format(self.module.name, self.enum.name, self.name)
+
+ def toJson(self):
+ o = super().toJson()
+ o['value'] = self.value
+ return o
+
diff --git a/qface/idl/listener.py b/qface/idl/listener.py
index feeb8c9..4e9e720 100644
--- a/qface/idl/listener.py
+++ b/qface/idl/listener.py
@@ -1,6 +1,5 @@
# Copyright (c) Pelagicore AB 2016
import logging
-from _operator import concat
from .parser.TListener import TListener
from .parser.TParser import TParser
@@ -11,9 +10,9 @@ import click
from .profile import get_features, EProfile, EFeature
try:
- from yaml import CLoader as Loader, CDumper as Dumper
+ from yaml import CSafeLoader as Loader, CDumper as Dumper
except ImportError:
- from yaml import Loader, Dumper
+ from yaml import SafeLoader as Loader, Dumper
log = logging.getLogger(__name__)
@@ -99,7 +98,7 @@ class DomainListener(QFaceListener):
data = yaml.load('\n'.join(lines), Loader=Loader)
symbol._tags = data
except yaml.YAMLError as exc:
- click.secho(exc, fg='red')
+ click.secho(str(exc), fg='red')
def enterEveryRule(self, ctx):
log.debug('enter ' + ctx.__class__.__name__)
@@ -124,6 +123,8 @@ class DomainListener(QFaceListener):
name = ctx.name.text
self.interface = Interface(name, self.module)
self.parse_annotations(ctx, self.interface)
+ if ctx.extends:
+ self.interface._extends = ctx.extends.text
contextMap[ctx] = self.interface
def exitInterfaceSymbol(self, ctx: TParser.InterfaceSymbolContext):
@@ -165,6 +166,9 @@ class DomainListener(QFaceListener):
assert self.interface
name = ctx.name.text
self.operation = Operation(name, self.interface)
+ modifier = ctx.operationModifierSymbol()
+ if modifier:
+ self.operation.is_const = bool(modifier.is_const)
self.parse_annotations(ctx, self.operation)
self.parse_type(ctx, self.operation.type)
contextMap[ctx] = self.operation
@@ -195,7 +199,19 @@ class DomainListener(QFaceListener):
assert self.interface
name = ctx.name.text
self.property = Property(name, self.interface)
- self.property.is_readonly = bool(ctx.isReadOnly)
+ modifier = ctx.propertyModifierSymbol()
+
+ if modifier:
+ self.property.readonly = bool(modifier.is_readonly)
+ self.property.const = bool(modifier.is_const)
+
+ if ctx.value:
+ try:
+ value = yaml.load(ctx.value.text, Loader=Loader)
+ self.property._value = value
+ except yaml.YAMLError as exc:
+ click.secho(exc, fg='red')
+
self.parse_annotations(ctx, self.property)
self.parse_type(ctx, self.property.type)
contextMap[ctx] = self.property
@@ -207,6 +223,7 @@ class DomainListener(QFaceListener):
assert self.struct
name = ctx.name.text
self.field = Field(name, self.struct)
+ self.parse_annotations(ctx, self.field)
contextMap[ctx] = self.field
def exitStructFieldSymbol(self, ctx: TParser.StructFieldSymbolContext):
@@ -221,6 +238,7 @@ class DomainListener(QFaceListener):
if ctx.intSymbol():
value = int(ctx.intSymbol().value.text, 0)
self.field.value = value
+ self.parse_annotations(ctx, self.field)
contextMap[ctx] = self.field
if self.enum.is_flag:
self.enumCounter <<= 1
diff --git a/qface/idl/parser/T.g4 b/qface/idl/parser/T.g4
index 4ec68c8..9cfe4e7 100644
--- a/qface/idl/parser/T.g4
+++ b/qface/idl/parser/T.g4
@@ -29,7 +29,7 @@ definitionSymbol
;
interfaceSymbol
- : comment=DOCCOMMENT? tagSymbol* 'interface' name=IDENTIFIER '{' interfaceMemberSymbol* '}' ';'?
+ : comment=DOCCOMMENT? tagSymbol* 'interface' name=IDENTIFIER ('extends' extends=IDENTIFIER)? '{' interfaceMemberSymbol* '}' ';'?
;
interfaceMemberSymbol
@@ -39,7 +39,11 @@ interfaceMemberSymbol
;
operationSymbol
- : comment=DOCCOMMENT? tagSymbol* (typeSymbol | 'void') name=IDENTIFIER '(' operationParameterSymbol* ')' ';'?
+ : comment=DOCCOMMENT? tagSymbol* (typeSymbol | 'void') name=IDENTIFIER '(' operationParameterSymbol* ')' operationModifierSymbol? ';'?
+ ;
+
+operationModifierSymbol
+ : is_const='const'
;
signalSymbol
@@ -48,7 +52,12 @@ signalSymbol
propertySymbol
- : comment=DOCCOMMENT? tagSymbol* isReadOnly='readonly'? typeSymbol name=IDENTIFIER ';'?
+ : comment=DOCCOMMENT? tagSymbol* propertyModifierSymbol? typeSymbol name=IDENTIFIER ';'?
+ ;
+
+propertyModifierSymbol
+ : is_readonly='readonly'
+ | is_const='const'
;
operationParameterSymbol
diff --git a/qface/idl/parser/T.tokens b/qface/idl/parser/T.tokens
index 86bf74a..5f94603 100644
--- a/qface/idl/parser/T.tokens
+++ b/qface/idl/parser/T.tokens
@@ -23,38 +23,42 @@ T__21=22
T__22=23
T__23=24
T__24=25
-TAGLINE=26
-INTCONSTANT=27
-HEXCONSTANT=28
-TAGIDENTIFIER=29
-IDENTIFIER=30
-VERSION=31
-DOCCOMMENT=32
-WHITESPACE=33
-COMMENT=34
-MULTICOMM=35
+T__25=26
+T__26=27
+TAGLINE=28
+INTCONSTANT=29
+HEXCONSTANT=30
+TAGIDENTIFIER=31
+IDENTIFIER=32
+VERSION=33
+DOCCOMMENT=34
+WHITESPACE=35
+COMMENT=36
+MULTICOMM=37
'import'=1
';'=2
'module'=3
'interface'=4
-'{'=5
-'}'=6
-'void'=7
-'('=8
-')'=9
-'signal'=10
-'readonly'=11
-','=12
-'='=13
-'bool'=14
-'int'=15
-'real'=16
-'string'=17
-'var'=18
-'list'=19
-'<'=20
-'>'=21
-'model'=22
-'struct'=23
-'enum'=24
-'flag'=25
+'extends'=5
+'{'=6
+'}'=7
+'void'=8
+'('=9
+')'=10
+'const'=11
+'signal'=12
+'readonly'=13
+','=14
+'='=15
+'bool'=16
+'int'=17
+'real'=18
+'string'=19
+'var'=20
+'list'=21
+'<'=22
+'>'=23
+'model'=24
+'struct'=25
+'enum'=26
+'flag'=27
diff --git a/qface/idl/parser/TLexer.py b/qface/idl/parser/TLexer.py
index 59f1fcb..cb108c4 100644
--- a/qface/idl/parser/TLexer.py
+++ b/qface/idl/parser/TLexer.py
@@ -1,124 +1,133 @@
-# Generated from T.g4 by ANTLR 4.6
+# Generated from T.g4 by ANTLR 4.7
from antlr4 import *
from io import StringIO
+from typing.io import TextIO
+import sys
def serializedATN():
with StringIO() as buf:
- buf.write("\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2%")
- buf.write("\u0114\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7")
+ buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2\'")
+ buf.write("\u0126\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7")
buf.write("\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r")
buf.write("\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23")
buf.write("\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30")
buf.write("\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36")
- buf.write("\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\3\2\3")
- buf.write("\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\4\3\4\3\4\3\4")
- buf.write("\3\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3")
- buf.write("\7\3\7\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\n\3\n\3\13\3\13\3")
- buf.write("\13\3\13\3\13\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3")
- buf.write("\f\3\f\3\r\3\r\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20")
- buf.write("\3\20\3\20\3\20\3\21\3\21\3\21\3\21\3\21\3\22\3\22\3\22")
- buf.write("\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\24\3\24\3\24")
- buf.write("\3\24\3\24\3\25\3\25\3\26\3\26\3\27\3\27\3\27\3\27\3\27")
- buf.write("\3\27\3\30\3\30\3\30\3\30\3\30\3\30\3\30\3\31\3\31\3\31")
- buf.write("\3\31\3\31\3\32\3\32\3\32\3\32\3\32\3\33\3\33\7\33\u00c0")
- buf.write("\n\33\f\33\16\33\u00c3\13\33\3\34\5\34\u00c6\n\34\3\34")
- buf.write("\6\34\u00c9\n\34\r\34\16\34\u00ca\3\35\3\35\3\35\3\35")
- buf.write("\6\35\u00d1\n\35\r\35\16\35\u00d2\3\36\3\36\3\36\7\36")
- buf.write("\u00d8\n\36\f\36\16\36\u00db\13\36\3\37\3\37\7\37\u00df")
- buf.write("\n\37\f\37\16\37\u00e2\13\37\3 \3 \3 \3 \3!\3!\3!\3!\3")
- buf.write("!\7!\u00ed\n!\f!\16!\u00f0\13!\3!\3!\3!\3\"\6\"\u00f6")
- buf.write("\n\"\r\"\16\"\u00f7\3\"\3\"\3#\3#\3#\3#\7#\u0100\n#\f")
- buf.write("#\16#\u0103\13#\3#\3#\3$\3$\3$\3$\7$\u010b\n$\f$\16$\u010e")
- buf.write("\13$\3$\3$\3$\3$\3$\4\u00ee\u010c\2%\3\3\5\4\7\5\t\6\13")
- buf.write("\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37")
- buf.write("\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65\34")
- buf.write("\67\359\36;\37= ?!A\"C#E$G%\3\2\t\4\2\f\f\17\17\4\2--")
- buf.write("//\5\2\62;CHch\5\2C\\aac|\7\2\60\60\62;C\\aac|\3\2\62")
- buf.write(";\5\2\13\f\17\17\"\"\u011d\2\3\3\2\2\2\2\5\3\2\2\2\2\7")
- buf.write("\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3\2")
- buf.write("\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2")
- buf.write("\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2")
- buf.write("\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2")
- buf.write("\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63")
+ buf.write("\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4%\t%")
+ buf.write("\4&\t&\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\4")
+ buf.write("\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3")
+ buf.write("\5\3\6\3\6\3\6\3\6\3\6\3\6\3\6\3\6\3\7\3\7\3\b\3\b\3\t")
+ buf.write("\3\t\3\t\3\t\3\t\3\n\3\n\3\13\3\13\3\f\3\f\3\f\3\f\3\f")
+ buf.write("\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16\3\16\3")
+ buf.write("\16\3\16\3\16\3\16\3\16\3\17\3\17\3\20\3\20\3\21\3\21")
+ buf.write("\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\23\3\23\3\23\3\23")
+ buf.write("\3\23\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\25\3\25\3\25")
+ buf.write("\3\25\3\26\3\26\3\26\3\26\3\26\3\27\3\27\3\30\3\30\3\31")
+ buf.write("\3\31\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\32\3\32")
+ buf.write("\3\32\3\33\3\33\3\33\3\33\3\33\3\34\3\34\3\34\3\34\3\34")
+ buf.write("\3\35\3\35\7\35\u00d2\n\35\f\35\16\35\u00d5\13\35\3\36")
+ buf.write("\5\36\u00d8\n\36\3\36\6\36\u00db\n\36\r\36\16\36\u00dc")
+ buf.write("\3\37\3\37\3\37\3\37\6\37\u00e3\n\37\r\37\16\37\u00e4")
+ buf.write("\3 \3 \3 \7 \u00ea\n \f \16 \u00ed\13 \3!\3!\7!\u00f1")
+ buf.write("\n!\f!\16!\u00f4\13!\3\"\3\"\3\"\3\"\3#\3#\3#\3#\3#\7")
+ buf.write("#\u00ff\n#\f#\16#\u0102\13#\3#\3#\3#\3$\6$\u0108\n$\r")
+ buf.write("$\16$\u0109\3$\3$\3%\3%\3%\3%\7%\u0112\n%\f%\16%\u0115")
+ buf.write("\13%\3%\3%\3&\3&\3&\3&\7&\u011d\n&\f&\16&\u0120\13&\3")
+ buf.write("&\3&\3&\3&\3&\4\u0100\u011e\2\'\3\3\5\4\7\5\t\6\13\7\r")
+ buf.write("\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!")
+ buf.write("\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65\34\67")
+ buf.write("\359\36;\37= ?!A\"C#E$G%I&K\'\3\2\t\4\2\f\f\17\17\4\2")
+ buf.write("--//\5\2\62;CHch\5\2C\\aac|\7\2\60\60\62;C\\aac|\3\2\62")
+ buf.write(";\5\2\13\f\17\17\"\"\2\u012f\2\3\3\2\2\2\2\5\3\2\2\2\2")
+ buf.write("\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2\17\3")
+ buf.write("\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2")
+ buf.write("\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2")
+ buf.write("\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2")
+ buf.write("\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63")
buf.write("\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2")
buf.write("\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2")
- buf.write("\2\2\2G\3\2\2\2\3I\3\2\2\2\5P\3\2\2\2\7R\3\2\2\2\tY\3")
- buf.write("\2\2\2\13c\3\2\2\2\re\3\2\2\2\17g\3\2\2\2\21l\3\2\2\2")
- buf.write("\23n\3\2\2\2\25p\3\2\2\2\27w\3\2\2\2\31\u0080\3\2\2\2")
- buf.write("\33\u0082\3\2\2\2\35\u0084\3\2\2\2\37\u0089\3\2\2\2!\u008d")
- buf.write("\3\2\2\2#\u0092\3\2\2\2%\u0099\3\2\2\2\'\u009d\3\2\2\2")
- buf.write(")\u00a2\3\2\2\2+\u00a4\3\2\2\2-\u00a6\3\2\2\2/\u00ac\3")
- buf.write("\2\2\2\61\u00b3\3\2\2\2\63\u00b8\3\2\2\2\65\u00bd\3\2")
- buf.write("\2\2\67\u00c5\3\2\2\29\u00cc\3\2\2\2;\u00d4\3\2\2\2=\u00dc")
- buf.write("\3\2\2\2?\u00e3\3\2\2\2A\u00e7\3\2\2\2C\u00f5\3\2\2\2")
- buf.write("E\u00fb\3\2\2\2G\u0106\3\2\2\2IJ\7k\2\2JK\7o\2\2KL\7r")
- buf.write("\2\2LM\7q\2\2MN\7t\2\2NO\7v\2\2O\4\3\2\2\2PQ\7=\2\2Q\6")
- buf.write("\3\2\2\2RS\7o\2\2ST\7q\2\2TU\7f\2\2UV\7w\2\2VW\7n\2\2")
- buf.write("WX\7g\2\2X\b\3\2\2\2YZ\7k\2\2Z[\7p\2\2[\\\7v\2\2\\]\7")
- buf.write("g\2\2]^\7t\2\2^_\7h\2\2_`\7c\2\2`a\7e\2\2ab\7g\2\2b\n")
- buf.write("\3\2\2\2cd\7}\2\2d\f\3\2\2\2ef\7\177\2\2f\16\3\2\2\2g")
- buf.write("h\7x\2\2hi\7q\2\2ij\7k\2\2jk\7f\2\2k\20\3\2\2\2lm\7*\2")
- buf.write("\2m\22\3\2\2\2no\7+\2\2o\24\3\2\2\2pq\7u\2\2qr\7k\2\2")
- buf.write("rs\7i\2\2st\7p\2\2tu\7c\2\2uv\7n\2\2v\26\3\2\2\2wx\7t")
- buf.write("\2\2xy\7g\2\2yz\7c\2\2z{\7f\2\2{|\7q\2\2|}\7p\2\2}~\7")
- buf.write("n\2\2~\177\7{\2\2\177\30\3\2\2\2\u0080\u0081\7.\2\2\u0081")
- buf.write("\32\3\2\2\2\u0082\u0083\7?\2\2\u0083\34\3\2\2\2\u0084")
- buf.write("\u0085\7d\2\2\u0085\u0086\7q\2\2\u0086\u0087\7q\2\2\u0087")
- buf.write("\u0088\7n\2\2\u0088\36\3\2\2\2\u0089\u008a\7k\2\2\u008a")
- buf.write("\u008b\7p\2\2\u008b\u008c\7v\2\2\u008c \3\2\2\2\u008d")
- buf.write("\u008e\7t\2\2\u008e\u008f\7g\2\2\u008f\u0090\7c\2\2\u0090")
- buf.write("\u0091\7n\2\2\u0091\"\3\2\2\2\u0092\u0093\7u\2\2\u0093")
- buf.write("\u0094\7v\2\2\u0094\u0095\7t\2\2\u0095\u0096\7k\2\2\u0096")
- buf.write("\u0097\7p\2\2\u0097\u0098\7i\2\2\u0098$\3\2\2\2\u0099")
- buf.write("\u009a\7x\2\2\u009a\u009b\7c\2\2\u009b\u009c\7t\2\2\u009c")
- buf.write("&\3\2\2\2\u009d\u009e\7n\2\2\u009e\u009f\7k\2\2\u009f")
- buf.write("\u00a0\7u\2\2\u00a0\u00a1\7v\2\2\u00a1(\3\2\2\2\u00a2")
- buf.write("\u00a3\7>\2\2\u00a3*\3\2\2\2\u00a4\u00a5\7@\2\2\u00a5")
- buf.write(",\3\2\2\2\u00a6\u00a7\7o\2\2\u00a7\u00a8\7q\2\2\u00a8")
- buf.write("\u00a9\7f\2\2\u00a9\u00aa\7g\2\2\u00aa\u00ab\7n\2\2\u00ab")
- buf.write(".\3\2\2\2\u00ac\u00ad\7u\2\2\u00ad\u00ae\7v\2\2\u00ae")
- buf.write("\u00af\7t\2\2\u00af\u00b0\7w\2\2\u00b0\u00b1\7e\2\2\u00b1")
- buf.write("\u00b2\7v\2\2\u00b2\60\3\2\2\2\u00b3\u00b4\7g\2\2\u00b4")
- buf.write("\u00b5\7p\2\2\u00b5\u00b6\7w\2\2\u00b6\u00b7\7o\2\2\u00b7")
- buf.write("\62\3\2\2\2\u00b8\u00b9\7h\2\2\u00b9\u00ba\7n\2\2\u00ba")
- buf.write("\u00bb\7c\2\2\u00bb\u00bc\7i\2\2\u00bc\64\3\2\2\2\u00bd")
- buf.write("\u00c1\7B\2\2\u00be\u00c0\n\2\2\2\u00bf\u00be\3\2\2\2")
- buf.write("\u00c0\u00c3\3\2\2\2\u00c1\u00bf\3\2\2\2\u00c1\u00c2\3")
- buf.write("\2\2\2\u00c2\66\3\2\2\2\u00c3\u00c1\3\2\2\2\u00c4\u00c6")
- buf.write("\t\3\2\2\u00c5\u00c4\3\2\2\2\u00c5\u00c6\3\2\2\2\u00c6")
- buf.write("\u00c8\3\2\2\2\u00c7\u00c9\4\62;\2\u00c8\u00c7\3\2\2\2")
- buf.write("\u00c9\u00ca\3\2\2\2\u00ca\u00c8\3\2\2\2\u00ca\u00cb\3")
- buf.write("\2\2\2\u00cb8\3\2\2\2\u00cc\u00cd\7\62\2\2\u00cd\u00ce")
- buf.write("\7z\2\2\u00ce\u00d0\3\2\2\2\u00cf\u00d1\t\4\2\2\u00d0")
- buf.write("\u00cf\3\2\2\2\u00d1\u00d2\3\2\2\2\u00d2\u00d0\3\2\2\2")
- buf.write("\u00d2\u00d3\3\2\2\2\u00d3:\3\2\2\2\u00d4\u00d5\7B\2\2")
- buf.write("\u00d5\u00d9\t\5\2\2\u00d6\u00d8\t\6\2\2\u00d7\u00d6\3")
- buf.write("\2\2\2\u00d8\u00db\3\2\2\2\u00d9\u00d7\3\2\2\2\u00d9\u00da")
- buf.write("\3\2\2\2\u00da<\3\2\2\2\u00db\u00d9\3\2\2\2\u00dc\u00e0")
- buf.write("\t\5\2\2\u00dd\u00df\t\6\2\2\u00de\u00dd\3\2\2\2\u00df")
- buf.write("\u00e2\3\2\2\2\u00e0\u00de\3\2\2\2\u00e0\u00e1\3\2\2\2")
- buf.write("\u00e1>\3\2\2\2\u00e2\u00e0\3\2\2\2\u00e3\u00e4\t\7\2")
- buf.write("\2\u00e4\u00e5\7\60\2\2\u00e5\u00e6\t\7\2\2\u00e6@\3\2")
- buf.write("\2\2\u00e7\u00e8\7\61\2\2\u00e8\u00e9\7,\2\2\u00e9\u00ea")
- buf.write("\7,\2\2\u00ea\u00ee\3\2\2\2\u00eb\u00ed\13\2\2\2\u00ec")
- buf.write("\u00eb\3\2\2\2\u00ed\u00f0\3\2\2\2\u00ee\u00ef\3\2\2\2")
- buf.write("\u00ee\u00ec\3\2\2\2\u00ef\u00f1\3\2\2\2\u00f0\u00ee\3")
- buf.write("\2\2\2\u00f1\u00f2\7,\2\2\u00f2\u00f3\7\61\2\2\u00f3B")
- buf.write("\3\2\2\2\u00f4\u00f6\t\b\2\2\u00f5\u00f4\3\2\2\2\u00f6")
- buf.write("\u00f7\3\2\2\2\u00f7\u00f5\3\2\2\2\u00f7\u00f8\3\2\2\2")
- buf.write("\u00f8\u00f9\3\2\2\2\u00f9\u00fa\b\"\2\2\u00faD\3\2\2")
- buf.write("\2\u00fb\u00fc\7\61\2\2\u00fc\u00fd\7\61\2\2\u00fd\u0101")
- buf.write("\3\2\2\2\u00fe\u0100\n\2\2\2\u00ff\u00fe\3\2\2\2\u0100")
- buf.write("\u0103\3\2\2\2\u0101\u00ff\3\2\2\2\u0101\u0102\3\2\2\2")
- buf.write("\u0102\u0104\3\2\2\2\u0103\u0101\3\2\2\2\u0104\u0105\b")
- buf.write("#\2\2\u0105F\3\2\2\2\u0106\u0107\7\61\2\2\u0107\u0108")
- buf.write("\7,\2\2\u0108\u010c\3\2\2\2\u0109\u010b\13\2\2\2\u010a")
- buf.write("\u0109\3\2\2\2\u010b\u010e\3\2\2\2\u010c\u010d\3\2\2\2")
- buf.write("\u010c\u010a\3\2\2\2\u010d\u010f\3\2\2\2\u010e\u010c\3")
- buf.write("\2\2\2\u010f\u0110\7,\2\2\u0110\u0111\7\61\2\2\u0111\u0112")
- buf.write("\3\2\2\2\u0112\u0113\b$\2\2\u0113H\3\2\2\2\r\2\u00c1\u00c5")
- buf.write("\u00ca\u00d2\u00d9\u00e0\u00ee\u00f7\u0101\u010c\3\b\2")
+ buf.write("\2\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2\3M\3\2\2\2\5T\3")
+ buf.write("\2\2\2\7V\3\2\2\2\t]\3\2\2\2\13g\3\2\2\2\ro\3\2\2\2\17")
+ buf.write("q\3\2\2\2\21s\3\2\2\2\23x\3\2\2\2\25z\3\2\2\2\27|\3\2")
+ buf.write("\2\2\31\u0082\3\2\2\2\33\u0089\3\2\2\2\35\u0092\3\2\2")
+ buf.write("\2\37\u0094\3\2\2\2!\u0096\3\2\2\2#\u009b\3\2\2\2%\u009f")
+ buf.write("\3\2\2\2\'\u00a4\3\2\2\2)\u00ab\3\2\2\2+\u00af\3\2\2\2")
+ buf.write("-\u00b4\3\2\2\2/\u00b6\3\2\2\2\61\u00b8\3\2\2\2\63\u00be")
+ buf.write("\3\2\2\2\65\u00c5\3\2\2\2\67\u00ca\3\2\2\29\u00cf\3\2")
+ buf.write("\2\2;\u00d7\3\2\2\2=\u00de\3\2\2\2?\u00e6\3\2\2\2A\u00ee")
+ buf.write("\3\2\2\2C\u00f5\3\2\2\2E\u00f9\3\2\2\2G\u0107\3\2\2\2")
+ buf.write("I\u010d\3\2\2\2K\u0118\3\2\2\2MN\7k\2\2NO\7o\2\2OP\7r")
+ buf.write("\2\2PQ\7q\2\2QR\7t\2\2RS\7v\2\2S\4\3\2\2\2TU\7=\2\2U\6")
+ buf.write("\3\2\2\2VW\7o\2\2WX\7q\2\2XY\7f\2\2YZ\7w\2\2Z[\7n\2\2")
+ buf.write("[\\\7g\2\2\\\b\3\2\2\2]^\7k\2\2^_\7p\2\2_`\7v\2\2`a\7")
+ buf.write("g\2\2ab\7t\2\2bc\7h\2\2cd\7c\2\2de\7e\2\2ef\7g\2\2f\n")
+ buf.write("\3\2\2\2gh\7g\2\2hi\7z\2\2ij\7v\2\2jk\7g\2\2kl\7p\2\2")
+ buf.write("lm\7f\2\2mn\7u\2\2n\f\3\2\2\2op\7}\2\2p\16\3\2\2\2qr\7")
+ buf.write("\177\2\2r\20\3\2\2\2st\7x\2\2tu\7q\2\2uv\7k\2\2vw\7f\2")
+ buf.write("\2w\22\3\2\2\2xy\7*\2\2y\24\3\2\2\2z{\7+\2\2{\26\3\2\2")
+ buf.write("\2|}\7e\2\2}~\7q\2\2~\177\7p\2\2\177\u0080\7u\2\2\u0080")
+ buf.write("\u0081\7v\2\2\u0081\30\3\2\2\2\u0082\u0083\7u\2\2\u0083")
+ buf.write("\u0084\7k\2\2\u0084\u0085\7i\2\2\u0085\u0086\7p\2\2\u0086")
+ buf.write("\u0087\7c\2\2\u0087\u0088\7n\2\2\u0088\32\3\2\2\2\u0089")
+ buf.write("\u008a\7t\2\2\u008a\u008b\7g\2\2\u008b\u008c\7c\2\2\u008c")
+ buf.write("\u008d\7f\2\2\u008d\u008e\7q\2\2\u008e\u008f\7p\2\2\u008f")
+ buf.write("\u0090\7n\2\2\u0090\u0091\7{\2\2\u0091\34\3\2\2\2\u0092")
+ buf.write("\u0093\7.\2\2\u0093\36\3\2\2\2\u0094\u0095\7?\2\2\u0095")
+ buf.write(" \3\2\2\2\u0096\u0097\7d\2\2\u0097\u0098\7q\2\2\u0098")
+ buf.write("\u0099\7q\2\2\u0099\u009a\7n\2\2\u009a\"\3\2\2\2\u009b")
+ buf.write("\u009c\7k\2\2\u009c\u009d\7p\2\2\u009d\u009e\7v\2\2\u009e")
+ buf.write("$\3\2\2\2\u009f\u00a0\7t\2\2\u00a0\u00a1\7g\2\2\u00a1")
+ buf.write("\u00a2\7c\2\2\u00a2\u00a3\7n\2\2\u00a3&\3\2\2\2\u00a4")
+ buf.write("\u00a5\7u\2\2\u00a5\u00a6\7v\2\2\u00a6\u00a7\7t\2\2\u00a7")
+ buf.write("\u00a8\7k\2\2\u00a8\u00a9\7p\2\2\u00a9\u00aa\7i\2\2\u00aa")
+ buf.write("(\3\2\2\2\u00ab\u00ac\7x\2\2\u00ac\u00ad\7c\2\2\u00ad")
+ buf.write("\u00ae\7t\2\2\u00ae*\3\2\2\2\u00af\u00b0\7n\2\2\u00b0")
+ buf.write("\u00b1\7k\2\2\u00b1\u00b2\7u\2\2\u00b2\u00b3\7v\2\2\u00b3")
+ buf.write(",\3\2\2\2\u00b4\u00b5\7>\2\2\u00b5.\3\2\2\2\u00b6\u00b7")
+ buf.write("\7@\2\2\u00b7\60\3\2\2\2\u00b8\u00b9\7o\2\2\u00b9\u00ba")
+ buf.write("\7q\2\2\u00ba\u00bb\7f\2\2\u00bb\u00bc\7g\2\2\u00bc\u00bd")
+ buf.write("\7n\2\2\u00bd\62\3\2\2\2\u00be\u00bf\7u\2\2\u00bf\u00c0")
+ buf.write("\7v\2\2\u00c0\u00c1\7t\2\2\u00c1\u00c2\7w\2\2\u00c2\u00c3")
+ buf.write("\7e\2\2\u00c3\u00c4\7v\2\2\u00c4\64\3\2\2\2\u00c5\u00c6")
+ buf.write("\7g\2\2\u00c6\u00c7\7p\2\2\u00c7\u00c8\7w\2\2\u00c8\u00c9")
+ buf.write("\7o\2\2\u00c9\66\3\2\2\2\u00ca\u00cb\7h\2\2\u00cb\u00cc")
+ buf.write("\7n\2\2\u00cc\u00cd\7c\2\2\u00cd\u00ce\7i\2\2\u00ce8\3")
+ buf.write("\2\2\2\u00cf\u00d3\7B\2\2\u00d0\u00d2\n\2\2\2\u00d1\u00d0")
+ buf.write("\3\2\2\2\u00d2\u00d5\3\2\2\2\u00d3\u00d1\3\2\2\2\u00d3")
+ buf.write("\u00d4\3\2\2\2\u00d4:\3\2\2\2\u00d5\u00d3\3\2\2\2\u00d6")
+ buf.write("\u00d8\t\3\2\2\u00d7\u00d6\3\2\2\2\u00d7\u00d8\3\2\2\2")
+ buf.write("\u00d8\u00da\3\2\2\2\u00d9\u00db\4\62;\2\u00da\u00d9\3")
+ buf.write("\2\2\2\u00db\u00dc\3\2\2\2\u00dc\u00da\3\2\2\2\u00dc\u00dd")
+ buf.write("\3\2\2\2\u00dd<\3\2\2\2\u00de\u00df\7\62\2\2\u00df\u00e0")
+ buf.write("\7z\2\2\u00e0\u00e2\3\2\2\2\u00e1\u00e3\t\4\2\2\u00e2")
+ buf.write("\u00e1\3\2\2\2\u00e3\u00e4\3\2\2\2\u00e4\u00e2\3\2\2\2")
+ buf.write("\u00e4\u00e5\3\2\2\2\u00e5>\3\2\2\2\u00e6\u00e7\7B\2\2")
+ buf.write("\u00e7\u00eb\t\5\2\2\u00e8\u00ea\t\6\2\2\u00e9\u00e8\3")
+ buf.write("\2\2\2\u00ea\u00ed\3\2\2\2\u00eb\u00e9\3\2\2\2\u00eb\u00ec")
+ buf.write("\3\2\2\2\u00ec@\3\2\2\2\u00ed\u00eb\3\2\2\2\u00ee\u00f2")
+ buf.write("\t\5\2\2\u00ef\u00f1\t\6\2\2\u00f0\u00ef\3\2\2\2\u00f1")
+ buf.write("\u00f4\3\2\2\2\u00f2\u00f0\3\2\2\2\u00f2\u00f3\3\2\2\2")
+ buf.write("\u00f3B\3\2\2\2\u00f4\u00f2\3\2\2\2\u00f5\u00f6\t\7\2")
+ buf.write("\2\u00f6\u00f7\7\60\2\2\u00f7\u00f8\t\7\2\2\u00f8D\3\2")
+ buf.write("\2\2\u00f9\u00fa\7\61\2\2\u00fa\u00fb\7,\2\2\u00fb\u00fc")
+ buf.write("\7,\2\2\u00fc\u0100\3\2\2\2\u00fd\u00ff\13\2\2\2\u00fe")
+ buf.write("\u00fd\3\2\2\2\u00ff\u0102\3\2\2\2\u0100\u0101\3\2\2\2")
+ buf.write("\u0100\u00fe\3\2\2\2\u0101\u0103\3\2\2\2\u0102\u0100\3")
+ buf.write("\2\2\2\u0103\u0104\7,\2\2\u0104\u0105\7\61\2\2\u0105F")
+ buf.write("\3\2\2\2\u0106\u0108\t\b\2\2\u0107\u0106\3\2\2\2\u0108")
+ buf.write("\u0109\3\2\2\2\u0109\u0107\3\2\2\2\u0109\u010a\3\2\2\2")
+ buf.write("\u010a\u010b\3\2\2\2\u010b\u010c\b$\2\2\u010cH\3\2\2\2")
+ buf.write("\u010d\u010e\7\61\2\2\u010e\u010f\7\61\2\2\u010f\u0113")
+ buf.write("\3\2\2\2\u0110\u0112\n\2\2\2\u0111\u0110\3\2\2\2\u0112")
+ buf.write("\u0115\3\2\2\2\u0113\u0111\3\2\2\2\u0113\u0114\3\2\2\2")
+ buf.write("\u0114\u0116\3\2\2\2\u0115\u0113\3\2\2\2\u0116\u0117\b")
+ buf.write("%\2\2\u0117J\3\2\2\2\u0118\u0119\7\61\2\2\u0119\u011a")
+ buf.write("\7,\2\2\u011a\u011e\3\2\2\2\u011b\u011d\13\2\2\2\u011c")
+ buf.write("\u011b\3\2\2\2\u011d\u0120\3\2\2\2\u011e\u011f\3\2\2\2")
+ buf.write("\u011e\u011c\3\2\2\2\u011f\u0121\3\2\2\2\u0120\u011e\3")
+ buf.write("\2\2\2\u0121\u0122\7,\2\2\u0122\u0123\7\61\2\2\u0123\u0124")
+ buf.write("\3\2\2\2\u0124\u0125\b&\2\2\u0125L\3\2\2\2\r\2\u00d3\u00d7")
+ buf.write("\u00dc\u00e4\u00eb\u00f2\u0100\u0109\u0113\u011e\3\b\2")
buf.write("\2")
return buf.getvalue()
@@ -129,7 +138,6 @@ class TLexer(Lexer):
decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ]
-
T__0 = 1
T__1 = 2
T__2 = 3
@@ -155,24 +163,28 @@ class TLexer(Lexer):
T__22 = 23
T__23 = 24
T__24 = 25
- TAGLINE = 26
- INTCONSTANT = 27
- HEXCONSTANT = 28
- TAGIDENTIFIER = 29
- IDENTIFIER = 30
- VERSION = 31
- DOCCOMMENT = 32
- WHITESPACE = 33
- COMMENT = 34
- MULTICOMM = 35
+ T__25 = 26
+ T__26 = 27
+ TAGLINE = 28
+ INTCONSTANT = 29
+ HEXCONSTANT = 30
+ TAGIDENTIFIER = 31
+ IDENTIFIER = 32
+ VERSION = 33
+ DOCCOMMENT = 34
+ WHITESPACE = 35
+ COMMENT = 36
+ MULTICOMM = 37
+
+ channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ]
modeNames = [ "DEFAULT_MODE" ]
literalNames = [ "<INVALID>",
- "'import'", "';'", "'module'", "'interface'", "'{'", "'}'",
- "'void'", "'('", "')'", "'signal'", "'readonly'", "','", "'='",
- "'bool'", "'int'", "'real'", "'string'", "'var'", "'list'",
- "'<'", "'>'", "'model'", "'struct'", "'enum'", "'flag'" ]
+ "'import'", "';'", "'module'", "'interface'", "'extends'", "'{'",
+ "'}'", "'void'", "'('", "')'", "'const'", "'signal'", "'readonly'",
+ "','", "'='", "'bool'", "'int'", "'real'", "'string'", "'var'",
+ "'list'", "'<'", "'>'", "'model'", "'struct'", "'enum'", "'flag'" ]
symbolicNames = [ "<INVALID>",
"TAGLINE", "INTCONSTANT", "HEXCONSTANT", "TAGIDENTIFIER", "IDENTIFIER",
@@ -181,15 +193,16 @@ class TLexer(Lexer):
ruleNames = [ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6",
"T__7", "T__8", "T__9", "T__10", "T__11", "T__12", "T__13",
"T__14", "T__15", "T__16", "T__17", "T__18", "T__19",
- "T__20", "T__21", "T__22", "T__23", "T__24", "TAGLINE",
- "INTCONSTANT", "HEXCONSTANT", "TAGIDENTIFIER", "IDENTIFIER",
- "VERSION", "DOCCOMMENT", "WHITESPACE", "COMMENT", "MULTICOMM" ]
+ "T__20", "T__21", "T__22", "T__23", "T__24", "T__25",
+ "T__26", "TAGLINE", "INTCONSTANT", "HEXCONSTANT", "TAGIDENTIFIER",
+ "IDENTIFIER", "VERSION", "DOCCOMMENT", "WHITESPACE", "COMMENT",
+ "MULTICOMM" ]
grammarFileName = "T.g4"
- def __init__(self, input=None):
- super().__init__(input)
- self.checkVersion("4.6")
+ def __init__(self, input=None, output:TextIO = sys.stdout):
+ super().__init__(input, output)
+ self.checkVersion("4.7")
self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache())
self._actions = None
self._predicates = None
diff --git a/qface/idl/parser/TLexer.tokens b/qface/idl/parser/TLexer.tokens
index 86bf74a..5f94603 100644
--- a/qface/idl/parser/TLexer.tokens
+++ b/qface/idl/parser/TLexer.tokens
@@ -23,38 +23,42 @@ T__21=22
T__22=23
T__23=24
T__24=25
-TAGLINE=26
-INTCONSTANT=27
-HEXCONSTANT=28
-TAGIDENTIFIER=29
-IDENTIFIER=30
-VERSION=31
-DOCCOMMENT=32
-WHITESPACE=33
-COMMENT=34
-MULTICOMM=35
+T__25=26
+T__26=27
+TAGLINE=28
+INTCONSTANT=29
+HEXCONSTANT=30
+TAGIDENTIFIER=31
+IDENTIFIER=32
+VERSION=33
+DOCCOMMENT=34
+WHITESPACE=35
+COMMENT=36
+MULTICOMM=37
'import'=1
';'=2
'module'=3
'interface'=4
-'{'=5
-'}'=6
-'void'=7
-'('=8
-')'=9
-'signal'=10
-'readonly'=11
-','=12
-'='=13
-'bool'=14
-'int'=15
-'real'=16
-'string'=17
-'var'=18
-'list'=19
-'<'=20
-'>'=21
-'model'=22
-'struct'=23
-'enum'=24
-'flag'=25
+'extends'=5
+'{'=6
+'}'=7
+'void'=8
+'('=9
+')'=10
+'const'=11
+'signal'=12
+'readonly'=13
+','=14
+'='=15
+'bool'=16
+'int'=17
+'real'=18
+'string'=19
+'var'=20
+'list'=21
+'<'=22
+'>'=23
+'model'=24
+'struct'=25
+'enum'=26
+'flag'=27
diff --git a/qface/idl/parser/TListener.py b/qface/idl/parser/TListener.py
index 07d41ad..54e764a 100644
--- a/qface/idl/parser/TListener.py
+++ b/qface/idl/parser/TListener.py
@@ -1,4 +1,4 @@
-# Generated from T.g4 by ANTLR 4.6
+# Generated from T.g4 by ANTLR 4.7
from antlr4 import *
if __name__ is not None and "." in __name__:
from .TParser import TParser
@@ -80,6 +80,15 @@ class TListener(ParseTreeListener):
pass
+ # Enter a parse tree produced by TParser#operationModifierSymbol.
+ def enterOperationModifierSymbol(self, ctx:TParser.OperationModifierSymbolContext):
+ pass
+
+ # Exit a parse tree produced by TParser#operationModifierSymbol.
+ def exitOperationModifierSymbol(self, ctx:TParser.OperationModifierSymbolContext):
+ pass
+
+
# Enter a parse tree produced by TParser#signalSymbol.
def enterSignalSymbol(self, ctx:TParser.SignalSymbolContext):
pass
@@ -98,6 +107,15 @@ class TListener(ParseTreeListener):
pass
+ # Enter a parse tree produced by TParser#propertyModifierSymbol.
+ def enterPropertyModifierSymbol(self, ctx:TParser.PropertyModifierSymbolContext):
+ pass
+
+ # Exit a parse tree produced by TParser#propertyModifierSymbol.
+ def exitPropertyModifierSymbol(self, ctx:TParser.PropertyModifierSymbolContext):
+ pass
+
+
# Enter a parse tree produced by TParser#operationParameterSymbol.
def enterOperationParameterSymbol(self, ctx:TParser.OperationParameterSymbolContext):
pass
diff --git a/qface/idl/parser/TParser.py b/qface/idl/parser/TParser.py
index 15eadd6..b180f95 100644
--- a/qface/idl/parser/TParser.py
+++ b/qface/idl/parser/TParser.py
@@ -1,151 +1,163 @@
-# Generated from T.g4 by ANTLR 4.6
+# Generated from T.g4 by ANTLR 4.7
# encoding: utf-8
from antlr4 import *
from io import StringIO
+from typing.io import TextIO
+import sys
def serializedATN():
with StringIO() as buf:
- buf.write("\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3%")
- buf.write("\u0131\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7")
+ buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\'")
+ buf.write("\u0142\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7")
buf.write("\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r\4\16")
buf.write("\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23\t\23")
buf.write("\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31")
- buf.write("\t\31\3\2\3\2\7\2\65\n\2\f\2\16\28\13\2\3\3\3\3\7\3<\n")
- buf.write("\3\f\3\16\3?\13\3\3\4\3\4\3\4\3\4\5\4E\n\4\3\5\5\5H\n")
- buf.write("\5\3\5\7\5K\n\5\f\5\16\5N\13\5\3\5\3\5\3\5\3\5\5\5T\n")
- buf.write("\5\3\6\3\6\3\6\5\6Y\n\6\3\7\5\7\\\n\7\3\7\7\7_\n\7\f\7")
- buf.write("\16\7b\13\7\3\7\3\7\3\7\3\7\7\7h\n\7\f\7\16\7k\13\7\3")
- buf.write("\7\3\7\5\7o\n\7\3\b\3\b\3\b\5\bt\n\b\3\t\5\tw\n\t\3\t")
- buf.write("\7\tz\n\t\f\t\16\t}\13\t\3\t\3\t\5\t\u0081\n\t\3\t\3\t")
- buf.write("\3\t\7\t\u0086\n\t\f\t\16\t\u0089\13\t\3\t\3\t\5\t\u008d")
- buf.write("\n\t\3\n\5\n\u0090\n\n\3\n\7\n\u0093\n\n\f\n\16\n\u0096")
- buf.write("\13\n\3\n\3\n\3\n\3\n\7\n\u009c\n\n\f\n\16\n\u009f\13")
- buf.write("\n\3\n\3\n\5\n\u00a3\n\n\3\13\5\13\u00a6\n\13\3\13\7\13")
- buf.write("\u00a9\n\13\f\13\16\13\u00ac\13\13\3\13\5\13\u00af\n\13")
- buf.write("\3\13\3\13\3\13\5\13\u00b4\n\13\3\f\3\f\3\f\5\f\u00b9")
- buf.write("\n\f\3\r\3\r\3\16\3\16\3\16\5\16\u00c0\n\16\3\16\5\16")
- buf.write("\u00c3\n\16\3\17\3\17\3\17\3\17\5\17\u00c9\n\17\3\20\3")
- buf.write("\20\3\21\3\21\3\21\3\21\3\21\5\21\u00d2\n\21\3\22\3\22")
- buf.write("\3\22\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\24\5\24\u00df")
- buf.write("\n\24\3\24\7\24\u00e2\n\24\f\24\16\24\u00e5\13\24\3\24")
- buf.write("\3\24\3\24\3\24\7\24\u00eb\n\24\f\24\16\24\u00ee\13\24")
- buf.write("\3\24\3\24\5\24\u00f2\n\24\3\25\5\25\u00f5\n\25\3\25\7")
- buf.write("\25\u00f8\n\25\f\25\16\25\u00fb\13\25\3\25\3\25\3\25\5")
- buf.write("\25\u0100\n\25\3\26\5\26\u0103\n\26\3\26\7\26\u0106\n")
- buf.write("\26\f\26\16\26\u0109\13\26\3\26\3\26\3\26\3\26\7\26\u010f")
- buf.write("\n\26\f\26\16\26\u0112\13\26\3\26\3\26\5\26\u0116\n\26")
- buf.write("\3\27\3\27\5\27\u011a\n\27\3\30\5\30\u011d\n\30\3\30\7")
- buf.write("\30\u0120\n\30\f\30\16\30\u0123\13\30\3\30\3\30\3\30\5")
- buf.write("\30\u0128\n\30\3\30\5\30\u012b\n\30\3\31\3\31\5\31\u012f")
- buf.write("\n\31\3\31\2\2\32\2\4\6\b\n\f\16\20\22\24\26\30\32\34")
- buf.write("\36 \"$&(*,.\60\2\2\u014e\2\62\3\2\2\2\49\3\2\2\2\6@\3")
- buf.write("\2\2\2\bG\3\2\2\2\nX\3\2\2\2\f[\3\2\2\2\16s\3\2\2\2\20")
- buf.write("v\3\2\2\2\22\u008f\3\2\2\2\24\u00a5\3\2\2\2\26\u00b5\3")
- buf.write("\2\2\2\30\u00ba\3\2\2\2\32\u00bc\3\2\2\2\34\u00c8\3\2")
- buf.write("\2\2\36\u00ca\3\2\2\2 \u00d1\3\2\2\2\"\u00d3\3\2\2\2$")
- buf.write("\u00d8\3\2\2\2&\u00de\3\2\2\2(\u00f4\3\2\2\2*\u0102\3")
- buf.write("\2\2\2,\u0119\3\2\2\2.\u011c\3\2\2\2\60\u012e\3\2\2\2")
- buf.write("\62\66\5\4\3\2\63\65\5\n\6\2\64\63\3\2\2\2\658\3\2\2\2")
- buf.write("\66\64\3\2\2\2\66\67\3\2\2\2\67\3\3\2\2\28\66\3\2\2\2")
- buf.write("9=\5\b\5\2:<\5\6\4\2;:\3\2\2\2<?\3\2\2\2=;\3\2\2\2=>\3")
- buf.write("\2\2\2>\5\3\2\2\2?=\3\2\2\2@A\7\3\2\2AB\7 \2\2BD\7!\2")
- buf.write("\2CE\7\4\2\2DC\3\2\2\2DE\3\2\2\2E\7\3\2\2\2FH\7\"\2\2")
- buf.write("GF\3\2\2\2GH\3\2\2\2HL\3\2\2\2IK\5\30\r\2JI\3\2\2\2KN")
- buf.write("\3\2\2\2LJ\3\2\2\2LM\3\2\2\2MO\3\2\2\2NL\3\2\2\2OP\7\5")
- buf.write("\2\2PQ\7 \2\2QS\7!\2\2RT\7\4\2\2SR\3\2\2\2ST\3\2\2\2T")
- buf.write("\t\3\2\2\2UY\5\f\7\2VY\5&\24\2WY\5*\26\2XU\3\2\2\2XV\3")
- buf.write("\2\2\2XW\3\2\2\2Y\13\3\2\2\2Z\\\7\"\2\2[Z\3\2\2\2[\\\3")
- buf.write("\2\2\2\\`\3\2\2\2]_\5\30\r\2^]\3\2\2\2_b\3\2\2\2`^\3\2")
- buf.write("\2\2`a\3\2\2\2ac\3\2\2\2b`\3\2\2\2cd\7\6\2\2de\7 \2\2")
- buf.write("ei\7\7\2\2fh\5\16\b\2gf\3\2\2\2hk\3\2\2\2ig\3\2\2\2ij")
- buf.write("\3\2\2\2jl\3\2\2\2ki\3\2\2\2ln\7\b\2\2mo\7\4\2\2nm\3\2")
- buf.write("\2\2no\3\2\2\2o\r\3\2\2\2pt\5\20\t\2qt\5\24\13\2rt\5\22")
- buf.write("\n\2sp\3\2\2\2sq\3\2\2\2sr\3\2\2\2t\17\3\2\2\2uw\7\"\2")
- buf.write("\2vu\3\2\2\2vw\3\2\2\2w{\3\2\2\2xz\5\30\r\2yx\3\2\2\2")
- buf.write("z}\3\2\2\2{y\3\2\2\2{|\3\2\2\2|\u0080\3\2\2\2}{\3\2\2")
- buf.write("\2~\u0081\5\34\17\2\177\u0081\7\t\2\2\u0080~\3\2\2\2\u0080")
- buf.write("\177\3\2\2\2\u0081\u0082\3\2\2\2\u0082\u0083\7 \2\2\u0083")
- buf.write("\u0087\7\n\2\2\u0084\u0086\5\26\f\2\u0085\u0084\3\2\2")
- buf.write("\2\u0086\u0089\3\2\2\2\u0087\u0085\3\2\2\2\u0087\u0088")
- buf.write("\3\2\2\2\u0088\u008a\3\2\2\2\u0089\u0087\3\2\2\2\u008a")
- buf.write("\u008c\7\13\2\2\u008b\u008d\7\4\2\2\u008c\u008b\3\2\2")
- buf.write("\2\u008c\u008d\3\2\2\2\u008d\21\3\2\2\2\u008e\u0090\7")
- buf.write("\"\2\2\u008f\u008e\3\2\2\2\u008f\u0090\3\2\2\2\u0090\u0094")
- buf.write("\3\2\2\2\u0091\u0093\5\30\r\2\u0092\u0091\3\2\2\2\u0093")
- buf.write("\u0096\3\2\2\2\u0094\u0092\3\2\2\2\u0094\u0095\3\2\2\2")
- buf.write("\u0095\u0097\3\2\2\2\u0096\u0094\3\2\2\2\u0097\u0098\7")
- buf.write("\f\2\2\u0098\u0099\7 \2\2\u0099\u009d\7\n\2\2\u009a\u009c")
- buf.write("\5\26\f\2\u009b\u009a\3\2\2\2\u009c\u009f\3\2\2\2\u009d")
- buf.write("\u009b\3\2\2\2\u009d\u009e\3\2\2\2\u009e\u00a0\3\2\2\2")
- buf.write("\u009f\u009d\3\2\2\2\u00a0\u00a2\7\13\2\2\u00a1\u00a3")
- buf.write("\7\4\2\2\u00a2\u00a1\3\2\2\2\u00a2\u00a3\3\2\2\2\u00a3")
- buf.write("\23\3\2\2\2\u00a4\u00a6\7\"\2\2\u00a5\u00a4\3\2\2\2\u00a5")
- buf.write("\u00a6\3\2\2\2\u00a6\u00aa\3\2\2\2\u00a7\u00a9\5\30\r")
- buf.write("\2\u00a8\u00a7\3\2\2\2\u00a9\u00ac\3\2\2\2\u00aa\u00a8")
- buf.write("\3\2\2\2\u00aa\u00ab\3\2\2\2\u00ab\u00ae\3\2\2\2\u00ac")
- buf.write("\u00aa\3\2\2\2\u00ad\u00af\7\r\2\2\u00ae\u00ad\3\2\2\2")
- buf.write("\u00ae\u00af\3\2\2\2\u00af\u00b0\3\2\2\2\u00b0\u00b1\5")
- buf.write("\34\17\2\u00b1\u00b3\7 \2\2\u00b2\u00b4\7\4\2\2\u00b3")
- buf.write("\u00b2\3\2\2\2\u00b3\u00b4\3\2\2\2\u00b4\25\3\2\2\2\u00b5")
- buf.write("\u00b6\5\34\17\2\u00b6\u00b8\7 \2\2\u00b7\u00b9\7\16\2")
- buf.write("\2\u00b8\u00b7\3\2\2\2\u00b8\u00b9\3\2\2\2\u00b9\27\3")
- buf.write("\2\2\2\u00ba\u00bb\7\34\2\2\u00bb\31\3\2\2\2\u00bc\u00bf")
- buf.write("\7 \2\2\u00bd\u00be\7\17\2\2\u00be\u00c0\7 \2\2\u00bf")
- buf.write("\u00bd\3\2\2\2\u00bf\u00c0\3\2\2\2\u00c0\u00c2\3\2\2\2")
- buf.write("\u00c1\u00c3\7\16\2\2\u00c2\u00c1\3\2\2\2\u00c2\u00c3")
- buf.write("\3\2\2\2\u00c3\33\3\2\2\2\u00c4\u00c9\5 \21\2\u00c5\u00c9")
- buf.write("\5\36\20\2\u00c6\u00c9\5\"\22\2\u00c7\u00c9\5$\23\2\u00c8")
- buf.write("\u00c4\3\2\2\2\u00c8\u00c5\3\2\2\2\u00c8\u00c6\3\2\2\2")
- buf.write("\u00c8\u00c7\3\2\2\2\u00c9\35\3\2\2\2\u00ca\u00cb\7 \2")
- buf.write("\2\u00cb\37\3\2\2\2\u00cc\u00d2\7\20\2\2\u00cd\u00d2\7")
- buf.write("\21\2\2\u00ce\u00d2\7\22\2\2\u00cf\u00d2\7\23\2\2\u00d0")
- buf.write("\u00d2\7\24\2\2\u00d1\u00cc\3\2\2\2\u00d1\u00cd\3\2\2")
- buf.write("\2\u00d1\u00ce\3\2\2\2\u00d1\u00cf\3\2\2\2\u00d1\u00d0")
- buf.write("\3\2\2\2\u00d2!\3\2\2\2\u00d3\u00d4\7\25\2\2\u00d4\u00d5")
- buf.write("\7\26\2\2\u00d5\u00d6\5\34\17\2\u00d6\u00d7\7\27\2\2\u00d7")
- buf.write("#\3\2\2\2\u00d8\u00d9\7\30\2\2\u00d9\u00da\7\26\2\2\u00da")
- buf.write("\u00db\5\34\17\2\u00db\u00dc\7\27\2\2\u00dc%\3\2\2\2\u00dd")
- buf.write("\u00df\7\"\2\2\u00de\u00dd\3\2\2\2\u00de\u00df\3\2\2\2")
- buf.write("\u00df\u00e3\3\2\2\2\u00e0\u00e2\5\30\r\2\u00e1\u00e0")
- buf.write("\3\2\2\2\u00e2\u00e5\3\2\2\2\u00e3\u00e1\3\2\2\2\u00e3")
- buf.write("\u00e4\3\2\2\2\u00e4\u00e6\3\2\2\2\u00e5\u00e3\3\2\2\2")
- buf.write("\u00e6\u00e7\7\31\2\2\u00e7\u00e8\7 \2\2\u00e8\u00ec\7")
- buf.write("\7\2\2\u00e9\u00eb\5(\25\2\u00ea\u00e9\3\2\2\2\u00eb\u00ee")
- buf.write("\3\2\2\2\u00ec\u00ea\3\2\2\2\u00ec\u00ed\3\2\2\2\u00ed")
- buf.write("\u00ef\3\2\2\2\u00ee\u00ec\3\2\2\2\u00ef\u00f1\7\b\2\2")
- buf.write("\u00f0\u00f2\7\4\2\2\u00f1\u00f0\3\2\2\2\u00f1\u00f2\3")
- buf.write("\2\2\2\u00f2\'\3\2\2\2\u00f3\u00f5\7\"\2\2\u00f4\u00f3")
- buf.write("\3\2\2\2\u00f4\u00f5\3\2\2\2\u00f5\u00f9\3\2\2\2\u00f6")
- buf.write("\u00f8\5\30\r\2\u00f7\u00f6\3\2\2\2\u00f8\u00fb\3\2\2")
- buf.write("\2\u00f9\u00f7\3\2\2\2\u00f9\u00fa\3\2\2\2\u00fa\u00fc")
- buf.write("\3\2\2\2\u00fb\u00f9\3\2\2\2\u00fc\u00fd\5\34\17\2\u00fd")
- buf.write("\u00ff\7 \2\2\u00fe\u0100\7\4\2\2\u00ff\u00fe\3\2\2\2")
- buf.write("\u00ff\u0100\3\2\2\2\u0100)\3\2\2\2\u0101\u0103\7\"\2")
- buf.write("\2\u0102\u0101\3\2\2\2\u0102\u0103\3\2\2\2\u0103\u0107")
- buf.write("\3\2\2\2\u0104\u0106\5\30\r\2\u0105\u0104\3\2\2\2\u0106")
- buf.write("\u0109\3\2\2\2\u0107\u0105\3\2\2\2\u0107\u0108\3\2\2\2")
- buf.write("\u0108\u010a\3\2\2\2\u0109\u0107\3\2\2\2\u010a\u010b\5")
- buf.write(",\27\2\u010b\u010c\7 \2\2\u010c\u0110\7\7\2\2\u010d\u010f")
- buf.write("\5.\30\2\u010e\u010d\3\2\2\2\u010f\u0112\3\2\2\2\u0110")
- buf.write("\u010e\3\2\2\2\u0110\u0111\3\2\2\2\u0111\u0113\3\2\2\2")
- buf.write("\u0112\u0110\3\2\2\2\u0113\u0115\7\b\2\2\u0114\u0116\7")
- buf.write("\4\2\2\u0115\u0114\3\2\2\2\u0115\u0116\3\2\2\2\u0116+")
- buf.write("\3\2\2\2\u0117\u011a\7\32\2\2\u0118\u011a\7\33\2\2\u0119")
- buf.write("\u0117\3\2\2\2\u0119\u0118\3\2\2\2\u011a-\3\2\2\2\u011b")
- buf.write("\u011d\7\"\2\2\u011c\u011b\3\2\2\2\u011c\u011d\3\2\2\2")
- buf.write("\u011d\u0121\3\2\2\2\u011e\u0120\5\30\r\2\u011f\u011e")
- buf.write("\3\2\2\2\u0120\u0123\3\2\2\2\u0121\u011f\3\2\2\2\u0121")
- buf.write("\u0122\3\2\2\2\u0122\u0124\3\2\2\2\u0123\u0121\3\2\2\2")
- buf.write("\u0124\u0127\7 \2\2\u0125\u0126\7\17\2\2\u0126\u0128\5")
- buf.write("\60\31\2\u0127\u0125\3\2\2\2\u0127\u0128\3\2\2\2\u0128")
- buf.write("\u012a\3\2\2\2\u0129\u012b\7\16\2\2\u012a\u0129\3\2\2")
- buf.write("\2\u012a\u012b\3\2\2\2\u012b/\3\2\2\2\u012c\u012f\7\35")
- buf.write("\2\2\u012d\u012f\7\36\2\2\u012e\u012c\3\2\2\2\u012e\u012d")
- buf.write("\3\2\2\2\u012f\61\3\2\2\2\61\66=DGLSX[`insv{\u0080\u0087")
- buf.write("\u008c\u008f\u0094\u009d\u00a2\u00a5\u00aa\u00ae\u00b3")
- buf.write("\u00b8\u00bf\u00c2\u00c8\u00d1\u00de\u00e3\u00ec\u00f1")
- buf.write("\u00f4\u00f9\u00ff\u0102\u0107\u0110\u0115\u0119\u011c")
- buf.write("\u0121\u0127\u012a\u012e")
+ buf.write("\t\31\4\32\t\32\4\33\t\33\3\2\3\2\7\29\n\2\f\2\16\2<\13")
+ buf.write("\2\3\3\3\3\7\3@\n\3\f\3\16\3C\13\3\3\4\3\4\3\4\3\4\5\4")
+ buf.write("I\n\4\3\5\5\5L\n\5\3\5\7\5O\n\5\f\5\16\5R\13\5\3\5\3\5")
+ buf.write("\3\5\3\5\5\5X\n\5\3\6\3\6\3\6\5\6]\n\6\3\7\5\7`\n\7\3")
+ buf.write("\7\7\7c\n\7\f\7\16\7f\13\7\3\7\3\7\3\7\3\7\5\7l\n\7\3")
+ buf.write("\7\3\7\7\7p\n\7\f\7\16\7s\13\7\3\7\3\7\5\7w\n\7\3\b\3")
+ buf.write("\b\3\b\5\b|\n\b\3\t\5\t\177\n\t\3\t\7\t\u0082\n\t\f\t")
+ buf.write("\16\t\u0085\13\t\3\t\3\t\5\t\u0089\n\t\3\t\3\t\3\t\7\t")
+ buf.write("\u008e\n\t\f\t\16\t\u0091\13\t\3\t\3\t\5\t\u0095\n\t\3")
+ buf.write("\t\5\t\u0098\n\t\3\n\3\n\3\13\5\13\u009d\n\13\3\13\7\13")
+ buf.write("\u00a0\n\13\f\13\16\13\u00a3\13\13\3\13\3\13\3\13\3\13")
+ buf.write("\7\13\u00a9\n\13\f\13\16\13\u00ac\13\13\3\13\3\13\5\13")
+ buf.write("\u00b0\n\13\3\f\5\f\u00b3\n\f\3\f\7\f\u00b6\n\f\f\f\16")
+ buf.write("\f\u00b9\13\f\3\f\5\f\u00bc\n\f\3\f\3\f\3\f\5\f\u00c1")
+ buf.write("\n\f\3\r\3\r\5\r\u00c5\n\r\3\16\3\16\3\16\5\16\u00ca\n")
+ buf.write("\16\3\17\3\17\3\20\3\20\3\20\5\20\u00d1\n\20\3\20\5\20")
+ buf.write("\u00d4\n\20\3\21\3\21\3\21\3\21\5\21\u00da\n\21\3\22\3")
+ buf.write("\22\3\23\3\23\3\23\3\23\3\23\5\23\u00e3\n\23\3\24\3\24")
+ buf.write("\3\24\3\24\3\24\3\25\3\25\3\25\3\25\3\25\3\26\5\26\u00f0")
+ buf.write("\n\26\3\26\7\26\u00f3\n\26\f\26\16\26\u00f6\13\26\3\26")
+ buf.write("\3\26\3\26\3\26\7\26\u00fc\n\26\f\26\16\26\u00ff\13\26")
+ buf.write("\3\26\3\26\5\26\u0103\n\26\3\27\5\27\u0106\n\27\3\27\7")
+ buf.write("\27\u0109\n\27\f\27\16\27\u010c\13\27\3\27\3\27\3\27\5")
+ buf.write("\27\u0111\n\27\3\30\5\30\u0114\n\30\3\30\7\30\u0117\n")
+ buf.write("\30\f\30\16\30\u011a\13\30\3\30\3\30\3\30\3\30\7\30\u0120")
+ buf.write("\n\30\f\30\16\30\u0123\13\30\3\30\3\30\5\30\u0127\n\30")
+ buf.write("\3\31\3\31\5\31\u012b\n\31\3\32\5\32\u012e\n\32\3\32\7")
+ buf.write("\32\u0131\n\32\f\32\16\32\u0134\13\32\3\32\3\32\3\32\5")
+ buf.write("\32\u0139\n\32\3\32\5\32\u013c\n\32\3\33\3\33\5\33\u0140")
+ buf.write("\n\33\3\33\2\2\34\2\4\6\b\n\f\16\20\22\24\26\30\32\34")
+ buf.write("\36 \"$&(*,.\60\62\64\2\2\2\u0160\2\66\3\2\2\2\4=\3\2")
+ buf.write("\2\2\6D\3\2\2\2\bK\3\2\2\2\n\\\3\2\2\2\f_\3\2\2\2\16{")
+ buf.write("\3\2\2\2\20~\3\2\2\2\22\u0099\3\2\2\2\24\u009c\3\2\2\2")
+ buf.write("\26\u00b2\3\2\2\2\30\u00c4\3\2\2\2\32\u00c6\3\2\2\2\34")
+ buf.write("\u00cb\3\2\2\2\36\u00cd\3\2\2\2 \u00d9\3\2\2\2\"\u00db")
+ buf.write("\3\2\2\2$\u00e2\3\2\2\2&\u00e4\3\2\2\2(\u00e9\3\2\2\2")
+ buf.write("*\u00ef\3\2\2\2,\u0105\3\2\2\2.\u0113\3\2\2\2\60\u012a")
+ buf.write("\3\2\2\2\62\u012d\3\2\2\2\64\u013f\3\2\2\2\66:\5\4\3\2")
+ buf.write("\679\5\n\6\28\67\3\2\2\29<\3\2\2\2:8\3\2\2\2:;\3\2\2\2")
+ buf.write(";\3\3\2\2\2<:\3\2\2\2=A\5\b\5\2>@\5\6\4\2?>\3\2\2\2@C")
+ buf.write("\3\2\2\2A?\3\2\2\2AB\3\2\2\2B\5\3\2\2\2CA\3\2\2\2DE\7")
+ buf.write("\3\2\2EF\7\"\2\2FH\7#\2\2GI\7\4\2\2HG\3\2\2\2HI\3\2\2")
+ buf.write("\2I\7\3\2\2\2JL\7$\2\2KJ\3\2\2\2KL\3\2\2\2LP\3\2\2\2M")
+ buf.write("O\5\34\17\2NM\3\2\2\2OR\3\2\2\2PN\3\2\2\2PQ\3\2\2\2QS")
+ buf.write("\3\2\2\2RP\3\2\2\2ST\7\5\2\2TU\7\"\2\2UW\7#\2\2VX\7\4")
+ buf.write("\2\2WV\3\2\2\2WX\3\2\2\2X\t\3\2\2\2Y]\5\f\7\2Z]\5*\26")
+ buf.write("\2[]\5.\30\2\\Y\3\2\2\2\\Z\3\2\2\2\\[\3\2\2\2]\13\3\2")
+ buf.write("\2\2^`\7$\2\2_^\3\2\2\2_`\3\2\2\2`d\3\2\2\2ac\5\34\17")
+ buf.write("\2ba\3\2\2\2cf\3\2\2\2db\3\2\2\2de\3\2\2\2eg\3\2\2\2f")
+ buf.write("d\3\2\2\2gh\7\6\2\2hk\7\"\2\2ij\7\7\2\2jl\7\"\2\2ki\3")
+ buf.write("\2\2\2kl\3\2\2\2lm\3\2\2\2mq\7\b\2\2np\5\16\b\2on\3\2")
+ buf.write("\2\2ps\3\2\2\2qo\3\2\2\2qr\3\2\2\2rt\3\2\2\2sq\3\2\2\2")
+ buf.write("tv\7\t\2\2uw\7\4\2\2vu\3\2\2\2vw\3\2\2\2w\r\3\2\2\2x|")
+ buf.write("\5\20\t\2y|\5\26\f\2z|\5\24\13\2{x\3\2\2\2{y\3\2\2\2{")
+ buf.write("z\3\2\2\2|\17\3\2\2\2}\177\7$\2\2~}\3\2\2\2~\177\3\2\2")
+ buf.write("\2\177\u0083\3\2\2\2\u0080\u0082\5\34\17\2\u0081\u0080")
+ buf.write("\3\2\2\2\u0082\u0085\3\2\2\2\u0083\u0081\3\2\2\2\u0083")
+ buf.write("\u0084\3\2\2\2\u0084\u0088\3\2\2\2\u0085\u0083\3\2\2\2")
+ buf.write("\u0086\u0089\5 \21\2\u0087\u0089\7\n\2\2\u0088\u0086\3")
+ buf.write("\2\2\2\u0088\u0087\3\2\2\2\u0089\u008a\3\2\2\2\u008a\u008b")
+ buf.write("\7\"\2\2\u008b\u008f\7\13\2\2\u008c\u008e\5\32\16\2\u008d")
+ buf.write("\u008c\3\2\2\2\u008e\u0091\3\2\2\2\u008f\u008d\3\2\2\2")
+ buf.write("\u008f\u0090\3\2\2\2\u0090\u0092\3\2\2\2\u0091\u008f\3")
+ buf.write("\2\2\2\u0092\u0094\7\f\2\2\u0093\u0095\5\22\n\2\u0094")
+ buf.write("\u0093\3\2\2\2\u0094\u0095\3\2\2\2\u0095\u0097\3\2\2\2")
+ buf.write("\u0096\u0098\7\4\2\2\u0097\u0096\3\2\2\2\u0097\u0098\3")
+ buf.write("\2\2\2\u0098\21\3\2\2\2\u0099\u009a\7\r\2\2\u009a\23\3")
+ buf.write("\2\2\2\u009b\u009d\7$\2\2\u009c\u009b\3\2\2\2\u009c\u009d")
+ buf.write("\3\2\2\2\u009d\u00a1\3\2\2\2\u009e\u00a0\5\34\17\2\u009f")
+ buf.write("\u009e\3\2\2\2\u00a0\u00a3\3\2\2\2\u00a1\u009f\3\2\2\2")
+ buf.write("\u00a1\u00a2\3\2\2\2\u00a2\u00a4\3\2\2\2\u00a3\u00a1\3")
+ buf.write("\2\2\2\u00a4\u00a5\7\16\2\2\u00a5\u00a6\7\"\2\2\u00a6")
+ buf.write("\u00aa\7\13\2\2\u00a7\u00a9\5\32\16\2\u00a8\u00a7\3\2")
+ buf.write("\2\2\u00a9\u00ac\3\2\2\2\u00aa\u00a8\3\2\2\2\u00aa\u00ab")
+ buf.write("\3\2\2\2\u00ab\u00ad\3\2\2\2\u00ac\u00aa\3\2\2\2\u00ad")
+ buf.write("\u00af\7\f\2\2\u00ae\u00b0\7\4\2\2\u00af\u00ae\3\2\2\2")
+ buf.write("\u00af\u00b0\3\2\2\2\u00b0\25\3\2\2\2\u00b1\u00b3\7$\2")
+ buf.write("\2\u00b2\u00b1\3\2\2\2\u00b2\u00b3\3\2\2\2\u00b3\u00b7")
+ buf.write("\3\2\2\2\u00b4\u00b6\5\34\17\2\u00b5\u00b4\3\2\2\2\u00b6")
+ buf.write("\u00b9\3\2\2\2\u00b7\u00b5\3\2\2\2\u00b7\u00b8\3\2\2\2")
+ buf.write("\u00b8\u00bb\3\2\2\2\u00b9\u00b7\3\2\2\2\u00ba\u00bc\5")
+ buf.write("\30\r\2\u00bb\u00ba\3\2\2\2\u00bb\u00bc\3\2\2\2\u00bc")
+ buf.write("\u00bd\3\2\2\2\u00bd\u00be\5 \21\2\u00be\u00c0\7\"\2\2")
+ buf.write("\u00bf\u00c1\7\4\2\2\u00c0\u00bf\3\2\2\2\u00c0\u00c1\3")
+ buf.write("\2\2\2\u00c1\27\3\2\2\2\u00c2\u00c5\7\17\2\2\u00c3\u00c5")
+ buf.write("\7\r\2\2\u00c4\u00c2\3\2\2\2\u00c4\u00c3\3\2\2\2\u00c5")
+ buf.write("\31\3\2\2\2\u00c6\u00c7\5 \21\2\u00c7\u00c9\7\"\2\2\u00c8")
+ buf.write("\u00ca\7\20\2\2\u00c9\u00c8\3\2\2\2\u00c9\u00ca\3\2\2")
+ buf.write("\2\u00ca\33\3\2\2\2\u00cb\u00cc\7\36\2\2\u00cc\35\3\2")
+ buf.write("\2\2\u00cd\u00d0\7\"\2\2\u00ce\u00cf\7\21\2\2\u00cf\u00d1")
+ buf.write("\7\"\2\2\u00d0\u00ce\3\2\2\2\u00d0\u00d1\3\2\2\2\u00d1")
+ buf.write("\u00d3\3\2\2\2\u00d2\u00d4\7\20\2\2\u00d3\u00d2\3\2\2")
+ buf.write("\2\u00d3\u00d4\3\2\2\2\u00d4\37\3\2\2\2\u00d5\u00da\5")
+ buf.write("$\23\2\u00d6\u00da\5\"\22\2\u00d7\u00da\5&\24\2\u00d8")
+ buf.write("\u00da\5(\25\2\u00d9\u00d5\3\2\2\2\u00d9\u00d6\3\2\2\2")
+ buf.write("\u00d9\u00d7\3\2\2\2\u00d9\u00d8\3\2\2\2\u00da!\3\2\2")
+ buf.write("\2\u00db\u00dc\7\"\2\2\u00dc#\3\2\2\2\u00dd\u00e3\7\22")
+ buf.write("\2\2\u00de\u00e3\7\23\2\2\u00df\u00e3\7\24\2\2\u00e0\u00e3")
+ buf.write("\7\25\2\2\u00e1\u00e3\7\26\2\2\u00e2\u00dd\3\2\2\2\u00e2")
+ buf.write("\u00de\3\2\2\2\u00e2\u00df\3\2\2\2\u00e2\u00e0\3\2\2\2")
+ buf.write("\u00e2\u00e1\3\2\2\2\u00e3%\3\2\2\2\u00e4\u00e5\7\27\2")
+ buf.write("\2\u00e5\u00e6\7\30\2\2\u00e6\u00e7\5 \21\2\u00e7\u00e8")
+ buf.write("\7\31\2\2\u00e8\'\3\2\2\2\u00e9\u00ea\7\32\2\2\u00ea\u00eb")
+ buf.write("\7\30\2\2\u00eb\u00ec\5 \21\2\u00ec\u00ed\7\31\2\2\u00ed")
+ buf.write(")\3\2\2\2\u00ee\u00f0\7$\2\2\u00ef\u00ee\3\2\2\2\u00ef")
+ buf.write("\u00f0\3\2\2\2\u00f0\u00f4\3\2\2\2\u00f1\u00f3\5\34\17")
+ buf.write("\2\u00f2\u00f1\3\2\2\2\u00f3\u00f6\3\2\2\2\u00f4\u00f2")
+ buf.write("\3\2\2\2\u00f4\u00f5\3\2\2\2\u00f5\u00f7\3\2\2\2\u00f6")
+ buf.write("\u00f4\3\2\2\2\u00f7\u00f8\7\33\2\2\u00f8\u00f9\7\"\2")
+ buf.write("\2\u00f9\u00fd\7\b\2\2\u00fa\u00fc\5,\27\2\u00fb\u00fa")
+ buf.write("\3\2\2\2\u00fc\u00ff\3\2\2\2\u00fd\u00fb\3\2\2\2\u00fd")
+ buf.write("\u00fe\3\2\2\2\u00fe\u0100\3\2\2\2\u00ff\u00fd\3\2\2\2")
+ buf.write("\u0100\u0102\7\t\2\2\u0101\u0103\7\4\2\2\u0102\u0101\3")
+ buf.write("\2\2\2\u0102\u0103\3\2\2\2\u0103+\3\2\2\2\u0104\u0106")
+ buf.write("\7$\2\2\u0105\u0104\3\2\2\2\u0105\u0106\3\2\2\2\u0106")
+ buf.write("\u010a\3\2\2\2\u0107\u0109\5\34\17\2\u0108\u0107\3\2\2")
+ buf.write("\2\u0109\u010c\3\2\2\2\u010a\u0108\3\2\2\2\u010a\u010b")
+ buf.write("\3\2\2\2\u010b\u010d\3\2\2\2\u010c\u010a\3\2\2\2\u010d")
+ buf.write("\u010e\5 \21\2\u010e\u0110\7\"\2\2\u010f\u0111\7\4\2\2")
+ buf.write("\u0110\u010f\3\2\2\2\u0110\u0111\3\2\2\2\u0111-\3\2\2")
+ buf.write("\2\u0112\u0114\7$\2\2\u0113\u0112\3\2\2\2\u0113\u0114")
+ buf.write("\3\2\2\2\u0114\u0118\3\2\2\2\u0115\u0117\5\34\17\2\u0116")
+ buf.write("\u0115\3\2\2\2\u0117\u011a\3\2\2\2\u0118\u0116\3\2\2\2")
+ buf.write("\u0118\u0119\3\2\2\2\u0119\u011b\3\2\2\2\u011a\u0118\3")
+ buf.write("\2\2\2\u011b\u011c\5\60\31\2\u011c\u011d\7\"\2\2\u011d")
+ buf.write("\u0121\7\b\2\2\u011e\u0120\5\62\32\2\u011f\u011e\3\2\2")
+ buf.write("\2\u0120\u0123\3\2\2\2\u0121\u011f\3\2\2\2\u0121\u0122")
+ buf.write("\3\2\2\2\u0122\u0124\3\2\2\2\u0123\u0121\3\2\2\2\u0124")
+ buf.write("\u0126\7\t\2\2\u0125\u0127\7\4\2\2\u0126\u0125\3\2\2\2")
+ buf.write("\u0126\u0127\3\2\2\2\u0127/\3\2\2\2\u0128\u012b\7\34\2")
+ buf.write("\2\u0129\u012b\7\35\2\2\u012a\u0128\3\2\2\2\u012a\u0129")
+ buf.write("\3\2\2\2\u012b\61\3\2\2\2\u012c\u012e\7$\2\2\u012d\u012c")
+ buf.write("\3\2\2\2\u012d\u012e\3\2\2\2\u012e\u0132\3\2\2\2\u012f")
+ buf.write("\u0131\5\34\17\2\u0130\u012f\3\2\2\2\u0131\u0134\3\2\2")
+ buf.write("\2\u0132\u0130\3\2\2\2\u0132\u0133\3\2\2\2\u0133\u0135")
+ buf.write("\3\2\2\2\u0134\u0132\3\2\2\2\u0135\u0138\7\"\2\2\u0136")
+ buf.write("\u0137\7\21\2\2\u0137\u0139\5\64\33\2\u0138\u0136\3\2")
+ buf.write("\2\2\u0138\u0139\3\2\2\2\u0139\u013b\3\2\2\2\u013a\u013c")
+ buf.write("\7\20\2\2\u013b\u013a\3\2\2\2\u013b\u013c\3\2\2\2\u013c")
+ buf.write("\63\3\2\2\2\u013d\u0140\7\37\2\2\u013e\u0140\7 \2\2\u013f")
+ buf.write("\u013d\3\2\2\2\u013f\u013e\3\2\2\2\u0140\65\3\2\2\2\64")
+ buf.write(":AHKPW\\_dkqv{~\u0083\u0088\u008f\u0094\u0097\u009c\u00a1")
+ buf.write("\u00aa\u00af\u00b2\u00b7\u00bb\u00c0\u00c4\u00c9\u00d0")
+ buf.write("\u00d3\u00d9\u00e2\u00ef\u00f4\u00fd\u0102\u0105\u010a")
+ buf.write("\u0110\u0113\u0118\u0121\u0126\u012a\u012d\u0132\u0138")
+ buf.write("\u013b\u013f")
return buf.getvalue()
@@ -160,10 +172,10 @@ class TParser ( Parser ):
sharedContextCache = PredictionContextCache()
literalNames = [ "<INVALID>", "'import'", "';'", "'module'", "'interface'",
- "'{'", "'}'", "'void'", "'('", "')'", "'signal'", "'readonly'",
- "','", "'='", "'bool'", "'int'", "'real'", "'string'",
- "'var'", "'list'", "'<'", "'>'", "'model'", "'struct'",
- "'enum'", "'flag'" ]
+ "'extends'", "'{'", "'}'", "'void'", "'('", "')'",
+ "'const'", "'signal'", "'readonly'", "','", "'='",
+ "'bool'", "'int'", "'real'", "'string'", "'var'", "'list'",
+ "'<'", "'>'", "'model'", "'struct'", "'enum'", "'flag'" ]
symbolicNames = [ "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>",
"<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>",
@@ -171,9 +183,10 @@ class TParser ( Parser ):
"<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>",
"<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>",
"<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>",
- "<INVALID>", "<INVALID>", "TAGLINE", "INTCONSTANT",
- "HEXCONSTANT", "TAGIDENTIFIER", "IDENTIFIER", "VERSION",
- "DOCCOMMENT", "WHITESPACE", "COMMENT", "MULTICOMM" ]
+ "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>",
+ "TAGLINE", "INTCONSTANT", "HEXCONSTANT", "TAGIDENTIFIER",
+ "IDENTIFIER", "VERSION", "DOCCOMMENT", "WHITESPACE",
+ "COMMENT", "MULTICOMM" ]
RULE_documentSymbol = 0
RULE_headerSymbol = 1
@@ -183,30 +196,32 @@ class TParser ( Parser ):
RULE_interfaceSymbol = 5
RULE_interfaceMemberSymbol = 6
RULE_operationSymbol = 7
- RULE_signalSymbol = 8
- RULE_propertySymbol = 9
- RULE_operationParameterSymbol = 10
- RULE_tagSymbol = 11
- RULE_tagAttributeSymbol = 12
- RULE_typeSymbol = 13
- RULE_complexTypeSymbol = 14
- RULE_primitiveTypeSymbol = 15
- RULE_listTypeSymbol = 16
- RULE_modelTypeSymbol = 17
- RULE_structSymbol = 18
- RULE_structFieldSymbol = 19
- RULE_enumSymbol = 20
- RULE_enumTypeSymbol = 21
- RULE_enumMemberSymbol = 22
- RULE_intSymbol = 23
+ RULE_operationModifierSymbol = 8
+ RULE_signalSymbol = 9
+ RULE_propertySymbol = 10
+ RULE_propertyModifierSymbol = 11
+ RULE_operationParameterSymbol = 12
+ RULE_tagSymbol = 13
+ RULE_tagAttributeSymbol = 14
+ RULE_typeSymbol = 15
+ RULE_complexTypeSymbol = 16
+ RULE_primitiveTypeSymbol = 17
+ RULE_listTypeSymbol = 18
+ RULE_modelTypeSymbol = 19
+ RULE_structSymbol = 20
+ RULE_structFieldSymbol = 21
+ RULE_enumSymbol = 22
+ RULE_enumTypeSymbol = 23
+ RULE_enumMemberSymbol = 24
+ RULE_intSymbol = 25
ruleNames = [ "documentSymbol", "headerSymbol", "importSymbol", "moduleSymbol",
"definitionSymbol", "interfaceSymbol", "interfaceMemberSymbol",
- "operationSymbol", "signalSymbol", "propertySymbol",
- "operationParameterSymbol", "tagSymbol", "tagAttributeSymbol",
- "typeSymbol", "complexTypeSymbol", "primitiveTypeSymbol",
- "listTypeSymbol", "modelTypeSymbol", "structSymbol",
- "structFieldSymbol", "enumSymbol", "enumTypeSymbol",
+ "operationSymbol", "operationModifierSymbol", "signalSymbol",
+ "propertySymbol", "propertyModifierSymbol", "operationParameterSymbol",
+ "tagSymbol", "tagAttributeSymbol", "typeSymbol", "complexTypeSymbol",
+ "primitiveTypeSymbol", "listTypeSymbol", "modelTypeSymbol",
+ "structSymbol", "structFieldSymbol", "enumSymbol", "enumTypeSymbol",
"enumMemberSymbol", "intSymbol" ]
EOF = Token.EOF
@@ -235,20 +250,22 @@ class TParser ( Parser ):
T__22=23
T__23=24
T__24=25
- TAGLINE=26
- INTCONSTANT=27
- HEXCONSTANT=28
- TAGIDENTIFIER=29
- IDENTIFIER=30
- VERSION=31
- DOCCOMMENT=32
- WHITESPACE=33
- COMMENT=34
- MULTICOMM=35
-
- def __init__(self, input:TokenStream):
- super().__init__(input)
- self.checkVersion("4.6")
+ T__25=26
+ T__26=27
+ TAGLINE=28
+ INTCONSTANT=29
+ HEXCONSTANT=30
+ TAGIDENTIFIER=31
+ IDENTIFIER=32
+ VERSION=33
+ DOCCOMMENT=34
+ WHITESPACE=35
+ COMMENT=36
+ MULTICOMM=37
+
+ def __init__(self, input:TokenStream, output:TextIO = sys.stdout):
+ super().__init__(input, output)
+ self.checkVersion("4.7")
self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache)
self._predicates = None
@@ -298,15 +315,15 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 48
- self.headerSymbol()
self.state = 52
+ self.headerSymbol()
+ self.state = 56
self._errHandler.sync(self)
_la = self._input.LA(1)
- while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__3) | (1 << TParser.T__22) | (1 << TParser.T__23) | (1 << TParser.T__24) | (1 << TParser.TAGLINE) | (1 << TParser.DOCCOMMENT))) != 0):
- self.state = 49
+ while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__3) | (1 << TParser.T__24) | (1 << TParser.T__25) | (1 << TParser.T__26) | (1 << TParser.TAGLINE) | (1 << TParser.DOCCOMMENT))) != 0):
+ self.state = 53
self.definitionSymbol()
- self.state = 54
+ self.state = 58
self._errHandler.sync(self)
_la = self._input.LA(1)
@@ -362,15 +379,15 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 55
- self.moduleSymbol()
self.state = 59
+ self.moduleSymbol()
+ self.state = 63
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.T__0:
- self.state = 56
+ self.state = 60
self.importSymbol()
- self.state = 61
+ self.state = 65
self._errHandler.sync(self)
_la = self._input.LA(1)
@@ -423,17 +440,17 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 62
+ self.state = 66
self.match(TParser.T__0)
- self.state = 63
+ self.state = 67
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 64
+ self.state = 68
localctx.version = self.match(TParser.VERSION)
- self.state = 66
+ self.state = 70
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 65
+ self.state = 69
self.match(TParser.T__1)
@@ -497,35 +514,35 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 69
+ self.state = 73
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 68
+ self.state = 72
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 74
+ self.state = 78
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 71
+ self.state = 75
self.tagSymbol()
- self.state = 76
+ self.state = 80
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 77
+ self.state = 81
self.match(TParser.T__2)
- self.state = 78
+ self.state = 82
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 79
+ self.state = 83
localctx.version = self.match(TParser.VERSION)
- self.state = 81
+ self.state = 85
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 80
+ self.state = 84
self.match(TParser.T__1)
@@ -580,24 +597,24 @@ class TParser ( Parser ):
localctx = TParser.DefinitionSymbolContext(self, self._ctx, self.state)
self.enterRule(localctx, 8, self.RULE_definitionSymbol)
try:
- self.state = 86
+ self.state = 90
self._errHandler.sync(self)
la_ = self._interp.adaptivePredict(self._input,6,self._ctx)
if la_ == 1:
self.enterOuterAlt(localctx, 1)
- self.state = 83
+ self.state = 87
self.interfaceSymbol()
pass
elif la_ == 2:
self.enterOuterAlt(localctx, 2)
- self.state = 84
+ self.state = 88
self.structSymbol()
pass
elif la_ == 3:
self.enterOuterAlt(localctx, 3)
- self.state = 85
+ self.state = 89
self.enumSymbol()
pass
@@ -617,9 +634,13 @@ class TParser ( Parser ):
self.parser = parser
self.comment = None # Token
self.name = None # Token
+ self.extends = None # Token
- def IDENTIFIER(self):
- return self.getToken(TParser.IDENTIFIER, 0)
+ def IDENTIFIER(self, i:int=None):
+ if i is None:
+ return self.getTokens(TParser.IDENTIFIER)
+ else:
+ return self.getToken(TParser.IDENTIFIER, i)
def tagSymbol(self, i:int=None):
if i is None:
@@ -665,47 +686,57 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 89
+ self.state = 93
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 88
+ self.state = 92
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 94
+ self.state = 98
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 91
+ self.state = 95
self.tagSymbol()
- self.state = 96
+ self.state = 100
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 97
+ self.state = 101
self.match(TParser.T__3)
- self.state = 98
+ self.state = 102
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 99
- self.match(TParser.T__4)
- self.state = 103
+ self.state = 105
self._errHandler.sync(self)
_la = self._input.LA(1)
- while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__6) | (1 << TParser.T__9) | (1 << TParser.T__10) | (1 << TParser.T__13) | (1 << TParser.T__14) | (1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__18) | (1 << TParser.T__21) | (1 << TParser.TAGLINE) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0):
- self.state = 100
+ if _la==TParser.T__4:
+ self.state = 103
+ self.match(TParser.T__4)
+ self.state = 104
+ localctx.extends = self.match(TParser.IDENTIFIER)
+
+
+ self.state = 107
+ self.match(TParser.T__5)
+ self.state = 111
+ self._errHandler.sync(self)
+ _la = self._input.LA(1)
+ while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__7) | (1 << TParser.T__10) | (1 << TParser.T__11) | (1 << TParser.T__12) | (1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__18) | (1 << TParser.T__19) | (1 << TParser.T__20) | (1 << TParser.T__23) | (1 << TParser.TAGLINE) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0):
+ self.state = 108
self.interfaceMemberSymbol()
- self.state = 105
+ self.state = 113
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 106
- self.match(TParser.T__5)
- self.state = 108
+ self.state = 114
+ self.match(TParser.T__6)
+ self.state = 116
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 107
+ self.state = 115
self.match(TParser.T__1)
@@ -760,24 +791,24 @@ class TParser ( Parser ):
localctx = TParser.InterfaceMemberSymbolContext(self, self._ctx, self.state)
self.enterRule(localctx, 12, self.RULE_interfaceMemberSymbol)
try:
- self.state = 113
+ self.state = 121
self._errHandler.sync(self)
- la_ = self._interp.adaptivePredict(self._input,11,self._ctx)
+ la_ = self._interp.adaptivePredict(self._input,12,self._ctx)
if la_ == 1:
self.enterOuterAlt(localctx, 1)
- self.state = 110
+ self.state = 118
self.operationSymbol()
pass
elif la_ == 2:
self.enterOuterAlt(localctx, 2)
- self.state = 111
+ self.state = 119
self.propertySymbol()
pass
elif la_ == 3:
self.enterOuterAlt(localctx, 3)
- self.state = 112
+ self.state = 120
self.signalSymbol()
pass
@@ -819,6 +850,10 @@ class TParser ( Parser ):
return self.getTypedRuleContext(TParser.OperationParameterSymbolContext,i)
+ def operationModifierSymbol(self):
+ return self.getTypedRuleContext(TParser.OperationModifierSymbolContext,0)
+
+
def DOCCOMMENT(self):
return self.getToken(TParser.DOCCOMMENT, 0)
@@ -849,59 +884,67 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 116
+ self.state = 124
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 115
+ self.state = 123
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 121
+ self.state = 129
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 118
+ self.state = 126
self.tagSymbol()
- self.state = 123
+ self.state = 131
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 126
+ self.state = 134
self._errHandler.sync(self)
token = self._input.LA(1)
- if token in [TParser.T__13, TParser.T__14, TParser.T__15, TParser.T__16, TParser.T__17, TParser.T__18, TParser.T__21, TParser.IDENTIFIER]:
- self.state = 124
+ if token in [TParser.T__15, TParser.T__16, TParser.T__17, TParser.T__18, TParser.T__19, TParser.T__20, TParser.T__23, TParser.IDENTIFIER]:
+ self.state = 132
self.typeSymbol()
pass
- elif token in [TParser.T__6]:
- self.state = 125
- self.match(TParser.T__6)
+ elif token in [TParser.T__7]:
+ self.state = 133
+ self.match(TParser.T__7)
pass
else:
raise NoViableAltException(self)
- self.state = 128
+ self.state = 136
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 129
- self.match(TParser.T__7)
- self.state = 133
+ self.state = 137
+ self.match(TParser.T__8)
+ self.state = 141
self._errHandler.sync(self)
_la = self._input.LA(1)
- while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__13) | (1 << TParser.T__14) | (1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__18) | (1 << TParser.T__21) | (1 << TParser.IDENTIFIER))) != 0):
- self.state = 130
+ while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__18) | (1 << TParser.T__19) | (1 << TParser.T__20) | (1 << TParser.T__23) | (1 << TParser.IDENTIFIER))) != 0):
+ self.state = 138
self.operationParameterSymbol()
- self.state = 135
+ self.state = 143
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 136
- self.match(TParser.T__8)
- self.state = 138
+ self.state = 144
+ self.match(TParser.T__9)
+ self.state = 146
+ self._errHandler.sync(self)
+ la_ = self._interp.adaptivePredict(self._input,17,self._ctx)
+ if la_ == 1:
+ self.state = 145
+ self.operationModifierSymbol()
+
+
+ self.state = 149
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 137
+ self.state = 148
self.match(TParser.T__1)
@@ -913,6 +956,50 @@ class TParser ( Parser ):
self.exitRule()
return localctx
+ class OperationModifierSymbolContext(ParserRuleContext):
+
+ def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1):
+ super().__init__(parent, invokingState)
+ self.parser = parser
+ self.is_const = None # Token
+
+
+ def getRuleIndex(self):
+ return TParser.RULE_operationModifierSymbol
+
+ def enterRule(self, listener:ParseTreeListener):
+ if hasattr( listener, "enterOperationModifierSymbol" ):
+ listener.enterOperationModifierSymbol(self)
+
+ def exitRule(self, listener:ParseTreeListener):
+ if hasattr( listener, "exitOperationModifierSymbol" ):
+ listener.exitOperationModifierSymbol(self)
+
+ def accept(self, visitor:ParseTreeVisitor):
+ if hasattr( visitor, "visitOperationModifierSymbol" ):
+ return visitor.visitOperationModifierSymbol(self)
+ else:
+ return visitor.visitChildren(self)
+
+
+
+
+ def operationModifierSymbol(self):
+
+ localctx = TParser.OperationModifierSymbolContext(self, self._ctx, self.state)
+ self.enterRule(localctx, 16, self.RULE_operationModifierSymbol)
+ try:
+ self.enterOuterAlt(localctx, 1)
+ self.state = 151
+ localctx.is_const = self.match(TParser.T__10)
+ except RecognitionException as re:
+ localctx.exception = re
+ self._errHandler.reportError(self, re)
+ self._errHandler.recover(self, re)
+ finally:
+ self.exitRule()
+ return localctx
+
class SignalSymbolContext(ParserRuleContext):
def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1):
@@ -964,51 +1051,51 @@ class TParser ( Parser ):
def signalSymbol(self):
localctx = TParser.SignalSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 16, self.RULE_signalSymbol)
+ self.enterRule(localctx, 18, self.RULE_signalSymbol)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 141
+ self.state = 154
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 140
+ self.state = 153
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 146
+ self.state = 159
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 143
+ self.state = 156
self.tagSymbol()
- self.state = 148
+ self.state = 161
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 149
- self.match(TParser.T__9)
- self.state = 150
+ self.state = 162
+ self.match(TParser.T__11)
+ self.state = 163
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 151
- self.match(TParser.T__7)
- self.state = 155
+ self.state = 164
+ self.match(TParser.T__8)
+ self.state = 168
self._errHandler.sync(self)
_la = self._input.LA(1)
- while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__13) | (1 << TParser.T__14) | (1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__18) | (1 << TParser.T__21) | (1 << TParser.IDENTIFIER))) != 0):
- self.state = 152
+ while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__18) | (1 << TParser.T__19) | (1 << TParser.T__20) | (1 << TParser.T__23) | (1 << TParser.IDENTIFIER))) != 0):
+ self.state = 165
self.operationParameterSymbol()
- self.state = 157
+ self.state = 170
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 158
- self.match(TParser.T__8)
- self.state = 160
+ self.state = 171
+ self.match(TParser.T__9)
+ self.state = 173
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 159
+ self.state = 172
self.match(TParser.T__1)
@@ -1026,7 +1113,6 @@ class TParser ( Parser ):
super().__init__(parent, invokingState)
self.parser = parser
self.comment = None # Token
- self.isReadOnly = None # Token
self.name = None # Token
def typeSymbol(self):
@@ -1043,6 +1129,10 @@ class TParser ( Parser ):
return self.getTypedRuleContext(TParser.TagSymbolContext,i)
+ def propertyModifierSymbol(self):
+ return self.getTypedRuleContext(TParser.PropertyModifierSymbolContext,0)
+
+
def DOCCOMMENT(self):
return self.getToken(TParser.DOCCOMMENT, 0)
@@ -1069,45 +1159,45 @@ class TParser ( Parser ):
def propertySymbol(self):
localctx = TParser.PropertySymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 18, self.RULE_propertySymbol)
+ self.enterRule(localctx, 20, self.RULE_propertySymbol)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 163
+ self.state = 176
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 162
+ self.state = 175
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 168
+ self.state = 181
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 165
+ self.state = 178
self.tagSymbol()
- self.state = 170
+ self.state = 183
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 172
+ self.state = 185
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__10:
- self.state = 171
- localctx.isReadOnly = self.match(TParser.T__10)
+ if _la==TParser.T__10 or _la==TParser.T__12:
+ self.state = 184
+ self.propertyModifierSymbol()
- self.state = 174
+ self.state = 187
self.typeSymbol()
- self.state = 175
+ self.state = 188
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 177
+ self.state = 190
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 176
+ self.state = 189
self.match(TParser.T__1)
@@ -1119,6 +1209,64 @@ class TParser ( Parser ):
self.exitRule()
return localctx
+ class PropertyModifierSymbolContext(ParserRuleContext):
+
+ def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1):
+ super().__init__(parent, invokingState)
+ self.parser = parser
+ self.is_readonly = None # Token
+ self.is_const = None # Token
+
+
+ def getRuleIndex(self):
+ return TParser.RULE_propertyModifierSymbol
+
+ def enterRule(self, listener:ParseTreeListener):
+ if hasattr( listener, "enterPropertyModifierSymbol" ):
+ listener.enterPropertyModifierSymbol(self)
+
+ def exitRule(self, listener:ParseTreeListener):
+ if hasattr( listener, "exitPropertyModifierSymbol" ):
+ listener.exitPropertyModifierSymbol(self)
+
+ def accept(self, visitor:ParseTreeVisitor):
+ if hasattr( visitor, "visitPropertyModifierSymbol" ):
+ return visitor.visitPropertyModifierSymbol(self)
+ else:
+ return visitor.visitChildren(self)
+
+
+
+
+ def propertyModifierSymbol(self):
+
+ localctx = TParser.PropertyModifierSymbolContext(self, self._ctx, self.state)
+ self.enterRule(localctx, 22, self.RULE_propertyModifierSymbol)
+ try:
+ self.state = 194
+ self._errHandler.sync(self)
+ token = self._input.LA(1)
+ if token in [TParser.T__12]:
+ self.enterOuterAlt(localctx, 1)
+ self.state = 192
+ localctx.is_readonly = self.match(TParser.T__12)
+ pass
+ elif token in [TParser.T__10]:
+ self.enterOuterAlt(localctx, 2)
+ self.state = 193
+ localctx.is_const = self.match(TParser.T__10)
+ pass
+ else:
+ raise NoViableAltException(self)
+
+ except RecognitionException as re:
+ localctx.exception = re
+ self._errHandler.reportError(self, re)
+ self._errHandler.recover(self, re)
+ finally:
+ self.exitRule()
+ return localctx
+
class OperationParameterSymbolContext(ParserRuleContext):
def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1):
@@ -1156,20 +1304,20 @@ class TParser ( Parser ):
def operationParameterSymbol(self):
localctx = TParser.OperationParameterSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 20, self.RULE_operationParameterSymbol)
+ self.enterRule(localctx, 24, self.RULE_operationParameterSymbol)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 179
+ self.state = 196
self.typeSymbol()
- self.state = 180
+ self.state = 197
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 182
+ self.state = 199
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__11:
- self.state = 181
- self.match(TParser.T__11)
+ if _la==TParser.T__13:
+ self.state = 198
+ self.match(TParser.T__13)
except RecognitionException as re:
@@ -1213,10 +1361,10 @@ class TParser ( Parser ):
def tagSymbol(self):
localctx = TParser.TagSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 22, self.RULE_tagSymbol)
+ self.enterRule(localctx, 26, self.RULE_tagSymbol)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 184
+ self.state = 201
localctx.line = self.match(TParser.TAGLINE)
except RecognitionException as re:
localctx.exception = re
@@ -1263,28 +1411,28 @@ class TParser ( Parser ):
def tagAttributeSymbol(self):
localctx = TParser.TagAttributeSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 24, self.RULE_tagAttributeSymbol)
+ self.enterRule(localctx, 28, self.RULE_tagAttributeSymbol)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 186
+ self.state = 203
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 189
+ self.state = 206
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__12:
- self.state = 187
- self.match(TParser.T__12)
- self.state = 188
+ if _la==TParser.T__14:
+ self.state = 204
+ self.match(TParser.T__14)
+ self.state = 205
localctx.value = self.match(TParser.IDENTIFIER)
- self.state = 192
+ self.state = 209
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__11:
- self.state = 191
- self.match(TParser.T__11)
+ if _la==TParser.T__13:
+ self.state = 208
+ self.match(TParser.T__13)
except RecognitionException as re:
@@ -1340,29 +1488,29 @@ class TParser ( Parser ):
def typeSymbol(self):
localctx = TParser.TypeSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 26, self.RULE_typeSymbol)
+ self.enterRule(localctx, 30, self.RULE_typeSymbol)
try:
- self.state = 198
+ self.state = 215
self._errHandler.sync(self)
token = self._input.LA(1)
- if token in [TParser.T__13, TParser.T__14, TParser.T__15, TParser.T__16, TParser.T__17]:
+ if token in [TParser.T__15, TParser.T__16, TParser.T__17, TParser.T__18, TParser.T__19]:
self.enterOuterAlt(localctx, 1)
- self.state = 194
+ self.state = 211
self.primitiveTypeSymbol()
pass
elif token in [TParser.IDENTIFIER]:
self.enterOuterAlt(localctx, 2)
- self.state = 195
+ self.state = 212
self.complexTypeSymbol()
pass
- elif token in [TParser.T__18]:
+ elif token in [TParser.T__20]:
self.enterOuterAlt(localctx, 3)
- self.state = 196
+ self.state = 213
self.listTypeSymbol()
pass
- elif token in [TParser.T__21]:
+ elif token in [TParser.T__23]:
self.enterOuterAlt(localctx, 4)
- self.state = 197
+ self.state = 214
self.modelTypeSymbol()
pass
else:
@@ -1409,10 +1557,10 @@ class TParser ( Parser ):
def complexTypeSymbol(self):
localctx = TParser.ComplexTypeSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 28, self.RULE_complexTypeSymbol)
+ self.enterRule(localctx, 32, self.RULE_complexTypeSymbol)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 200
+ self.state = 217
localctx.name = self.match(TParser.IDENTIFIER)
except RecognitionException as re:
localctx.exception = re
@@ -1453,35 +1601,35 @@ class TParser ( Parser ):
def primitiveTypeSymbol(self):
localctx = TParser.PrimitiveTypeSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 30, self.RULE_primitiveTypeSymbol)
+ self.enterRule(localctx, 34, self.RULE_primitiveTypeSymbol)
try:
- self.state = 207
+ self.state = 224
self._errHandler.sync(self)
token = self._input.LA(1)
- if token in [TParser.T__13]:
+ if token in [TParser.T__15]:
self.enterOuterAlt(localctx, 1)
- self.state = 202
- localctx.name = self.match(TParser.T__13)
+ self.state = 219
+ localctx.name = self.match(TParser.T__15)
pass
- elif token in [TParser.T__14]:
+ elif token in [TParser.T__16]:
self.enterOuterAlt(localctx, 2)
- self.state = 203
- localctx.name = self.match(TParser.T__14)
+ self.state = 220
+ localctx.name = self.match(TParser.T__16)
pass
- elif token in [TParser.T__15]:
+ elif token in [TParser.T__17]:
self.enterOuterAlt(localctx, 3)
- self.state = 204
- localctx.name = self.match(TParser.T__15)
+ self.state = 221
+ localctx.name = self.match(TParser.T__17)
pass
- elif token in [TParser.T__16]:
+ elif token in [TParser.T__18]:
self.enterOuterAlt(localctx, 4)
- self.state = 205
- localctx.name = self.match(TParser.T__16)
+ self.state = 222
+ localctx.name = self.match(TParser.T__18)
pass
- elif token in [TParser.T__17]:
+ elif token in [TParser.T__19]:
self.enterOuterAlt(localctx, 5)
- self.state = 206
- localctx.name = self.match(TParser.T__17)
+ self.state = 223
+ localctx.name = self.match(TParser.T__19)
pass
else:
raise NoViableAltException(self)
@@ -1528,17 +1676,17 @@ class TParser ( Parser ):
def listTypeSymbol(self):
localctx = TParser.ListTypeSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 32, self.RULE_listTypeSymbol)
+ self.enterRule(localctx, 36, self.RULE_listTypeSymbol)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 209
- self.match(TParser.T__18)
- self.state = 210
- self.match(TParser.T__19)
- self.state = 211
- localctx.valueType = self.typeSymbol()
- self.state = 212
+ self.state = 226
self.match(TParser.T__20)
+ self.state = 227
+ self.match(TParser.T__21)
+ self.state = 228
+ localctx.valueType = self.typeSymbol()
+ self.state = 229
+ self.match(TParser.T__22)
except RecognitionException as re:
localctx.exception = re
self._errHandler.reportError(self, re)
@@ -1581,17 +1729,17 @@ class TParser ( Parser ):
def modelTypeSymbol(self):
localctx = TParser.ModelTypeSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 34, self.RULE_modelTypeSymbol)
+ self.enterRule(localctx, 38, self.RULE_modelTypeSymbol)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 214
+ self.state = 231
+ self.match(TParser.T__23)
+ self.state = 232
self.match(TParser.T__21)
- self.state = 215
- self.match(TParser.T__19)
- self.state = 216
+ self.state = 233
localctx.valueType = self.typeSymbol()
- self.state = 217
- self.match(TParser.T__20)
+ self.state = 234
+ self.match(TParser.T__22)
except RecognitionException as re:
localctx.exception = re
self._errHandler.reportError(self, re)
@@ -1651,51 +1799,51 @@ class TParser ( Parser ):
def structSymbol(self):
localctx = TParser.StructSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 36, self.RULE_structSymbol)
+ self.enterRule(localctx, 40, self.RULE_structSymbol)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 220
+ self.state = 237
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 219
+ self.state = 236
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 225
+ self.state = 242
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 222
+ self.state = 239
self.tagSymbol()
- self.state = 227
+ self.state = 244
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 228
- self.match(TParser.T__22)
- self.state = 229
+ self.state = 245
+ self.match(TParser.T__24)
+ self.state = 246
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 230
- self.match(TParser.T__4)
- self.state = 234
+ self.state = 247
+ self.match(TParser.T__5)
+ self.state = 251
self._errHandler.sync(self)
_la = self._input.LA(1)
- while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__13) | (1 << TParser.T__14) | (1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__18) | (1 << TParser.T__21) | (1 << TParser.TAGLINE) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0):
- self.state = 231
+ while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__18) | (1 << TParser.T__19) | (1 << TParser.T__20) | (1 << TParser.T__23) | (1 << TParser.TAGLINE) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0):
+ self.state = 248
self.structFieldSymbol()
- self.state = 236
+ self.state = 253
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 237
- self.match(TParser.T__5)
- self.state = 239
+ self.state = 254
+ self.match(TParser.T__6)
+ self.state = 256
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 238
+ self.state = 255
self.match(TParser.T__1)
@@ -1755,37 +1903,37 @@ class TParser ( Parser ):
def structFieldSymbol(self):
localctx = TParser.StructFieldSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 38, self.RULE_structFieldSymbol)
+ self.enterRule(localctx, 42, self.RULE_structFieldSymbol)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 242
+ self.state = 259
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 241
+ self.state = 258
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 247
+ self.state = 264
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 244
+ self.state = 261
self.tagSymbol()
- self.state = 249
+ self.state = 266
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 250
+ self.state = 267
self.typeSymbol()
- self.state = 251
+ self.state = 268
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 253
+ self.state = 270
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 252
+ self.state = 269
self.match(TParser.T__1)
@@ -1852,51 +2000,51 @@ class TParser ( Parser ):
def enumSymbol(self):
localctx = TParser.EnumSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 40, self.RULE_enumSymbol)
+ self.enterRule(localctx, 44, self.RULE_enumSymbol)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 256
+ self.state = 273
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 255
+ self.state = 272
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 261
+ self.state = 278
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 258
+ self.state = 275
self.tagSymbol()
- self.state = 263
+ self.state = 280
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 264
+ self.state = 281
self.enumTypeSymbol()
- self.state = 265
+ self.state = 282
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 266
- self.match(TParser.T__4)
- self.state = 270
+ self.state = 283
+ self.match(TParser.T__5)
+ self.state = 287
self._errHandler.sync(self)
_la = self._input.LA(1)
while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.TAGLINE) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0):
- self.state = 267
+ self.state = 284
self.enumMemberSymbol()
- self.state = 272
+ self.state = 289
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 273
- self.match(TParser.T__5)
- self.state = 275
+ self.state = 290
+ self.match(TParser.T__6)
+ self.state = 292
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 274
+ self.state = 291
self.match(TParser.T__1)
@@ -1940,20 +2088,20 @@ class TParser ( Parser ):
def enumTypeSymbol(self):
localctx = TParser.EnumTypeSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 42, self.RULE_enumTypeSymbol)
+ self.enterRule(localctx, 46, self.RULE_enumTypeSymbol)
try:
- self.state = 279
+ self.state = 296
self._errHandler.sync(self)
token = self._input.LA(1)
- if token in [TParser.T__23]:
+ if token in [TParser.T__25]:
self.enterOuterAlt(localctx, 1)
- self.state = 277
- localctx.isEnum = self.match(TParser.T__23)
+ self.state = 294
+ localctx.isEnum = self.match(TParser.T__25)
pass
- elif token in [TParser.T__24]:
+ elif token in [TParser.T__26]:
self.enterOuterAlt(localctx, 2)
- self.state = 278
- localctx.isFlag = self.match(TParser.T__24)
+ self.state = 295
+ localctx.isFlag = self.match(TParser.T__26)
pass
else:
raise NoViableAltException(self)
@@ -2014,46 +2162,46 @@ class TParser ( Parser ):
def enumMemberSymbol(self):
localctx = TParser.EnumMemberSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 44, self.RULE_enumMemberSymbol)
+ self.enterRule(localctx, 48, self.RULE_enumMemberSymbol)
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 282
+ self.state = 299
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 281
+ self.state = 298
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 287
+ self.state = 304
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 284
+ self.state = 301
self.tagSymbol()
- self.state = 289
+ self.state = 306
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 290
+ self.state = 307
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 293
+ self.state = 310
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__12:
- self.state = 291
- self.match(TParser.T__12)
- self.state = 292
+ if _la==TParser.T__14:
+ self.state = 308
+ self.match(TParser.T__14)
+ self.state = 309
self.intSymbol()
- self.state = 296
+ self.state = 313
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__11:
- self.state = 295
- self.match(TParser.T__11)
+ if _la==TParser.T__13:
+ self.state = 312
+ self.match(TParser.T__13)
except RecognitionException as re:
@@ -2100,19 +2248,19 @@ class TParser ( Parser ):
def intSymbol(self):
localctx = TParser.IntSymbolContext(self, self._ctx, self.state)
- self.enterRule(localctx, 46, self.RULE_intSymbol)
+ self.enterRule(localctx, 50, self.RULE_intSymbol)
try:
- self.state = 300
+ self.state = 317
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [TParser.INTCONSTANT]:
self.enterOuterAlt(localctx, 1)
- self.state = 298
+ self.state = 315
localctx.value = self.match(TParser.INTCONSTANT)
pass
elif token in [TParser.HEXCONSTANT]:
self.enterOuterAlt(localctx, 2)
- self.state = 299
+ self.state = 316
localctx.value = self.match(TParser.HEXCONSTANT)
pass
else:
diff --git a/qface/idl/parser/TVisitor.py b/qface/idl/parser/TVisitor.py
index 537146c..a87cdf4 100644
--- a/qface/idl/parser/TVisitor.py
+++ b/qface/idl/parser/TVisitor.py
@@ -1,4 +1,4 @@
-# Generated from T.g4 by ANTLR 4.6
+# Generated from T.g4 by ANTLR 4.7
from antlr4 import *
if __name__ is not None and "." in __name__:
from .TParser import TParser
@@ -49,6 +49,11 @@ class TVisitor(ParseTreeVisitor):
return self.visitChildren(ctx)
+ # Visit a parse tree produced by TParser#operationModifierSymbol.
+ def visitOperationModifierSymbol(self, ctx:TParser.OperationModifierSymbolContext):
+ return self.visitChildren(ctx)
+
+
# Visit a parse tree produced by TParser#signalSymbol.
def visitSignalSymbol(self, ctx:TParser.SignalSymbolContext):
return self.visitChildren(ctx)
@@ -59,6 +64,11 @@ class TVisitor(ParseTreeVisitor):
return self.visitChildren(ctx)
+ # Visit a parse tree produced by TParser#propertyModifierSymbol.
+ def visitPropertyModifierSymbol(self, ctx:TParser.PropertyModifierSymbolContext):
+ return self.visitChildren(ctx)
+
+
# Visit a parse tree produced by TParser#operationParameterSymbol.
def visitOperationParameterSymbol(self, ctx:TParser.OperationParameterSymbolContext):
return self.visitChildren(ctx)
diff --git a/qface/templates/qface/qtcpp.j2 b/qface/templates/qface/qtcpp.j2
new file mode 100644
index 0000000..97e1c8d
--- /dev/null
+++ b/qface/templates/qface/qtcpp.j2
@@ -0,0 +1,103 @@
+{%+ macro enum_decl(enum) -%}
+ enum {{enum}}Enum {
+ {% for member in enum.members %}
+ {{member.name}} = {{member.value}}{% if not loop.last %},{%endif%}
+
+ {% endfor %}
+ };
+ {% if enum.is_flag %}
+ Q_DECLARE_FLAGS({{enum}}Enums, {{enum}}Enum)
+ Q_FLAG({{enum}}Enum)
+ {% else %}
+ Q_ENUM({{enum}}Enum)
+ {% endif %}
+{%- endmacro %}
+
+{% macro property(property, notifiable=True) -%}
+Q_PROPERTY({{property|returnType}} {{property}} READ {{property}} {% if not property.readonly %}WRITE set{{property|upperfirst}}{% endif %}{% if not property.const and notifiable %} NOTIFY {{property}}Changed{% endif %})
+{%- endmacro %}
+
+{% macro property_setter_decl(property, ending=";") -%}
+void set{{property|upperfirst}}({{ property|parameterType }}){{ending}}
+{%- endmacro %}
+
+{% macro property_getter_decl(property, ending=";") -%}
+{{property|returnType}} {{property}}() const{{ending}}
+{%- endmacro %}
+
+{% macro signal_decl(symbol, postfix="") -%}
+void {{symbol}}{{postfix}}({{symbol|parameters}});
+{%- endmacro %}
+
+{% macro property_member_decl(property) -%}
+{{property|returnType}} m_{{property}};
+{%- endmacro %}
+
+{% macro property_setter_impl(class, property, notifiable=True) -%}
+/*!
+ \qmlproperty {{property.type}} {{class}}::{{property}}
+{% with doc = property.comment|parse_doc %}
+ \brief {{doc.brief}}
+
+ {{doc.description}}
+{% endwith %}
+*/
+
+void {{class}}::set{{property|upperfirst}}({{ property|parameterType }})
+{
+{% if notifiable %}
+ if (m_{{property}} != {{property}}) {
+ m_{{property}} = {{property}};
+ Q_EMIT {{property}}Changed({{property}});
+ }
+{% else %}
+ m_{{property}} = {{property}};
+{% endif %}
+
+}
+{%- endmacro %}
+
+
+{% macro property_getter_impl(class, property) -%}
+{{property|returnType}} {{class}}::{{property}}() const
+{
+ return m_{{property}};
+}
+{%- endmacro %}
+
+
+{% macro operation_impl(class, operation) -%}
+/*!
+ \qmlmethod {{operation.type}} {{class}}::{{operation}}({{operation|parameters}})
+{% with doc = operation.comment|parse_doc %}
+ \brief {{doc.brief}}
+ {{doc.description}}
+{% endwith %}
+*/
+{{operation|returnType}} {{class}}::{{operation}}({{operation|parameters}})
+{
+ {% for parameter in operation.parameters %}
+ Q_UNUSED({{parameter.name}});
+ {% endfor %}
+ qWarning() << "{{class}}::{{operation}}(...) not implemented";
+ return {{operation|defaultValue}};
+}
+{%- endmacro %}
+
+{% macro operation_decl(operation, ending=";") -%}
+ virtual {{operation|returnType}} {{operation}}({{operation|parameters}}){{ending}}
+{%- endmacro %}
+
+{% macro autogenerated(prefix="//") -%}
+
+{{prefix}} This is an auto-generated file.
+{{prefix}} Do not edit! All changes made to it will be lost.
+
+{%- endmacro %}
+
+{% macro preserved(prefix="//") -%}
+{{prefix}} This is a preserved file.
+{{prefix}} Changes will not be overriden by the generator.
+{{prefix}} To reset the file you need to delete it first.
+{%- endmacro %}
+
diff --git a/qface/watch.py b/qface/watch.py
index 9129bfa..9501f25 100644
--- a/qface/watch.py
+++ b/qface/watch.py
@@ -16,30 +16,32 @@ class RunScriptChangeHandler(FileSystemEventHandler):
self.is_running = False
def on_modified(self, event):
+ if event.is_directory:
+ return
self.run()
def run(self):
if self.is_running:
return
self.is_running = True
- sh(self.script, cwd=Path.getcwd())
+ sh(str(self.script), cwd=Path.getcwd())
self.is_running = False
-def monitor(script, src, dst):
+def monitor(script, src, dst, args):
"""
reloads the script given by argv when src files changes
"""
src = src if isinstance(src, (list, tuple)) else [src]
- script = '{0} {1} {2}'.format(script, ' '.join(src), dst)
+ dst = Path(dst).expand().abspath()
src = [Path(entry).expand().abspath() for entry in src]
- event_handler = RunScriptChangeHandler(script)
+ command = ' '.join(args)
+ print('command: ', command)
+ event_handler = RunScriptChangeHandler(command)
observer = Observer()
- path = Path(script).dirname().expand().abspath()
- click.secho('watch recursive: {0}'.format(path), fg='blue')
- observer.schedule(event_handler, path, recursive=True)
+ click.secho('watch recursive: {0}'.format(script.dirname()), fg='blue')
+ observer.schedule(event_handler, script.dirname(), recursive=True)
for entry in src:
- entry = entry.dirname().expand().abspath()
click.secho('watch recursive: {0}'.format(entry), fg='blue')
observer.schedule(event_handler, entry, recursive=True)
event_handler.run() # run always once
diff --git a/requirements.txt b/requirements.txt
index c0f6959..be67b91 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,5 @@
-antlr4-python3-runtime>=4.6
+antlr4-python3-runtime==4.7
+typing
jinja2
click
path.py
@@ -8,3 +9,5 @@ pyyaml
pytest
coverage
pytest-cov
+six
+coloredlogs
diff --git a/setup.py b/setup.py
index c9815a6..295c53e 100644
--- a/setup.py
+++ b/setup.py
@@ -32,27 +32,27 @@ setup(
url=__uri__,
author=__author__,
author_email=__author_email__,
- license='GPLV3',
+ license='MIT',
classifiers=[
- 'Development Status :: 4 - Beta',
+ 'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Topic :: Software Development :: Code Generators',
- 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
+ 'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.3',
- 'Programming Language :: Python :: 3.4',
- 'Programming Language :: Python :: 3.5',
],
keywords='qt code generator framework',
packages=find_packages(),
include_package_data=True,
install_requires=[
+ 'click',
+ 'antlr4-python3-runtime==4.7',
'jinja2',
'path.py',
'pyyaml',
- 'antlr4-python3-runtime>=4.6',
- 'click',
+ 'typing',
'watchdog',
+ 'six',
+ 'coloredlogs',
],
extras_require={
'dev': [
@@ -64,11 +64,5 @@ setup(
'watchdog',
'ipdb',
],
- },
- entry_points={
- 'console_scripts': [
- 'qface-qtcpp = qface.builtin.qtcpp.qtcpp:app',
- 'qface-qtqml = qface.builtin.qtqml.qtqml:app',
- ],
- },
+ }
)
diff --git a/tests/in/com.pelagicore.ivi.tuner.qface b/tests/in/com.pelagicore.ivi.tuner.qface
index c50a4c8..725d4d5 100644
--- a/tests/in/com.pelagicore.ivi.tuner.qface
+++ b/tests/in/com.pelagicore.ivi.tuner.qface
@@ -1,15 +1,25 @@
module com.pelagicore.ivi.tuner 1.0;
+
+interface BaseTuner {
+ int baseValue;
+}
+
+
/** Service Tuner */
@service: true
@interface: true
@config: {private: true, b: B, c: C}
@data: [1,2,3]
-interface Tuner {
+interface Tuner extends BaseTuner {
/** property currentStation */
readonly Station currentStation;
+ /** the default station, which never changes */
+ const Station defaultStation;
/** operation nextStation */
void nextStation();
+ /** operation numStations */
+ int numStations() const;
/** operation previousStation */
void previousStation();
/** operation updateCurrentStation */
@@ -22,6 +32,13 @@ interface Tuner {
signal scanFinished();
signal broadcastMessage(string message);
+
+ TunerExtension extension;
+
+ Feature feature;
+}
+
+interface TunerExtension {
}
/** enum State */
@@ -45,7 +62,7 @@ enum Waveband {
AM=1
}
-flag Features {
+flag Feature {
Mono = 0x1,
Stereo = 0x2,
}
diff --git a/tests/in/org.example.echo.qface b/tests/in/org.example.echo.qface
index 04a93ce..087f14f 100644
--- a/tests/in/org.example.echo.qface
+++ b/tests/in/org.example.echo.qface
@@ -10,6 +10,8 @@ module org.example.echo 1.0
* @see org.example
* @see http://qt.io
* @anything hello
+ *
+ * continued description
*/
interface Echo {
/**
diff --git a/tests/in/org.example.failing.qface b/tests/in/org.example.failing.qface
new file mode 100644
index 0000000..0fe3888
--- /dev/null
+++ b/tests/in/org.example.failing.qface
@@ -0,0 +1,5 @@
+module org.example 1.0
+
+interfase xx Failed {
+
+} \ No newline at end of file
diff --git a/tests/test_comments.py b/tests/test_comments.py
index 008dd0d..d2f18b6 100644
--- a/tests/test_comments.py
+++ b/tests/test_comments.py
@@ -35,8 +35,8 @@ def test_comment():
interface = system.lookup('org.example.echo.Echo')
assert interface
o = doc.parse_doc(interface.comment)
- assert o.brief == 'the brief'
- assert o.description == ['the description', 'continues {@link http://qt.io}']
+ assert o.brief == ['the brief']
+ assert o.description == ['the description', 'continues {@link http://qt.io}', 'continued description']
assert o.deprecated is True
assert o.see == ['org.example.echo.Echo', 'org.example', 'http://qt.io']
@@ -50,4 +50,4 @@ def test_qdoc_translate():
assert interface
doc.translate = qdoc_translate
o = doc.parse_doc(interface.comment)
- assert o.description == ['the description', 'continues \\link{http://qt.io}']
+ assert o.description == ['the description', 'continues \\link{http://qt.io}', 'continued description']
diff --git a/tests/test_generator.py b/tests/test_generator.py
index 21c483c..9aa6e71 100644
--- a/tests/test_generator.py
+++ b/tests/test_generator.py
@@ -29,14 +29,10 @@ def test_gen_module():
def test_gen_interface():
system = loadSystem()
gen = Generator(search_path='tests/templates')
- template = """
- {%- for interface in module.interfaces -%}
- {{interface}}
- {%- endfor -%}
- """
+ template = """{{module.interfaces|join(',')}}"""
module = system.lookup('com.pelagicore.ivi.tuner')
text = gen.apply(template, {"module": module})
- assert text == 'Tuner'
+ assert text == 'BaseTuner,Tuner,TunerExtension'
def test_parse_document():
@@ -71,5 +67,5 @@ def test_destination_prefix():
ctx = {'out': out.abspath(), 'module': module}
generator.write(dst_template, 'module.txt', ctx)
path = generator.apply(dst_template, ctx)
- assert Path(path).exists()
+ assert Path(path).exists() == True
out.rmtree_p()
diff --git a/tests/test_json.py b/tests/test_json.py
new file mode 100644
index 0000000..785680a
--- /dev/null
+++ b/tests/test_json.py
@@ -0,0 +1,54 @@
+from qface.generator import FileSystem
+import logging
+from path import Path
+import json
+
+# logging.config.fileConfig('logging.ini')
+logging.basicConfig()
+
+log = logging.getLogger(__name__)
+
+inputPath = Path('tests/in')
+
+
+def loadEcho():
+ path = inputPath / 'org.example.echo.qface'
+ return FileSystem.parse_document(path)
+
+
+def load_tuner():
+ path = inputPath / 'com.pelagicore.ivi.tuner.qface'
+ return FileSystem.parse_document(path)
+
+
+def test_echo_json():
+ system = loadEcho()
+ data = system.toJson()
+ text = json.dumps(data)
+ data = json.loads(text)
+ assert len(data['modules']) == 1
+ module = data['modules'][0]
+ assert module['name'] == 'org.example.echo'
+ assert module['version'] == '1.0'
+ assert len(module['interfaces']) == 1
+ interface = module['interfaces'][0]
+ assert interface['name'] == 'Echo'
+ assert len(interface['operations']) == 1
+ # string echo(string msg);
+ operation = interface['operations'][0]
+ assert operation['parameters'][0]['name'] == 'msg'
+ assert operation['parameters'][0]['type']['name'] == 'string'
+
+
+def test_tuner_json():
+ system = load_tuner()
+ data = system.toJson()
+ text = json.dumps(data)
+ data = json.loads(text)
+ module = data['modules'][0]
+ assert len(module['interfaces']) == 3
+ interface = module['interfaces'][0]
+ assert interface['name'] == 'BaseTuner'
+ interface = module['interfaces'][1]
+ assert interface['name'] == 'Tuner'
+
diff --git a/tests/test_parser.py b/tests/test_parser.py
index d94a96f..f6bcedb 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -1,8 +1,10 @@
import logging
import logging.config
+import pytest
from path import Path
from qface.generator import FileSystem
+import qface.idl.domain as domain
# logging.config.fileConfig('logging.ini')
logging.basicConfig()
@@ -52,9 +54,14 @@ def test_property():
assert property.type.name == 'Station'
assert property.module == module
assert property.type.qualified_name == 'com.pelagicore.ivi.tuner.Station'
- assert property.is_readonly
+ assert property.readonly
+ assert not property.const
assert property.comment == '/** property currentStation */'
+ property = interface._propertyMap['defaultStation']
+ assert not property.readonly
+ assert property.const
+
def test_operation():
system = load_tuner()
@@ -63,6 +70,10 @@ def test_operation():
assert operation
operation = interface._contentMap['previousStation']
assert operation
+ assert not operation.is_const
+ operation = interface._contentMap['numStations']
+ assert operation
+ assert operation.is_const
def test_signals():
@@ -98,6 +109,7 @@ def test_enum():
def test_enum_counter():
system = load_test()
enum = system.lookup('com.pelagicore.test.State')
+ assert type(enum) is domain.Enum
assert enum
assert enum._memberMap['Null'].value is 0
assert enum._memberMap['Failure'].value is 3
@@ -106,6 +118,7 @@ def test_enum_counter():
def test_flag_counter():
system = load_test()
flag = system.lookup('com.pelagicore.test.Phase')
+ assert type(flag) is domain.Enum
assert flag
assert flag._memberMap['PhaseOne'].value is 1
assert flag._memberMap['PhaseTwo'].value is 2
@@ -114,20 +127,30 @@ def test_flag_counter():
def test_flag():
system = load_tuner()
- symbol = system.lookup('com.pelagicore.ivi.tuner.Features')
+ symbol = system.lookup('com.pelagicore.ivi.tuner.Feature')
+ assert type(symbol) is domain.Enum
assert symbol.is_flag
+ assert not symbol.is_enum
+ symbol = system.lookup('com.pelagicore.ivi.tuner.Tuner#feature')
+ assert type(symbol) is domain.Property
+ assert type(symbol.type.reference) is domain.Enum
+
+ assert symbol.type.is_flag
+ assert symbol.type.is_enumeration
def test_list():
system = load_tuner()
interface = system.lookup('com.pelagicore.ivi.tuner.Tuner')
property = interface._propertyMap['primitiveList']
+ assert type(property) is domain.Property
assert property.type.name == 'list'
assert property.type.is_list is True
assert property.type.nested.is_primitive
assert property.type.nested.name == 'int'
property = interface._propertyMap['complexList']
+ assert type(property) is domain.Property
assert property.type.name == 'list'
assert property.type.is_list is True
assert property.type.nested.is_complex
@@ -138,13 +161,49 @@ def test_model():
system = load_tuner()
interface = system.lookup('com.pelagicore.ivi.tuner.Tuner')
property = interface._propertyMap['primitiveModel']
+ assert type(property) is domain.Property
assert property.type.name == 'model'
assert property.type.is_model is True
assert property.type.nested.is_primitive
assert property.type.nested.name == 'int'
property = interface._propertyMap['complexModel']
+ assert type(property) is domain.Property
assert property.type.name == 'model'
assert property.type.is_model is True
assert property.type.nested.is_complex
assert property.type.nested.name == 'Station'
+
+
+def test_extension():
+ system = load_tuner()
+ interface = system.lookup('com.pelagicore.ivi.tuner.Tuner')
+ extends = system.lookup('com.pelagicore.ivi.tuner.BaseTuner')
+ # import pdb; pdb.set_trace()
+ assert extends is interface.extends
+
+
+def test_interface_property():
+ system = load_tuner()
+ tuner = system.lookup('com.pelagicore.ivi.tuner.Tuner')
+ extension = system.lookup('com.pelagicore.ivi.tuner.TunerExtension')
+ prop = tuner._propertyMap['extension']
+ assert prop.type.is_interface
+ assert prop.type.reference is extension
+
+
+def test_symbol_kind():
+ system = load_tuner()
+ tuner = system.lookup('com.pelagicore.ivi.tuner.Tuner')
+ assert tuner.kind == 'interface'
+ property = system.lookup('com.pelagicore.ivi.tuner.Tuner#primitiveModel')
+ assert property.kind == 'property'
+
+
+def test_parser_exceptions():
+ path = inputPath / 'org.example.failing.qface'
+ system = FileSystem.parse_document(path)
+
+ system = FileSystem.parse_document('not-exists')
+
+
diff --git a/tests/test_qtcpp_helper.py b/tests/test_qtcpp_helper.py
index 535905a..b75a88a 100644
--- a/tests/test_qtcpp_helper.py
+++ b/tests/test_qtcpp_helper.py
@@ -23,6 +23,7 @@ interface Test {
void echo(string message);
Message message;
Status status;
+ ApplicationState state;
list<int> list001;
list<Message> list002;
model<int> model001;
@@ -38,6 +39,14 @@ enum Status {
ON,
OFF
}
+
+flag ApplicationState {
+ Suspended,
+ Hidden,
+ Inactive,
+ Active,
+}
+
"""
@@ -70,11 +79,11 @@ def test_return_type():
# check for struct
prop = interface._propertyMap['message']
answer = qtcpp.Filters.returnType(prop)
- assert answer == 'QmlMessage'
+ assert answer == 'Message'
# check for enum
prop = interface._propertyMap['status']
answer = qtcpp.Filters.returnType(prop)
- assert answer == 'QmlExampleModule::Status'
+ assert answer == 'Status::StatusEnum'
# check for list of primitive
prop = interface._propertyMap['list001']
@@ -89,12 +98,12 @@ def test_return_type():
# check for model of primitive
prop = interface._propertyMap['model001']
answer = qtcpp.Filters.returnType(prop)
- assert answer == 'QmlVariantModel *'
+ assert answer == 'VariantModel *'
# check for model of structs
prop = interface._propertyMap['model002']
answer = qtcpp.Filters.returnType(prop)
- assert answer == 'QmlMessageModel *'
+ assert answer == 'MessageModel *'
def test_default_value():
@@ -106,9 +115,9 @@ def test_default_value():
parameter = operation._parameterMap['message']
types = {
- 'bool': 'false',
- 'int': '0',
- 'real': '0.0',
+ 'bool': 'bool(false)',
+ 'int': 'int(0)',
+ 'real': 'qreal(0.0)',
'string': 'QString()',
'var': 'QVariant()'
}
@@ -121,11 +130,16 @@ def test_default_value():
# check for struct
prop = interface._propertyMap['message']
answer = qtcpp.Filters.defaultValue(prop)
- assert answer == 'QmlMessage()'
+ assert answer == 'Message()'
# check for enum
prop = interface._propertyMap['status']
answer = qtcpp.Filters.defaultValue(prop)
- assert answer == 'QmlExampleModule::ON'
+ assert answer == 'Status::StatusEnum::ON'
+
+ # check for flag
+ prop = interface._propertyMap['state']
+ answer = qtcpp.Filters.defaultValue(prop)
+ assert answer == '0'
# check for list of primitive
prop = interface._propertyMap['list001']
@@ -140,12 +154,12 @@ def test_default_value():
# check for model of primitive
prop = interface._propertyMap['model001']
answer = qtcpp.Filters.defaultValue(prop)
- assert answer == 'new QmlVariantModel(this)'
+ assert answer == 'new VariantModel(this)'
# check for model of structs
prop = interface._propertyMap['model002']
answer = qtcpp.Filters.defaultValue(prop)
- assert answer == 'new QmlMessageModel(this)'
+ assert answer == 'new MessageModel(this)'
def test_parameter_type():
@@ -173,11 +187,11 @@ def test_parameter_type():
# check for struct
prop = interface._propertyMap['message']
answer = qtcpp.Filters.parameterType(prop)
- assert answer == 'const QmlMessage &{0}'.format(prop.name)
+ assert answer == 'const Message &{0}'.format(prop.name)
# check for enum
prop = interface._propertyMap['status']
answer = qtcpp.Filters.parameterType(prop)
- assert answer == 'QmlExampleModule::Status {0}'.format(prop.name)
+ assert answer == 'Status::StatusEnum {0}'.format(prop.name)
# check for list of primitive
prop = interface._propertyMap['list001']
@@ -192,12 +206,12 @@ def test_parameter_type():
# check for model of primitive
prop = interface._propertyMap['model001']
answer = qtcpp.Filters.parameterType(prop)
- assert answer == 'QmlVariantModel *{0}'.format(prop.name)
+ assert answer == 'VariantModel *{0}'.format(prop.name)
# check for model of structs
prop = interface._propertyMap['model002']
answer = qtcpp.Filters.parameterType(prop)
- assert answer == 'QmlMessageModel *{0}'.format(prop.name)
+ assert answer == 'MessageModel *{0}'.format(prop.name)
def test_namespace():
@@ -205,10 +219,10 @@ def test_namespace():
module = system.lookup('org.example')
assert module
ns = qtcpp.Filters.open_ns(module)
- assert ns == 'namespace org { example {'
+ assert ns == 'namespace org { namespace example {'
ns = qtcpp.Filters.close_ns(module)
- assert ns == '} }'
+ assert ns == '} } // namespace org::example'
ns = qtcpp.Filters.using_ns(module)
- assert ns == 'using namespace org::example'
+ assert ns == 'using namespace org::example;'