summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuergen Bocklage-Ryannel <juergen@ryannel.org>2018-12-24 13:32:17 +0100
committerJuergen Bocklage-Ryannel <juergen@ryannel.org>2018-12-24 13:32:17 +0100
commitca2868a450c4090d5460827a896648280bb72eb0 (patch)
treee2bcb28bb3d8f3d3efc86bb1c064380cd5579e60
parent0a3ae7686e1100be452b8c435bdcd84ec242340e (diff)
parent7091420944250d11b2f5e9a1783a14e74480e8bc (diff)
downloadqtivi-qface-ca2868a450c4090d5460827a896648280bb72eb0.tar.gz
Merge branch 'release/2.0'2.0
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml4
-rw-r--r--docs/annotations.rst12
-rw-r--r--docs/builtin.rst4
-rw-r--r--docs/domain.rst4
-rw-r--r--docs/extending.rst6
-rw-r--r--docs/grammar.rst43
-rw-r--r--docs/index.rst11
-rw-r--r--docs/motivation.rst24
-rw-r--r--docs/script.rst40
-rw-r--r--docs/usage.rst8
-rw-r--r--qface/__about__.py6
-rw-r--r--qface/app.py68
-rw-r--r--qface/cli.py40
-rw-r--r--qface/filters.py72
-rw-r--r--qface/generator.py80
-rw-r--r--qface/helper/doc.py6
-rw-r--r--qface/helper/generic.py52
-rw-r--r--qface/helper/qtcpp.py44
-rw-r--r--qface/helper/qtqml.py12
-rw-r--r--qface/idl/domain.py3
-rw-r--r--qface/idl/listener.py20
-rw-r--r--qface/idl/parser/T.g413
-rw-r--r--qface/idl/parser/T.interp10
-rw-r--r--qface/idl/parser/T.tokens29
-rw-r--r--qface/idl/parser/TLexer.interp14
-rw-r--r--qface/idl/parser/TLexer.py301
-rw-r--r--qface/idl/parser/TLexer.tokens29
-rw-r--r--qface/idl/parser/TParser.py497
-rw-r--r--qface/idl/profile.py4
-rw-r--r--qface/shell.py8
-rw-r--r--qface/templates/qface/qtcpp.j239
-rw-r--r--qface/utils.py30
-rw-r--r--qface/watch.py26
-rw-r--r--setup.py7
-rw-r--r--tests/in/com.pelagicore.test.qface15
-rw-r--r--tests/in/values.qface13
-rw-r--r--tests/test_parser.py8
-rw-r--r--tests/test_values.py36
39 files changed, 1030 insertions, 609 deletions
diff --git a/.gitignore b/.gitignore
index ada7038..41976ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@ dist/*
.coverage
.vscode
+htmlcov
diff --git a/.travis.yml b/.travis.yml
index 8f76043..15c96ea 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,5 @@
language: python
python:
- - "3.5"
+ - "3.6"
install: "pip install -r requirements.txt"
-script: ./cli.py test_ci
+script: ./cli.py test-ci
diff --git a/docs/annotations.rst b/docs/annotations.rst
index 1092f6e..73436c8 100644
--- a/docs/annotations.rst
+++ b/docs/annotations.rst
@@ -2,10 +2,10 @@
Annotations
***********
-Annotations is a way to add meta information to your interface definition. It
+Annotations allow to add meta information to your interface definition. It
is available to each symbol in the interface.
-Annotations allows an interface author to extend the existing interface with additional meta information, called tags, aka annotations. One or several annotations can precede a module, ``interface``, ``struct`` or ``enum``. They are also allowed before an ``operation``, ``property`` or ``signal``. Everywhere where a documentation comment is allowed you can also add annotations.
+With annotations an interface author can extend the existing interface with additional meta information, called tags, aka annotations. One or several annotations can precede a module, ``interface``, ``struct`` or ``enum``. They are also allowed before an ``operation``, ``property`` or ``signal``. Everywhere where a documentation comment is allowed you can also add annotations.
An annotation looks like this
@@ -16,9 +16,9 @@ An annotation looks like this
}
-An in code annotation precedes a symbol and it starts with an ``@`` sign. A symbol can have more than one one annotation line. Each line should be one individual annotation. The content is YAML content. All ``@`` signs preceding a symbol are collected and then evaluated using a YAML parser.
+An embedded annotation precedes a symbol and it starts with an ``@`` sign. A symbol can have more than one annotation line. Each line should be one individual annotation. The content is YAML content. All ``@`` signs preceding a symbol are collected and then evaluated using a YAML parser.
-For larger annotations you can use the external annotation document feature.
+For larger annotations you can use the external annotation document feature (see below).
.. code-block:: python
@@ -63,12 +63,12 @@ On the root level should be a fully qualified name of a symbol. The symbol will
Merging Annotations
===================
-The external annotations will be merged on top of the embedded annotations on per symbol base. Dictionaries will be merged. If a merge can not be done then the external document based annotations will override the embedded annotations.
+The external annotations will be merged on top of the embedded annotations per symbol. Dictionaries will be merged. If a merge can not be done then the external document based annotations will override the embedded annotations.
Generators
==========
-The annotation are available later when navigating the domain model.
+Annotations are available later when navigating the domain model.
.. code-block:: jinja2
diff --git a/docs/builtin.rst b/docs/builtin.rst
index a24f424..b0a339b 100644
--- a/docs/builtin.rst
+++ b/docs/builtin.rst
@@ -1,7 +1,7 @@
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.
+QFace does provide some 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 general purpose generators.
`qface-qtcpp`_
@@ -22,7 +22,7 @@ QFace does provide soem real world generators which are hosted as separated proj
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.
+From the QML user interface perspective the QtCPP and QtQML generators both provide the same API and are interchangeable.
diff --git a/docs/domain.rst b/docs/domain.rst
index bf8f1c1..df27987 100644
--- a/docs/domain.rst
+++ b/docs/domain.rst
@@ -12,10 +12,10 @@ The IDL is converted into an in memory domain model (see qface/idl/domain.py)
- System
- Module
- Import
- - Service
+ - Interface
- Property
- Operation
- - Event
+ - Signal
- Enum
- Flag
- Struct
diff --git a/docs/extending.rst b/docs/extending.rst
index 910c086..faf4ccb 100644
--- a/docs/extending.rst
+++ b/docs/extending.rst
@@ -81,10 +81,12 @@ The rules document is divided into several targets. Each target can have an own
<target>:
<symbol>:
- context: {}
- destination: ''
+ context: { <key>: <value> }
+ destination: <path>
documents:
<target>:<source>
+ preserve:
+ <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
diff --git a/docs/grammar.rst b/docs/grammar.rst
index eb6546d..a4c2663 100644
--- a/docs/grammar.rst
+++ b/docs/grammar.rst
@@ -4,7 +4,7 @@ Grammar
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.
+The grammar of QFace is well defined and is based on the concept of modules as larger collections of information.
A module can have several interfaces, structs and/or enums/flags.
@@ -37,7 +37,7 @@ A QFace document always describes one module. Each document can contain one or m
Module
======
-A module is identified name. A module should be normally a URI where all parts are lowercase (e.g. `entertainment.tuner`). A module may import other modules with the primary purpose being to ensure that dependencies are declared inside the QFace file.
+A module is identified by its name. A module should be normally a URI where all parts are lowercase (e.g. `entertainment.tuner`). A module may import other modules with the primary purpose being to ensure that dependencies are declared inside the QFace file.
.. code-block:: js
@@ -50,7 +50,7 @@ A module is identified name. A module should be normally a URI where all parts a
Interface
=========
-An interface is a collection of properties, operation and signals. Properties carry data, whereas the operations normally modify the data. Signals are used to notify the user of changes.
+An interface is a collection of properties, operations and signals. Properties carry data, whereas the operations normally modify the data. Signals are used to notify the user of changes.
.. code-block:: js
@@ -60,7 +60,7 @@ 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.
+QFace allows to extend interfaces using the ``extends`` keyword after the interface name.
.. code-block:: js
@@ -75,12 +75,12 @@ QFace allows to extends interfaces using the ``extends`` keyword after the inter
.. 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.
+ For the sake of simplicity, as an API designer you should carefully evaluate if this is required. The typical way in QFace to allow extensions is normally to write your own code-generator and use type annotations.
.. code-block:: js
- @station
+ @extends: Station
interface WeatherStation {
real temperature;
}
@@ -139,7 +139,7 @@ The value assignment for the enum type is sequential beginning from 0. To specif
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.
+The flag type defines an enumeration type where different values are treated as a bit mask. The values are in the sequence of the 2^n.
.. code-block:: js
@@ -155,9 +155,9 @@ The flag type defines an enumeration type where these different values are treat
Types
=====
-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>``).
+Types are either local and can be referenced simply by their names, or they are from external modules. In the latter 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.
+A module consists 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.
@@ -234,14 +234,14 @@ A nested type is a complex type which nests another type. These are container ty
map<Station> stations
model<WeatherInfo> weather
-A list is an array of the provided value type. A map specifies only the value type. The key-type should be generic (e.g. a string type) and can be freely choosen by the generator. This allows for example the geenrator to add an id to each structure and use it as a key in the map.
+A list is an array of the provided value type. A map specifies only the value type. The key-type should be generic (e.g. a string type) and can be freely chosen by the generator. This allows for example the generator to add an id to each structure and use it as a key in the map.
-A model is a special type of a list, it defines the model type can stream the data (e.g. add/change/remove) and the changes should be reflected by a more advanced API. Also the data could in general grow unlimited and the generator should provide some form of pagination or window API. You should use a model if you expect the data it represents can grow in a way it may influence the performance of your API.
+A model is a special type of a list. It should be able to stream (e.g. add/change/remove) the data and the changes should be reflected by a more advanced API. Also the data could in general grow infinitely and the generator should provide some form of pagination or window API. You should use a model if you expect the data it represents to grow in a way that it may influence the performance of your API.
Annotations
===========
-Annotation allow the writer to add meta data to an interface document. It uses the `@` notation followed by valid YAML one line content.
+Annotations 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
@@ -268,3 +268,22 @@ Currently only brief, description, see and deprecated are supported doc tags.
The QtCPP built-in generator generates valid Qt documentation out of these comments.
+Default Values
+==============
+
+QFace supports the assignment of default values to properties and struct fields. A default values is a text string
+passed to the generator.
+
+.. code-block:: js
+
+ interface Counter {
+ int count = "0";
+ Message lastMessage;
+ }
+
+ struct Message {
+ string text = "NO DATA";
+ }
+
+You can use quotes `'` or double-quotes `"` as a marker for text. There is no type check on QFace side. The
+text-content is directly passed to the generator.
diff --git a/docs/index.rst b/docs/index.rst
index ed5f38a..12a05b7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -4,7 +4,7 @@ QFace
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.
+Several code generators for common use cases have already been implemented. These can be used as is or can be used as a base for a custom generator.
.. toctree::
:maxdepth: 1
@@ -18,13 +18,14 @@ There exists already several code generators for common use cases. These can be
json
domain
extending
+ script
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.
+The list fo features is plit between features which are based on the chosen IDL and features which are provided by the generator itself.
.. rubric:: IDL Features
@@ -47,7 +48,7 @@ The list fo features is plit between features which are based on the choosen IDL
Quick Start
===========
-QFace is a generator framework and is bundled with several reference code generator.
+QFace is a generator framework and is bundled with several reference code generators.
To install qface you need to have python3 installed and typically also pip3
@@ -73,7 +74,7 @@ and then
Custom Generator
----------------
-For your own generator you need several ingredients. A QFace interface file here called "sample.qface" a small script which loads and parses the document. And one or more template files, which generate the resulting code.
+For your own generator you need several ingredients. A QFace interface file (here called "sample.qface"), a small script which loads and parses the document (generator.py) and one or more template files, used by the script to generate the resulting code.
The QFace document could look like this
@@ -127,7 +128,7 @@ And a "org.example.txt" file named after the module should be generated.
Bundled Generators
------------------
-QFace has some gnerators which are bundled with the QFace library. They live in their own reposiutories. These generators are documented in the repositories.
+QFace has some generators which are bundled with the QFace library. They live in their own repositories. These generators are documented in their respective repositories.
.. rubric:: See Also
diff --git a/docs/motivation.rst b/docs/motivation.rst
index 2b54801..299c160 100644
--- a/docs/motivation.rst
+++ b/docs/motivation.rst
@@ -7,7 +7,7 @@ QFace is an attempt to establish one interface description language with an easy
The IDL
=======
-The IDL uses common API concept such as modules, interfaces, properties, structs and enums/flags. Additionally it knows about lists and models. A list is an array of primitive or complex types. A model is an indicator for large data sets which are typical used via a defined interface or via pagination.
+The IDL uses common API concept such as modules, interfaces, properties, structs and enums/flags. Additionally it knows about lists, maps and models. A list is an array of primitive or complex types. A map is an associative array of key/value pairs. A model is an indicator for large data sets which are typically used via a defined interface or via pagination.
.. code-block:: js
@@ -41,48 +41,48 @@ Complex Types
* Struct
* Enum
* Flag
-* Array
+* List
+* Map
* Model
-The language as such does not provide any support for maps or dictionaries. The reason for not providing a map container type is that keys in dictionaries requires a hash which can not always be guaranteed to be available in complex types.
Why another IDL
===============
-There exists many IDLs. Most of them are bound to a certain technology or library or are limited for a specific use. Only a few IDL exists which are independent from a technology. From these few which are known to the author none satisfied the requirement from the author to be Qt compatible and easy to use. Also the IDL should be easy to use and easy to be install and to be extendable. The unique mix of technologies used in QFace allows it to provide a solid stable IDL with a powerful generation framework.
+Many IDLs are already in existence. Most of them are bound to a certain technology or library or are limited for a specific use. Only a few IDLs exist which are independent from a technology. From these few which are known to the author none satisfied the requirement from the author to be Qt compatible and easy to use. Also the IDL should be easy to install and be extendable. The unique mix of technologies used in QFace allows it to provide a solid stable IDL with a powerful generation framework.
Defining APIs
=============
-There are many opinions how to define APIs and what is the best way. The porposal of QFace is that is many project find QFace useful and use the same IDL there will be a large set of generators and at the end APIs can be compared and unified also if they will be used with different technologies.
+There are many opinions how to define APIs and what the best way is. The idea of QFace is that many projects find it useful and use the same IDL. Consequently, there will be a large set of generators and finally APIs can be compared and unified also if they will be used with different technologies.
-Even inside on e technolgy there are often discussions about how an interface shall be coded. QFace allows the different parties to create their own generators based on the same API. Ideally at the end the knowledge how an interface shall be coded will reside in the provided generator.
+Even inside one technology there are often discussions about how an interface shall be coded. QFace allows the different parties to create their own generators based on the same API. Ideally at the end the knowledge how an interface shall be coded will reside in the provided generator.
Large Projects
==============
-In larger projects there is the need to make available to QML a large set of operating services. It is less about defining new visual items in C++, more about creating an abstraction of a service and make it available to the HMI developer inside QML.
+In larger projects there is the need to make a large set of operating services available to QML. It is less about defining new visual items in C++, more about creating an abstraction of a service and make it available to the HMI developer inside QML.
-This can be a challenge when you create many of these plugins and in the middle of the project you figure out you have issues with your current design. Or if the customer in the next project wants to use a different HMI technology. All the knowledge is inside these plugins.
+This can be a challenge when you create many of these plugins and in the middle of the project you figure out that you have issues with your current design or if the customer in the next project wants to use a different HMI technology. All the knowledge is inside these plugins.
With QFace these companies can be certain that QFace does not lock them into the HMI technology and smaller design issues can be fixed by fixing the generator.
Remote Services
===============
-Some projects use network communication to communicate from the HMI to the services, which might run on a different process or event networked device. QFace was not designed for remote services as it does not define any storage types (e.g. int32, int16, int64), it only knows an int and does not define how large the int shall be. For this QFace needs to rely on the author of the generators to have a defined protocol to exchange data.
+Some projects use network communication to communicate from the HMI to the services, which might run on a different process or even a networked device. QFace was not designed for remote services as it does not define any storage types (e.g. int32, int16, int64), it only knows an int and does not define how large the int shall be. For this QFace needs to rely on the author of the generators to have a defined protocol to exchange data.
Complex APIs
============
QFace is purposely designed to have limited features. The goal is to make QFace easy to use with an easy to remember syntax so that you don't need to be an expert to write interface files.
-QFace does not suppot unions or extending from other interfaces or that a struct extends other structs. If you look for these features than QFace is probably the wrong choice.
+QFace does not support unions or structs that extend other structs. If you look for these features, QFace is probably the wrong choice.
Limitations
===========
-Like other code generation tools, QFace is limited by how much information you can place inside your interface files. In such cases code generation might not make sense and QFace will also help.
+Like other code generation tools, QFace is limited by how much information you can place inside your interface files. In excessive cases code generation might not make sense and hence QFace will also not help.
-QFace allows you to use annotation which can add meta information to the interface files. But the generator needs to be designed to understand this meta information. Only the structure of these annotations are defined not the information they carry. Annotations might help to add information to an interface document to better control the code generation process.
+QFace allows you to use annotations which can add meta information to the interface files. But the generator needs to be designed to understand this meta information. Only the structure of these annotations are defined not the information they carry. Annotations might help to add information to an interface document to better control the code generation process.
diff --git a/docs/script.rst b/docs/script.rst
new file mode 100644
index 0000000..fb3def2
--- /dev/null
+++ b/docs/script.rst
@@ -0,0 +1,40 @@
+***********
+Script Mode
+***********
+
+In the script mode, qface is used as the qface exectuable. In this mode the code generator consits of a rule document and template files and optionally a filter module.
+
+Whereas normally the generator writer create an own python package in this module only some documents are needed and the qface script is used.
+
+Setup
+=====
+
+To get started create a `qface-rules.yml` document and a templates folder::
+
+ qface-rules.yml
+ templates/
+
+
+In the rules file you provide the code generation rules accoring to the rule generator documentation. The templates folder will contain the required templates.
+
+Filters
+=======
+
+To provide extra filder you need to create a `filters.py` document with the declaration of your filters::
+
+ def echo(s):
+ print(s)
+ return "World"
+
+ filters['echo'] = echo
+
+The filters module will be loaded by qface and all entries to the filters dictionary are added to the global lists of Jinja filters.
+
+Running
+=======
+
+To run now the generator you can simply call::
+
+ qface --rules qface-rules.yml --target out counter.qface
+
+This will take your rules and generate the files inside the out folder based on the `counter.qface` interface file.
diff --git a/docs/usage.rst b/docs/usage.rst
index 7105bfa..87216c7 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -9,7 +9,7 @@ QFace requires one or more IDL files as input file and a generator to produce ou
.. figure:: qface_concept.jpg
-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.
+To use QFace you need to write your own generator. A generator is a small python script which reads the QFace document and writes code using template files.
.. code-block:: python
@@ -51,13 +51,13 @@ The code generation is driven by a small script which iterates over the domain m
generator.write('{{output}}/modules.csv', 'modules.csv', ctx)
-This script reads the input directory returns a system object form the domain model. This is used as the root object for the code generation inside the template language.
+This script reads the input directory and returns a system object from the domain model. This is used as the root object for the code generation inside the template language.
.. code-block:: jinja
{% for module in system.modules %}
{%- for interface in module.interfaces -%}
- SERVICE, {{module}}.{{interface}}
+ INTERFACE, {{module}}.{{interface}}
{% endfor -%}
{%- for struct in module.structs -%}
STRUCT , {{module}}.{{struct}}
@@ -67,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 the output file. Using the generator write method ``generator.write(path, template, context)`` the output file path can be specified.
diff --git a/qface/__about__.py b/qface/__about__.py
index 2b8012d..0ed253d 100644
--- a/qface/__about__.py
+++ b/qface/__about__.py
@@ -9,7 +9,7 @@ except NameError:
__title__ = "qface"
__summary__ = "A generator framework based on a common modern IDL"
__url__ = "https://pelagicore.github.io/qface/"
-__version__ = "1.10"
+__version__ = "2.0.0"
__author__ = "JRyannel"
-__author_email__ = "qface-generator@googlegroups.com"
-__copyright__ = "2018 Pelagicore"
+__author_email__ = ""
+__copyright__ = "2019 Pelagicore"
diff --git a/qface/app.py b/qface/app.py
new file mode 100644
index 0000000..38a26d6
--- /dev/null
+++ b/qface/app.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python3
+# Copyright (c) Pelagicore AB 2016
+
+import sys
+import click
+import logging
+from path import Path
+from qface.generator import FileSystem, RuleGenerator
+from qface.watch import monitor
+from qface.utils import load_filters
+
+here = Path(__file__).dirname()
+logging.basicConfig()
+
+
+def run(spec, src, dst, features, force):
+ spec = Path(spec)
+ project = Path(dst).name
+ system = FileSystem.parse(src)
+
+ extra_filters_path = spec.dirname() / 'filters.py'
+ extra_filters = load_filters(extra_filters_path)
+
+ ctx = {
+ 'dst': dst,
+ 'system': system,
+ 'project': project,
+ }
+
+ generator = RuleGenerator(
+ search_path=spec.dirname() / 'templates',
+ destination=dst,
+ context=ctx,
+ features=features,
+ force=force
+ )
+ generator.filters = extra_filters
+ generator.process_rules(spec, system)
+
+
+@click.command()
+@click.option('--rules', type=click.Path(exists=True, file_okay=True))
+@click.option('--target', type=click.Path(exists=False, file_okay=False))
+@click.option('--reload/--no-reload', default=False, help="Auto reload script on changes")
+@click.option('--scaffold/--no-scaffold', default=False, help="Add extrac scaffolding code")
+@click.option('--watch', type=click.Path(exists=False, file_okay=False))
+@click.option('--feature', multiple=True)
+@click.option('--force/--no-force', default=False, help="forces overwriting of files")
+@click.argument('source', nargs=-1, type=click.Path(exists=True))
+def main(rules, target, reload, source, watch, scaffold, feature, force):
+ rules = Path(rules)
+ if reload:
+ argv = sys.argv.copy()
+ argv.remove('--reload')
+ watch_list = list(source)
+ watch_list.append(rules.dirname())
+ if watch:
+ watch_list.append(watch)
+ monitor(args=argv, watch=watch_list)
+ else:
+ features = set(feature)
+ if scaffold:
+ features.add('scaffold')
+ run(rules, source, target, features=features, force=force)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/qface/cli.py b/qface/cli.py
new file mode 100644
index 0000000..f0b06b0
--- /dev/null
+++ b/qface/cli.py
@@ -0,0 +1,40 @@
+import sys
+import click
+from path import Path
+from qface.generator import FileSystem, RuleGenerator
+from qface.watch import monitor
+
+
+def run(config, src, dst, force=False, features=None):
+ project = Path(dst).name
+ system = FileSystem.parse(src)
+ template_dir = config.dirname() / 'templates'
+
+ context = {
+ 'dst': dst,
+ 'system': system,
+ 'project': project,
+ 'features': features,
+ }
+
+ generator = RuleGenerator(template_dir, destination=dst, context=context, features=features, force=force)
+ generator.process_rules(config, system)
+
+
+@click.command()
+@click.option('--config', '-c', type=click.Path(exists=True))
+@click.option('--reload/--no-reload', default=False)
+@click.option('--features', '-f', multiple=True)
+@click.option('--force/--no-force', default=True, help="Force writing of target files, ignores preserve")
+@click.argument('src', nargs=-1, type=click.Path(exists=True))
+@click.argument('dst', nargs=1, type=click.Path(exists=False, file_okay=False))
+def app(config, src, dst, features, reload, force):
+ """Takes several files or directories as src and generates the code
+ in the given dst directory."""
+ config = Path(config)
+ if reload:
+ argv = sys.argv.copy()
+ argv.remove('--reload')
+ monitor(config.dirname(), src, dst, argv)
+ else:
+ run(config, src, dst, force)
diff --git a/qface/filters.py b/qface/filters.py
index de424a4..236c7b3 100644
--- a/qface/filters.py
+++ b/qface/filters.py
@@ -1,46 +1,28 @@
-import json
-import hashlib
+from .helper import generic
+from .helper import qtqml
+from .helper import qtcpp
+from .helper import doc
+import importlib.util
+
+
+def get_filters():
+ filters = {}
+ filters.update(generic.get_filters())
+ filters.update(qtqml.Filters.get_filters())
+ filters.update(qtcpp.Filters.get_filters())
+ filters.update(doc.get_filters())
+ return filters
+
+
+def load_filters(path):
+ if not path.exists():
+ print('filter module does not exist')
+ return {}
+
+ extra_filters = {}
+ spec = importlib.util.spec_from_file_location('filters', path.abspath())
+ filters_module = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(filters_module)
+ filters_module.get_filters(extra_filters)
+ return extra_filters
-
-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 91049ba..b4f93df 100644
--- a/qface/generator.py
+++ b/qface/generator.py
@@ -5,14 +5,15 @@ 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 import InputStream, FileStream, CommonTokenStream, ParseTreeWalker
from antlr4.error import DiagnosticErrorListener, ErrorListener
import shelve
import logging
import hashlib
import yaml
import click
-import sys, os
+import sys
+import os
from .idl.parser.TLexer import TLexer
from .idl.parser.TParser import TParser
@@ -20,8 +21,7 @@ from .idl.parser.TListener import TListener
from .idl.profile import EProfile
from .idl.domain import System
from .idl.listener import DomainListener
-from .utils import merge
-from .filters import filters
+from .filters import get_filters
from jinja2.debug import make_traceback as _make_traceback
@@ -33,6 +33,16 @@ except ImportError:
logger = logging.getLogger(__name__)
+def merge(a, b):
+ "merges b into a recursively if a and b are dicts"
+ for key in b:
+ if isinstance(a.get(key), dict) and isinstance(b.get(key), dict):
+ merge(a[key], b[key])
+ else:
+ a[key] = b[key]
+ return a
+
+
def template_error_handler(traceback):
exc_type, exc_obj, exc_tb = traceback.exc_info
error = exc_obj
@@ -73,7 +83,7 @@ class Generator(object):
strict = False
""" enables strict code generation """
- def __init__(self, search_path, context={}):
+ def __init__(self, search_path, context={}, force=False):
loader = ChoiceLoader([
FileSystemLoader(search_path),
PackageLoader('qface')
@@ -84,10 +94,12 @@ class Generator(object):
lstrip_blocks=True,
)
self.env.exception_handler = template_error_handler
- self.env.filters.update(filters)
+ self.env.filters.update(get_filters())
self._destination = Path()
+ self._path = Path()
self._source = ''
self.context = context
+ self.force = force
@property
def destination(self):
@@ -96,8 +108,21 @@ class Generator(object):
@destination.setter
def destination(self, dst):
- if dst:
- self._destination = Path(self.apply(dst, self.context))
+ self._destination = dst
+
+ @property
+ def resolved_path(self):
+ return self.destination / self.path
+
+ @property
+ def path(self):
+ return self._path
+
+ @path.setter
+ def path(self, path):
+ if not path:
+ return
+ self._path = Path(self.apply(path))
@property
def source(self):
@@ -136,7 +161,8 @@ class Generator(object):
template = self.get_template(name)
return template.render(context)
- def apply(self, template, context):
+ def apply(self, template, context={}):
+ context.update(self.context)
"""Return the rendered text of a template instance"""
return self.env.from_string(template).render(context)
@@ -144,6 +170,9 @@ class Generator(object):
"""Using a template file name it renders a template
into a file given a context
"""
+ if not file_path or not template:
+ click.secho('source or target missing for document')
+ return
if not context:
context = self.context
error = False
@@ -165,12 +194,13 @@ class Generator(object):
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))
+ force = self.force or force
+ path = self.resolved_path / 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) or force:
- if path.exists() and preserve:
+ if path.exists() and preserve and not force:
click.secho('preserve: {0}'.format(path), fg='blue')
else:
click.secho('create: {0}'.format(path), fg='blue')
@@ -190,14 +220,14 @@ class Generator(object):
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)
+ def __init__(self, search_path: str, destination:Path, context:dict={}, features:set=set(), force=False):
+ super().__init__(search_path, context, force)
self.context.update({
'dst': destination,
'project': Path(destination).name,
'features': features,
})
- self.destination = '{{dst}}'
+ self.destination = destination
self.features = features
def process_rules(self, path: Path, system: System):
@@ -216,7 +246,7 @@ class RuleGenerator(Generator):
if not self._shall_proceed(rules):
return
self.context.update(rules.get('context', {}))
- self.destination = rules.get('destination', '{{dst}}')
+ self.path = rules.get('path', '')
self.source = rules.get('source', None)
self._process_rule(rules.get('system', None), {'system': system})
for module in system.modules:
@@ -234,11 +264,13 @@ class RuleGenerator(Generator):
return
self.context.update(context)
self.context.update(rule.get('context', {}))
- self.destination = rule.get('destination', None)
+ self.path = rule.get('path', None)
self.source = rule.get('source', None)
- for target, source in rule.get('documents', {}).items():
+ for entry in rule.get('documents', []):
+ target, source = self._resolve_rule_document(entry)
self.write(target, source)
- for target, source in rule.get('preserve', {}).items():
+ for entry in rule.get('preserve', []):
+ target, source = self._resolve_rule_document(entry)
self.write(target, source, preserve=True)
def _shall_proceed(self, obj):
@@ -250,6 +282,11 @@ class RuleGenerator(Generator):
result = self.features.intersection(set(conditions))
return bool(len(result))
+ def _resolve_rule_document(self, entry):
+ if type(entry) is dict:
+ return next(iter(entry.items()))
+ return (entry, entry)
+
class FileSystem(object):
"""QFace helper functions to work with the file system"""
@@ -271,6 +308,11 @@ class FileSystem(object):
sys.exit(-1)
@staticmethod
+ def parse_text(text: str, system: System = None, profile=EProfile.FULL):
+ stream = InputStream(text)
+ return FileSystem._parse_stream(stream, system, "<TEXT>", profile)
+
+ @staticmethod
def _parse_document(document: Path, system: System = None, profile=EProfile.FULL):
"""Parses a document and returns the resulting domain system
@@ -284,7 +326,7 @@ class FileSystem(object):
return system
@staticmethod
- def _parse_stream(stream, system: System = None, document=None, profile=EProfile.FULL):
+ def _parse_stream(stream: InputStream, system: System = None, document=None, profile=EProfile.FULL):
logger.debug('parse stream')
system = system or System()
diff --git a/qface/helper/doc.py b/qface/helper/doc.py
index 2b1df51..2b99b57 100644
--- a/qface/helper/doc.py
+++ b/qface/helper/doc.py
@@ -83,3 +83,9 @@ def parse_doc(s):
else: # append any loose lines to description
doc.add_tag('description', line)
return doc
+
+
+def get_filters():
+ return {
+ 'parse_doc': parse_doc,
+ }
diff --git a/qface/helper/generic.py b/qface/helper/generic.py
new file mode 100644
index 0000000..713952d
--- /dev/null
+++ b/qface/helper/generic.py
@@ -0,0 +1,52 @@
+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('.', '/')
+
+
+def identifier(s):
+ return str(s).lower().replace('.', '_')
+
+
+def get_filters():
+ return {
+ 'jsonify': jsonify,
+ 'upper_first': upper_first,
+ 'lower_first': lower_first,
+ 'upperfirst': upper_first,
+ 'lowerfirst': lower_first,
+ 'hash': hash,
+ 'path': path,
+ 'identifier': identifier,
+ }
diff --git a/qface/helper/qtcpp.py b/qface/helper/qtcpp.py
index 2c64e74..c9e6835 100644
--- a/qface/helper/qtcpp.py
+++ b/qface/helper/qtcpp.py
@@ -3,7 +3,11 @@ Provides helper functionality specificially for Qt C++/QML code generators
"""
import qface.idl.domain as domain
from jinja2 import environmentfilter
-from ..filters import upper_first
+
+
+def upper_first(s):
+ s = str(s)
+ return s[0].upper() + s[1:]
class Filters(object):
@@ -32,7 +36,7 @@ class Filters(object):
return 'QVariant()'
elif t.is_void:
return ''
- elif t.is_enum:
+ elif t.is_enumeration:
value = next(iter(t.reference.members))
return '{0}::{0}Enum::{1}'.format(symbol.type, value)
elif symbol.kind == 'enum':
@@ -54,7 +58,7 @@ class Filters(object):
@staticmethod
def parameterType(symbol):
prefix = Filters.classPrefix
- if symbol.type.is_enum:
+ if symbol.type.is_enumeration:
return '{0}::{0}Enum {1}'.format(symbol.type, symbol)
if symbol.type.is_void or symbol.type.is_primitive:
if symbol.type.is_string:
@@ -84,7 +88,7 @@ class Filters(object):
def returnType(symbol):
prefix = Filters.classPrefix
t = symbol.type
- if t.is_enum:
+ if t.is_enumeration:
return '{0}::{0}Enum'.format(symbol.type)
if symbol.type.is_void or symbol.type.is_primitive:
if t.is_string:
@@ -234,20 +238,20 @@ class Filters(object):
@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,
+ 'qt.defaultValue': Filters.defaultValue,
+ 'qt.returnType': Filters.returnType,
+ 'qt.parameterType': Filters.parameterType,
+ 'qt.cpp_open_ns': Filters.open_ns,
+ 'qt.close_ns': Filters.close_ns,
+ 'qt.using_ns': Filters.using_ns,
+ 'qt.ns': Filters.ns,
+ 'qt.fqn': Filters.fqn,
+ 'qt.signalName': Filters.signalName,
+ 'qt.parameters': Filters.parameters,
+ 'qt.signature': Filters.signature,
+ 'qt.identifier': Filters.identifier,
+ 'qt.path': Filters.path,
+ 'qt.className': Filters.className,
+ 'qt.source_dependencies': Filters.source_dependencies,
+ 'qt.header_dependencies': Filters.header_dependencies,
}
diff --git a/qface/helper/qtqml.py b/qface/helper/qtqml.py
index e29311f..915607d 100644
--- a/qface/helper/qtqml.py
+++ b/qface/helper/qtqml.py
@@ -60,10 +60,10 @@ class Filters(object):
return t
@staticmethod
- def path(s):
- return str(s).replace('.', '/')
-
- @staticmethod
- def identifier(s):
- return str(s).lower().replace('.', '_')
+ def get_filters():
+ return {
+ 'qml.className': Filters.className,
+ 'qml.defaultValue': Filters.defaultValue,
+ 'qml.propertyType': Filters.propertyType,
+ }
diff --git a/qface/idl/domain.py b/qface/idl/domain.py
index ae2359b..7949e6c 100644
--- a/qface/idl/domain.py
+++ b/qface/idl/domain.py
@@ -126,7 +126,8 @@ class Symbol(NamedElement):
self.comment = ''
"""comment which appeared in QFace right before symbol"""
self._tags = dict()
-
+ """a value attached to the symbol"""
+ self.value = None
self._contentMap = ChainMap()
self._dependencies = set()
self.type = TypeSymbol('', self)
diff --git a/qface/idl/listener.py b/qface/idl/listener.py
index 5fafa4f..2d8bfb6 100644
--- a/qface/idl/listener.py
+++ b/qface/idl/listener.py
@@ -8,6 +8,8 @@ from antlr4 import ParserRuleContext
import yaml
import click
from .profile import get_features, EProfile, EFeature
+import codecs
+import json
try:
from yaml import CSafeLoader as Loader, CDumper as Dumper
@@ -21,6 +23,10 @@ log = logging.getLogger(__name__)
contextMap = {}
+def escape_decode(s):
+ """removes \-escapes from str"""
+ return codecs.decode(bytes(s, 'utf-8'), 'unicode_escape')
+
class QFaceListener(TListener):
def __init__(self, system, profile=EProfile.FULL):
super().__init__()
@@ -108,6 +114,11 @@ class DomainListener(QFaceListener):
except yaml.YAMLError as exc:
click.secho(str(exc), fg='red')
+ def parse_value(self, ctx, symbol):
+ self.check_support(EFeature.DEFAULT_VALUES)
+ if ctx.value:
+ symbol.value = escape_decode(ctx.value.text[1:-1])
+
def enterEveryRule(self, ctx):
log.debug('enter ' + ctx.__class__.__name__)
@@ -213,15 +224,9 @@ class DomainListener(QFaceListener):
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)
+ self.parse_value(ctx, self.property)
contextMap[ctx] = self.property
def exitPropertySymbol(self, ctx: TParser.PropertySymbolContext):
@@ -232,6 +237,7 @@ class DomainListener(QFaceListener):
name = ctx.name.text
self.field = Field(name, self.struct)
self.parse_annotations(ctx, self.field)
+ self.parse_value(ctx, self.field)
contextMap[ctx] = self.field
def exitStructFieldSymbol(self, ctx: TParser.StructFieldSymbolContext):
diff --git a/qface/idl/parser/T.g4 b/qface/idl/parser/T.g4
index 8d07623..2551937 100644
--- a/qface/idl/parser/T.g4
+++ b/qface/idl/parser/T.g4
@@ -7,8 +7,8 @@ documentSymbol
;
/**
-module name;
-import name;
+module <name> <version>;
+import <name> <version>;
*/
headerSymbol
: moduleSymbol importSymbol*
@@ -52,7 +52,7 @@ signalSymbol
propertySymbol
- : comment=DOCCOMMENT? tagSymbol* propertyModifierSymbol? typeSymbol name=IDENTIFIER ';'?
+ : comment=DOCCOMMENT? tagSymbol* propertyModifierSymbol? typeSymbol name=IDENTIFIER ('=' value=STRING)? ';'?
;
propertyModifierSymbol
@@ -109,7 +109,7 @@ structSymbol
;
structFieldSymbol
- : comment=DOCCOMMENT? tagSymbol* typeSymbol name=IDENTIFIER ';'?
+ : comment=DOCCOMMENT? tagSymbol* typeSymbol name=IDENTIFIER ('=' value=STRING)? ';'?
;
enumSymbol
@@ -130,6 +130,9 @@ intSymbol
| value=HEXCONSTANT
;
+STRING: DOUBLE_STRING | SINGLE_STRING;
+DOUBLE_STRING : '"' ( ESC | ~ ["\\] )* '"';
+SINGLE_STRING : '\'' ( ESC | ~ ['\\] )* '\'';
TAGLINE : '@' ~[\r\n]*;
INTCONSTANT : ('+' | '-')? '0'..'9'+;
HEXCONSTANT : '0x' ('0'..'9' | 'a'..'f' | 'A'..'F')+;
@@ -140,4 +143,4 @@ DOCCOMMENT : '/**' .*? '*/';
WHITESPACE : [ \t\r\n]+ -> skip;
COMMENT : '//' ~[\r\n]* -> skip;
MULTICOMM : '/*' .*? '*/' -> skip;
-
+fragment ESC : '\\' ( ["\\/bfnrt] );
diff --git a/qface/idl/parser/T.interp b/qface/idl/parser/T.interp
index 9047ec1..c9c8a03 100644
--- a/qface/idl/parser/T.interp
+++ b/qface/idl/parser/T.interp
@@ -12,9 +12,9 @@ null
')'
'const'
'signal'
+'='
'readonly'
','
-'='
'bool'
'int'
'real'
@@ -38,6 +38,9 @@ null
null
null
null
+null
+null
+null
token symbolic names:
null
@@ -69,6 +72,9 @@ null
null
null
null
+STRING
+DOUBLE_STRING
+SINGLE_STRING
TAGLINE
INTCONSTANT
HEXCONSTANT
@@ -111,4 +117,4 @@ intSymbol
atn:
-[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 40, 330, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 3, 2, 3, 2, 7, 2, 59, 10, 2, 12, 2, 14, 2, 62, 11, 2, 3, 3, 3, 3, 7, 3, 66, 10, 3, 12, 3, 14, 3, 69, 11, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 75, 10, 4, 3, 5, 5, 5, 78, 10, 5, 3, 5, 7, 5, 81, 10, 5, 12, 5, 14, 5, 84, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 90, 10, 5, 3, 6, 3, 6, 3, 6, 5, 6, 95, 10, 6, 3, 7, 5, 7, 98, 10, 7, 3, 7, 7, 7, 101, 10, 7, 12, 7, 14, 7, 104, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 110, 10, 7, 3, 7, 3, 7, 7, 7, 114, 10, 7, 12, 7, 14, 7, 117, 11, 7, 3, 7, 3, 7, 5, 7, 121, 10, 7, 3, 8, 3, 8, 3, 8, 5, 8, 126, 10, 8, 3, 9, 5, 9, 129, 10, 9, 3, 9, 7, 9, 132, 10, 9, 12, 9, 14, 9, 135, 11, 9, 3, 9, 3, 9, 5, 9, 139, 10, 9, 3, 9, 3, 9, 3, 9, 7, 9, 144, 10, 9, 12, 9, 14, 9, 147, 11, 9, 3, 9, 3, 9, 5, 9, 151, 10, 9, 3, 9, 5, 9, 154, 10, 9, 3, 10, 3, 10, 3, 11, 5, 11, 159, 10, 11, 3, 11, 7, 11, 162, 10, 11, 12, 11, 14, 11, 165, 11, 11, 3, 11, 3, 11, 3, 11, 3, 11, 7, 11, 171, 10, 11, 12, 11, 14, 11, 174, 11, 11, 3, 11, 3, 11, 5, 11, 178, 10, 11, 3, 12, 5, 12, 181, 10, 12, 3, 12, 7, 12, 184, 10, 12, 12, 12, 14, 12, 187, 11, 12, 3, 12, 5, 12, 190, 10, 12, 3, 12, 3, 12, 3, 12, 5, 12, 195, 10, 12, 3, 13, 3, 13, 5, 13, 199, 10, 13, 3, 14, 3, 14, 3, 14, 5, 14, 204, 10, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 5, 16, 211, 10, 16, 3, 16, 5, 16, 214, 10, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 5, 17, 221, 10, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 5, 19, 230, 10, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 5, 23, 248, 10, 23, 3, 23, 7, 23, 251, 10, 23, 12, 23, 14, 23, 254, 11, 23, 3, 23, 3, 23, 3, 23, 3, 23, 7, 23, 260, 10, 23, 12, 23, 14, 23, 263, 11, 23, 3, 23, 3, 23, 5, 23, 267, 10, 23, 3, 24, 5, 24, 270, 10, 24, 3, 24, 7, 24, 273, 10, 24, 12, 24, 14, 24, 276, 11, 24, 3, 24, 3, 24, 3, 24, 5, 24, 281, 10, 24, 3, 25, 5, 25, 284, 10, 25, 3, 25, 7, 25, 287, 10, 25, 12, 25, 14, 25, 290, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 7, 25, 296, 10, 25, 12, 25, 14, 25, 299, 11, 25, 3, 25, 3, 25, 5, 25, 303, 10, 25, 3, 26, 3, 26, 5, 26, 307, 10, 26, 3, 27, 5, 27, 310, 10, 27, 3, 27, 7, 27, 313, 10, 27, 12, 27, 14, 27, 316, 11, 27, 3, 27, 3, 27, 3, 27, 5, 27, 321, 10, 27, 3, 27, 5, 27, 324, 10, 27, 3, 28, 3, 28, 5, 28, 328, 10, 28, 3, 28, 2, 2, 29, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 2, 2, 2, 360, 2, 56, 3, 2, 2, 2, 4, 63, 3, 2, 2, 2, 6, 70, 3, 2, 2, 2, 8, 77, 3, 2, 2, 2, 10, 94, 3, 2, 2, 2, 12, 97, 3, 2, 2, 2, 14, 125, 3, 2, 2, 2, 16, 128, 3, 2, 2, 2, 18, 155, 3, 2, 2, 2, 20, 158, 3, 2, 2, 2, 22, 180, 3, 2, 2, 2, 24, 198, 3, 2, 2, 2, 26, 200, 3, 2, 2, 2, 28, 205, 3, 2, 2, 2, 30, 207, 3, 2, 2, 2, 32, 220, 3, 2, 2, 2, 34, 222, 3, 2, 2, 2, 36, 229, 3, 2, 2, 2, 38, 231, 3, 2, 2, 2, 40, 236, 3, 2, 2, 2, 42, 241, 3, 2, 2, 2, 44, 247, 3, 2, 2, 2, 46, 269, 3, 2, 2, 2, 48, 283, 3, 2, 2, 2, 50, 306, 3, 2, 2, 2, 52, 309, 3, 2, 2, 2, 54, 327, 3, 2, 2, 2, 56, 60, 5, 4, 3, 2, 57, 59, 5, 10, 6, 2, 58, 57, 3, 2, 2, 2, 59, 62, 3, 2, 2, 2, 60, 58, 3, 2, 2, 2, 60, 61, 3, 2, 2, 2, 61, 3, 3, 2, 2, 2, 62, 60, 3, 2, 2, 2, 63, 67, 5, 8, 5, 2, 64, 66, 5, 6, 4, 2, 65, 64, 3, 2, 2, 2, 66, 69, 3, 2, 2, 2, 67, 65, 3, 2, 2, 2, 67, 68, 3, 2, 2, 2, 68, 5, 3, 2, 2, 2, 69, 67, 3, 2, 2, 2, 70, 71, 7, 3, 2, 2, 71, 72, 7, 35, 2, 2, 72, 74, 7, 36, 2, 2, 73, 75, 7, 4, 2, 2, 74, 73, 3, 2, 2, 2, 74, 75, 3, 2, 2, 2, 75, 7, 3, 2, 2, 2, 76, 78, 7, 37, 2, 2, 77, 76, 3, 2, 2, 2, 77, 78, 3, 2, 2, 2, 78, 82, 3, 2, 2, 2, 79, 81, 5, 28, 15, 2, 80, 79, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 85, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 86, 7, 5, 2, 2, 86, 87, 7, 35, 2, 2, 87, 89, 7, 36, 2, 2, 88, 90, 7, 4, 2, 2, 89, 88, 3, 2, 2, 2, 89, 90, 3, 2, 2, 2, 90, 9, 3, 2, 2, 2, 91, 95, 5, 12, 7, 2, 92, 95, 5, 44, 23, 2, 93, 95, 5, 48, 25, 2, 94, 91, 3, 2, 2, 2, 94, 92, 3, 2, 2, 2, 94, 93, 3, 2, 2, 2, 95, 11, 3, 2, 2, 2, 96, 98, 7, 37, 2, 2, 97, 96, 3, 2, 2, 2, 97, 98, 3, 2, 2, 2, 98, 102, 3, 2, 2, 2, 99, 101, 5, 28, 15, 2, 100, 99, 3, 2, 2, 2, 101, 104, 3, 2, 2, 2, 102, 100, 3, 2, 2, 2, 102, 103, 3, 2, 2, 2, 103, 105, 3, 2, 2, 2, 104, 102, 3, 2, 2, 2, 105, 106, 7, 6, 2, 2, 106, 109, 7, 35, 2, 2, 107, 108, 7, 7, 2, 2, 108, 110, 7, 35, 2, 2, 109, 107, 3, 2, 2, 2, 109, 110, 3, 2, 2, 2, 110, 111, 3, 2, 2, 2, 111, 115, 7, 8, 2, 2, 112, 114, 5, 14, 8, 2, 113, 112, 3, 2, 2, 2, 114, 117, 3, 2, 2, 2, 115, 113, 3, 2, 2, 2, 115, 116, 3, 2, 2, 2, 116, 118, 3, 2, 2, 2, 117, 115, 3, 2, 2, 2, 118, 120, 7, 9, 2, 2, 119, 121, 7, 4, 2, 2, 120, 119, 3, 2, 2, 2, 120, 121, 3, 2, 2, 2, 121, 13, 3, 2, 2, 2, 122, 126, 5, 16, 9, 2, 123, 126, 5, 22, 12, 2, 124, 126, 5, 20, 11, 2, 125, 122, 3, 2, 2, 2, 125, 123, 3, 2, 2, 2, 125, 124, 3, 2, 2, 2, 126, 15, 3, 2, 2, 2, 127, 129, 7, 37, 2, 2, 128, 127, 3, 2, 2, 2, 128, 129, 3, 2, 2, 2, 129, 133, 3, 2, 2, 2, 130, 132, 5, 28, 15, 2, 131, 130, 3, 2, 2, 2, 132, 135, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 138, 3, 2, 2, 2, 135, 133, 3, 2, 2, 2, 136, 139, 5, 32, 17, 2, 137, 139, 7, 10, 2, 2, 138, 136, 3, 2, 2, 2, 138, 137, 3, 2, 2, 2, 139, 140, 3, 2, 2, 2, 140, 141, 7, 35, 2, 2, 141, 145, 7, 11, 2, 2, 142, 144, 5, 26, 14, 2, 143, 142, 3, 2, 2, 2, 144, 147, 3, 2, 2, 2, 145, 143, 3, 2, 2, 2, 145, 146, 3, 2, 2, 2, 146, 148, 3, 2, 2, 2, 147, 145, 3, 2, 2, 2, 148, 150, 7, 12, 2, 2, 149, 151, 5, 18, 10, 2, 150, 149, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 153, 3, 2, 2, 2, 152, 154, 7, 4, 2, 2, 153, 152, 3, 2, 2, 2, 153, 154, 3, 2, 2, 2, 154, 17, 3, 2, 2, 2, 155, 156, 7, 13, 2, 2, 156, 19, 3, 2, 2, 2, 157, 159, 7, 37, 2, 2, 158, 157, 3, 2, 2, 2, 158, 159, 3, 2, 2, 2, 159, 163, 3, 2, 2, 2, 160, 162, 5, 28, 15, 2, 161, 160, 3, 2, 2, 2, 162, 165, 3, 2, 2, 2, 163, 161, 3, 2, 2, 2, 163, 164, 3, 2, 2, 2, 164, 166, 3, 2, 2, 2, 165, 163, 3, 2, 2, 2, 166, 167, 7, 14, 2, 2, 167, 168, 7, 35, 2, 2, 168, 172, 7, 11, 2, 2, 169, 171, 5, 26, 14, 2, 170, 169, 3, 2, 2, 2, 171, 174, 3, 2, 2, 2, 172, 170, 3, 2, 2, 2, 172, 173, 3, 2, 2, 2, 173, 175, 3, 2, 2, 2, 174, 172, 3, 2, 2, 2, 175, 177, 7, 12, 2, 2, 176, 178, 7, 4, 2, 2, 177, 176, 3, 2, 2, 2, 177, 178, 3, 2, 2, 2, 178, 21, 3, 2, 2, 2, 179, 181, 7, 37, 2, 2, 180, 179, 3, 2, 2, 2, 180, 181, 3, 2, 2, 2, 181, 185, 3, 2, 2, 2, 182, 184, 5, 28, 15, 2, 183, 182, 3, 2, 2, 2, 184, 187, 3, 2, 2, 2, 185, 183, 3, 2, 2, 2, 185, 186, 3, 2, 2, 2, 186, 189, 3, 2, 2, 2, 187, 185, 3, 2, 2, 2, 188, 190, 5, 24, 13, 2, 189, 188, 3, 2, 2, 2, 189, 190, 3, 2, 2, 2, 190, 191, 3, 2, 2, 2, 191, 192, 5, 32, 17, 2, 192, 194, 7, 35, 2, 2, 193, 195, 7, 4, 2, 2, 194, 193, 3, 2, 2, 2, 194, 195, 3, 2, 2, 2, 195, 23, 3, 2, 2, 2, 196, 199, 7, 15, 2, 2, 197, 199, 7, 13, 2, 2, 198, 196, 3, 2, 2, 2, 198, 197, 3, 2, 2, 2, 199, 25, 3, 2, 2, 2, 200, 201, 5, 32, 17, 2, 201, 203, 7, 35, 2, 2, 202, 204, 7, 16, 2, 2, 203, 202, 3, 2, 2, 2, 203, 204, 3, 2, 2, 2, 204, 27, 3, 2, 2, 2, 205, 206, 7, 31, 2, 2, 206, 29, 3, 2, 2, 2, 207, 210, 7, 35, 2, 2, 208, 209, 7, 17, 2, 2, 209, 211, 7, 35, 2, 2, 210, 208, 3, 2, 2, 2, 210, 211, 3, 2, 2, 2, 211, 213, 3, 2, 2, 2, 212, 214, 7, 16, 2, 2, 213, 212, 3, 2, 2, 2, 213, 214, 3, 2, 2, 2, 214, 31, 3, 2, 2, 2, 215, 221, 5, 36, 19, 2, 216, 221, 5, 34, 18, 2, 217, 221, 5, 38, 20, 2, 218, 221, 5, 40, 21, 2, 219, 221, 5, 42, 22, 2, 220, 215, 3, 2, 2, 2, 220, 216, 3, 2, 2, 2, 220, 217, 3, 2, 2, 2, 220, 218, 3, 2, 2, 2, 220, 219, 3, 2, 2, 2, 221, 33, 3, 2, 2, 2, 222, 223, 7, 35, 2, 2, 223, 35, 3, 2, 2, 2, 224, 230, 7, 18, 2, 2, 225, 230, 7, 19, 2, 2, 226, 230, 7, 20, 2, 2, 227, 230, 7, 21, 2, 2, 228, 230, 7, 22, 2, 2, 229, 224, 3, 2, 2, 2, 229, 225, 3, 2, 2, 2, 229, 226, 3, 2, 2, 2, 229, 227, 3, 2, 2, 2, 229, 228, 3, 2, 2, 2, 230, 37, 3, 2, 2, 2, 231, 232, 7, 23, 2, 2, 232, 233, 7, 24, 2, 2, 233, 234, 5, 32, 17, 2, 234, 235, 7, 25, 2, 2, 235, 39, 3, 2, 2, 2, 236, 237, 7, 26, 2, 2, 237, 238, 7, 24, 2, 2, 238, 239, 5, 32, 17, 2, 239, 240, 7, 25, 2, 2, 240, 41, 3, 2, 2, 2, 241, 242, 7, 27, 2, 2, 242, 243, 7, 24, 2, 2, 243, 244, 5, 32, 17, 2, 244, 245, 7, 25, 2, 2, 245, 43, 3, 2, 2, 2, 246, 248, 7, 37, 2, 2, 247, 246, 3, 2, 2, 2, 247, 248, 3, 2, 2, 2, 248, 252, 3, 2, 2, 2, 249, 251, 5, 28, 15, 2, 250, 249, 3, 2, 2, 2, 251, 254, 3, 2, 2, 2, 252, 250, 3, 2, 2, 2, 252, 253, 3, 2, 2, 2, 253, 255, 3, 2, 2, 2, 254, 252, 3, 2, 2, 2, 255, 256, 7, 28, 2, 2, 256, 257, 7, 35, 2, 2, 257, 261, 7, 8, 2, 2, 258, 260, 5, 46, 24, 2, 259, 258, 3, 2, 2, 2, 260, 263, 3, 2, 2, 2, 261, 259, 3, 2, 2, 2, 261, 262, 3, 2, 2, 2, 262, 264, 3, 2, 2, 2, 263, 261, 3, 2, 2, 2, 264, 266, 7, 9, 2, 2, 265, 267, 7, 4, 2, 2, 266, 265, 3, 2, 2, 2, 266, 267, 3, 2, 2, 2, 267, 45, 3, 2, 2, 2, 268, 270, 7, 37, 2, 2, 269, 268, 3, 2, 2, 2, 269, 270, 3, 2, 2, 2, 270, 274, 3, 2, 2, 2, 271, 273, 5, 28, 15, 2, 272, 271, 3, 2, 2, 2, 273, 276, 3, 2, 2, 2, 274, 272, 3, 2, 2, 2, 274, 275, 3, 2, 2, 2, 275, 277, 3, 2, 2, 2, 276, 274, 3, 2, 2, 2, 277, 278, 5, 32, 17, 2, 278, 280, 7, 35, 2, 2, 279, 281, 7, 4, 2, 2, 280, 279, 3, 2, 2, 2, 280, 281, 3, 2, 2, 2, 281, 47, 3, 2, 2, 2, 282, 284, 7, 37, 2, 2, 283, 282, 3, 2, 2, 2, 283, 284, 3, 2, 2, 2, 284, 288, 3, 2, 2, 2, 285, 287, 5, 28, 15, 2, 286, 285, 3, 2, 2, 2, 287, 290, 3, 2, 2, 2, 288, 286, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 291, 3, 2, 2, 2, 290, 288, 3, 2, 2, 2, 291, 292, 5, 50, 26, 2, 292, 293, 7, 35, 2, 2, 293, 297, 7, 8, 2, 2, 294, 296, 5, 52, 27, 2, 295, 294, 3, 2, 2, 2, 296, 299, 3, 2, 2, 2, 297, 295, 3, 2, 2, 2, 297, 298, 3, 2, 2, 2, 298, 300, 3, 2, 2, 2, 299, 297, 3, 2, 2, 2, 300, 302, 7, 9, 2, 2, 301, 303, 7, 4, 2, 2, 302, 301, 3, 2, 2, 2, 302, 303, 3, 2, 2, 2, 303, 49, 3, 2, 2, 2, 304, 307, 7, 29, 2, 2, 305, 307, 7, 30, 2, 2, 306, 304, 3, 2, 2, 2, 306, 305, 3, 2, 2, 2, 307, 51, 3, 2, 2, 2, 308, 310, 7, 37, 2, 2, 309, 308, 3, 2, 2, 2, 309, 310, 3, 2, 2, 2, 310, 314, 3, 2, 2, 2, 311, 313, 5, 28, 15, 2, 312, 311, 3, 2, 2, 2, 313, 316, 3, 2, 2, 2, 314, 312, 3, 2, 2, 2, 314, 315, 3, 2, 2, 2, 315, 317, 3, 2, 2, 2, 316, 314, 3, 2, 2, 2, 317, 320, 7, 35, 2, 2, 318, 319, 7, 17, 2, 2, 319, 321, 5, 54, 28, 2, 320, 318, 3, 2, 2, 2, 320, 321, 3, 2, 2, 2, 321, 323, 3, 2, 2, 2, 322, 324, 7, 16, 2, 2, 323, 322, 3, 2, 2, 2, 323, 324, 3, 2, 2, 2, 324, 53, 3, 2, 2, 2, 325, 328, 7, 32, 2, 2, 326, 328, 7, 33, 2, 2, 327, 325, 3, 2, 2, 2, 327, 326, 3, 2, 2, 2, 328, 55, 3, 2, 2, 2, 52, 60, 67, 74, 77, 82, 89, 94, 97, 102, 109, 115, 120, 125, 128, 133, 138, 145, 150, 153, 158, 163, 172, 177, 180, 185, 189, 194, 198, 203, 210, 213, 220, 229, 247, 252, 261, 266, 269, 274, 280, 283, 288, 297, 302, 306, 309, 314, 320, 323, 327] \ No newline at end of file
+[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 43, 338, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 3, 2, 3, 2, 7, 2, 59, 10, 2, 12, 2, 14, 2, 62, 11, 2, 3, 3, 3, 3, 7, 3, 66, 10, 3, 12, 3, 14, 3, 69, 11, 3, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 75, 10, 4, 3, 5, 5, 5, 78, 10, 5, 3, 5, 7, 5, 81, 10, 5, 12, 5, 14, 5, 84, 11, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 90, 10, 5, 3, 6, 3, 6, 3, 6, 5, 6, 95, 10, 6, 3, 7, 5, 7, 98, 10, 7, 3, 7, 7, 7, 101, 10, 7, 12, 7, 14, 7, 104, 11, 7, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 110, 10, 7, 3, 7, 3, 7, 7, 7, 114, 10, 7, 12, 7, 14, 7, 117, 11, 7, 3, 7, 3, 7, 5, 7, 121, 10, 7, 3, 8, 3, 8, 3, 8, 5, 8, 126, 10, 8, 3, 9, 5, 9, 129, 10, 9, 3, 9, 7, 9, 132, 10, 9, 12, 9, 14, 9, 135, 11, 9, 3, 9, 3, 9, 5, 9, 139, 10, 9, 3, 9, 3, 9, 3, 9, 7, 9, 144, 10, 9, 12, 9, 14, 9, 147, 11, 9, 3, 9, 3, 9, 5, 9, 151, 10, 9, 3, 9, 5, 9, 154, 10, 9, 3, 10, 3, 10, 3, 11, 5, 11, 159, 10, 11, 3, 11, 7, 11, 162, 10, 11, 12, 11, 14, 11, 165, 11, 11, 3, 11, 3, 11, 3, 11, 3, 11, 7, 11, 171, 10, 11, 12, 11, 14, 11, 174, 11, 11, 3, 11, 3, 11, 5, 11, 178, 10, 11, 3, 12, 5, 12, 181, 10, 12, 3, 12, 7, 12, 184, 10, 12, 12, 12, 14, 12, 187, 11, 12, 3, 12, 5, 12, 190, 10, 12, 3, 12, 3, 12, 3, 12, 3, 12, 5, 12, 196, 10, 12, 3, 12, 5, 12, 199, 10, 12, 3, 13, 3, 13, 5, 13, 203, 10, 13, 3, 14, 3, 14, 3, 14, 5, 14, 208, 10, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 5, 16, 215, 10, 16, 3, 16, 5, 16, 218, 10, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 5, 17, 225, 10, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 5, 19, 234, 10, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 5, 23, 252, 10, 23, 3, 23, 7, 23, 255, 10, 23, 12, 23, 14, 23, 258, 11, 23, 3, 23, 3, 23, 3, 23, 3, 23, 7, 23, 264, 10, 23, 12, 23, 14, 23, 267, 11, 23, 3, 23, 3, 23, 5, 23, 271, 10, 23, 3, 24, 5, 24, 274, 10, 24, 3, 24, 7, 24, 277, 10, 24, 12, 24, 14, 24, 280, 11, 24, 3, 24, 3, 24, 3, 24, 3, 24, 5, 24, 286, 10, 24, 3, 24, 5, 24, 289, 10, 24, 3, 25, 5, 25, 292, 10, 25, 3, 25, 7, 25, 295, 10, 25, 12, 25, 14, 25, 298, 11, 25, 3, 25, 3, 25, 3, 25, 3, 25, 7, 25, 304, 10, 25, 12, 25, 14, 25, 307, 11, 25, 3, 25, 3, 25, 5, 25, 311, 10, 25, 3, 26, 3, 26, 5, 26, 315, 10, 26, 3, 27, 5, 27, 318, 10, 27, 3, 27, 7, 27, 321, 10, 27, 12, 27, 14, 27, 324, 11, 27, 3, 27, 3, 27, 3, 27, 5, 27, 329, 10, 27, 3, 27, 5, 27, 332, 10, 27, 3, 28, 3, 28, 5, 28, 336, 10, 28, 3, 28, 2, 2, 29, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 2, 2, 2, 370, 2, 56, 3, 2, 2, 2, 4, 63, 3, 2, 2, 2, 6, 70, 3, 2, 2, 2, 8, 77, 3, 2, 2, 2, 10, 94, 3, 2, 2, 2, 12, 97, 3, 2, 2, 2, 14, 125, 3, 2, 2, 2, 16, 128, 3, 2, 2, 2, 18, 155, 3, 2, 2, 2, 20, 158, 3, 2, 2, 2, 22, 180, 3, 2, 2, 2, 24, 202, 3, 2, 2, 2, 26, 204, 3, 2, 2, 2, 28, 209, 3, 2, 2, 2, 30, 211, 3, 2, 2, 2, 32, 224, 3, 2, 2, 2, 34, 226, 3, 2, 2, 2, 36, 233, 3, 2, 2, 2, 38, 235, 3, 2, 2, 2, 40, 240, 3, 2, 2, 2, 42, 245, 3, 2, 2, 2, 44, 251, 3, 2, 2, 2, 46, 273, 3, 2, 2, 2, 48, 291, 3, 2, 2, 2, 50, 314, 3, 2, 2, 2, 52, 317, 3, 2, 2, 2, 54, 335, 3, 2, 2, 2, 56, 60, 5, 4, 3, 2, 57, 59, 5, 10, 6, 2, 58, 57, 3, 2, 2, 2, 59, 62, 3, 2, 2, 2, 60, 58, 3, 2, 2, 2, 60, 61, 3, 2, 2, 2, 61, 3, 3, 2, 2, 2, 62, 60, 3, 2, 2, 2, 63, 67, 5, 8, 5, 2, 64, 66, 5, 6, 4, 2, 65, 64, 3, 2, 2, 2, 66, 69, 3, 2, 2, 2, 67, 65, 3, 2, 2, 2, 67, 68, 3, 2, 2, 2, 68, 5, 3, 2, 2, 2, 69, 67, 3, 2, 2, 2, 70, 71, 7, 3, 2, 2, 71, 72, 7, 38, 2, 2, 72, 74, 7, 39, 2, 2, 73, 75, 7, 4, 2, 2, 74, 73, 3, 2, 2, 2, 74, 75, 3, 2, 2, 2, 75, 7, 3, 2, 2, 2, 76, 78, 7, 40, 2, 2, 77, 76, 3, 2, 2, 2, 77, 78, 3, 2, 2, 2, 78, 82, 3, 2, 2, 2, 79, 81, 5, 28, 15, 2, 80, 79, 3, 2, 2, 2, 81, 84, 3, 2, 2, 2, 82, 80, 3, 2, 2, 2, 82, 83, 3, 2, 2, 2, 83, 85, 3, 2, 2, 2, 84, 82, 3, 2, 2, 2, 85, 86, 7, 5, 2, 2, 86, 87, 7, 38, 2, 2, 87, 89, 7, 39, 2, 2, 88, 90, 7, 4, 2, 2, 89, 88, 3, 2, 2, 2, 89, 90, 3, 2, 2, 2, 90, 9, 3, 2, 2, 2, 91, 95, 5, 12, 7, 2, 92, 95, 5, 44, 23, 2, 93, 95, 5, 48, 25, 2, 94, 91, 3, 2, 2, 2, 94, 92, 3, 2, 2, 2, 94, 93, 3, 2, 2, 2, 95, 11, 3, 2, 2, 2, 96, 98, 7, 40, 2, 2, 97, 96, 3, 2, 2, 2, 97, 98, 3, 2, 2, 2, 98, 102, 3, 2, 2, 2, 99, 101, 5, 28, 15, 2, 100, 99, 3, 2, 2, 2, 101, 104, 3, 2, 2, 2, 102, 100, 3, 2, 2, 2, 102, 103, 3, 2, 2, 2, 103, 105, 3, 2, 2, 2, 104, 102, 3, 2, 2, 2, 105, 106, 7, 6, 2, 2, 106, 109, 7, 38, 2, 2, 107, 108, 7, 7, 2, 2, 108, 110, 7, 38, 2, 2, 109, 107, 3, 2, 2, 2, 109, 110, 3, 2, 2, 2, 110, 111, 3, 2, 2, 2, 111, 115, 7, 8, 2, 2, 112, 114, 5, 14, 8, 2, 113, 112, 3, 2, 2, 2, 114, 117, 3, 2, 2, 2, 115, 113, 3, 2, 2, 2, 115, 116, 3, 2, 2, 2, 116, 118, 3, 2, 2, 2, 117, 115, 3, 2, 2, 2, 118, 120, 7, 9, 2, 2, 119, 121, 7, 4, 2, 2, 120, 119, 3, 2, 2, 2, 120, 121, 3, 2, 2, 2, 121, 13, 3, 2, 2, 2, 122, 126, 5, 16, 9, 2, 123, 126, 5, 22, 12, 2, 124, 126, 5, 20, 11, 2, 125, 122, 3, 2, 2, 2, 125, 123, 3, 2, 2, 2, 125, 124, 3, 2, 2, 2, 126, 15, 3, 2, 2, 2, 127, 129, 7, 40, 2, 2, 128, 127, 3, 2, 2, 2, 128, 129, 3, 2, 2, 2, 129, 133, 3, 2, 2, 2, 130, 132, 5, 28, 15, 2, 131, 130, 3, 2, 2, 2, 132, 135, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 138, 3, 2, 2, 2, 135, 133, 3, 2, 2, 2, 136, 139, 5, 32, 17, 2, 137, 139, 7, 10, 2, 2, 138, 136, 3, 2, 2, 2, 138, 137, 3, 2, 2, 2, 139, 140, 3, 2, 2, 2, 140, 141, 7, 38, 2, 2, 141, 145, 7, 11, 2, 2, 142, 144, 5, 26, 14, 2, 143, 142, 3, 2, 2, 2, 144, 147, 3, 2, 2, 2, 145, 143, 3, 2, 2, 2, 145, 146, 3, 2, 2, 2, 146, 148, 3, 2, 2, 2, 147, 145, 3, 2, 2, 2, 148, 150, 7, 12, 2, 2, 149, 151, 5, 18, 10, 2, 150, 149, 3, 2, 2, 2, 150, 151, 3, 2, 2, 2, 151, 153, 3, 2, 2, 2, 152, 154, 7, 4, 2, 2, 153, 152, 3, 2, 2, 2, 153, 154, 3, 2, 2, 2, 154, 17, 3, 2, 2, 2, 155, 156, 7, 13, 2, 2, 156, 19, 3, 2, 2, 2, 157, 159, 7, 40, 2, 2, 158, 157, 3, 2, 2, 2, 158, 159, 3, 2, 2, 2, 159, 163, 3, 2, 2, 2, 160, 162, 5, 28, 15, 2, 161, 160, 3, 2, 2, 2, 162, 165, 3, 2, 2, 2, 163, 161, 3, 2, 2, 2, 163, 164, 3, 2, 2, 2, 164, 166, 3, 2, 2, 2, 165, 163, 3, 2, 2, 2, 166, 167, 7, 14, 2, 2, 167, 168, 7, 38, 2, 2, 168, 172, 7, 11, 2, 2, 169, 171, 5, 26, 14, 2, 170, 169, 3, 2, 2, 2, 171, 174, 3, 2, 2, 2, 172, 170, 3, 2, 2, 2, 172, 173, 3, 2, 2, 2, 173, 175, 3, 2, 2, 2, 174, 172, 3, 2, 2, 2, 175, 177, 7, 12, 2, 2, 176, 178, 7, 4, 2, 2, 177, 176, 3, 2, 2, 2, 177, 178, 3, 2, 2, 2, 178, 21, 3, 2, 2, 2, 179, 181, 7, 40, 2, 2, 180, 179, 3, 2, 2, 2, 180, 181, 3, 2, 2, 2, 181, 185, 3, 2, 2, 2, 182, 184, 5, 28, 15, 2, 183, 182, 3, 2, 2, 2, 184, 187, 3, 2, 2, 2, 185, 183, 3, 2, 2, 2, 185, 186, 3, 2, 2, 2, 186, 189, 3, 2, 2, 2, 187, 185, 3, 2, 2, 2, 188, 190, 5, 24, 13, 2, 189, 188, 3, 2, 2, 2, 189, 190, 3, 2, 2, 2, 190, 191, 3, 2, 2, 2, 191, 192, 5, 32, 17, 2, 192, 195, 7, 38, 2, 2, 193, 194, 7, 15, 2, 2, 194, 196, 7, 31, 2, 2, 195, 193, 3, 2, 2, 2, 195, 196, 3, 2, 2, 2, 196, 198, 3, 2, 2, 2, 197, 199, 7, 4, 2, 2, 198, 197, 3, 2, 2, 2, 198, 199, 3, 2, 2, 2, 199, 23, 3, 2, 2, 2, 200, 203, 7, 16, 2, 2, 201, 203, 7, 13, 2, 2, 202, 200, 3, 2, 2, 2, 202, 201, 3, 2, 2, 2, 203, 25, 3, 2, 2, 2, 204, 205, 5, 32, 17, 2, 205, 207, 7, 38, 2, 2, 206, 208, 7, 17, 2, 2, 207, 206, 3, 2, 2, 2, 207, 208, 3, 2, 2, 2, 208, 27, 3, 2, 2, 2, 209, 210, 7, 34, 2, 2, 210, 29, 3, 2, 2, 2, 211, 214, 7, 38, 2, 2, 212, 213, 7, 15, 2, 2, 213, 215, 7, 38, 2, 2, 214, 212, 3, 2, 2, 2, 214, 215, 3, 2, 2, 2, 215, 217, 3, 2, 2, 2, 216, 218, 7, 17, 2, 2, 217, 216, 3, 2, 2, 2, 217, 218, 3, 2, 2, 2, 218, 31, 3, 2, 2, 2, 219, 225, 5, 36, 19, 2, 220, 225, 5, 34, 18, 2, 221, 225, 5, 38, 20, 2, 222, 225, 5, 40, 21, 2, 223, 225, 5, 42, 22, 2, 224, 219, 3, 2, 2, 2, 224, 220, 3, 2, 2, 2, 224, 221, 3, 2, 2, 2, 224, 222, 3, 2, 2, 2, 224, 223, 3, 2, 2, 2, 225, 33, 3, 2, 2, 2, 226, 227, 7, 38, 2, 2, 227, 35, 3, 2, 2, 2, 228, 234, 7, 18, 2, 2, 229, 234, 7, 19, 2, 2, 230, 234, 7, 20, 2, 2, 231, 234, 7, 21, 2, 2, 232, 234, 7, 22, 2, 2, 233, 228, 3, 2, 2, 2, 233, 229, 3, 2, 2, 2, 233, 230, 3, 2, 2, 2, 233, 231, 3, 2, 2, 2, 233, 232, 3, 2, 2, 2, 234, 37, 3, 2, 2, 2, 235, 236, 7, 23, 2, 2, 236, 237, 7, 24, 2, 2, 237, 238, 5, 32, 17, 2, 238, 239, 7, 25, 2, 2, 239, 39, 3, 2, 2, 2, 240, 241, 7, 26, 2, 2, 241, 242, 7, 24, 2, 2, 242, 243, 5, 32, 17, 2, 243, 244, 7, 25, 2, 2, 244, 41, 3, 2, 2, 2, 245, 246, 7, 27, 2, 2, 246, 247, 7, 24, 2, 2, 247, 248, 5, 32, 17, 2, 248, 249, 7, 25, 2, 2, 249, 43, 3, 2, 2, 2, 250, 252, 7, 40, 2, 2, 251, 250, 3, 2, 2, 2, 251, 252, 3, 2, 2, 2, 252, 256, 3, 2, 2, 2, 253, 255, 5, 28, 15, 2, 254, 253, 3, 2, 2, 2, 255, 258, 3, 2, 2, 2, 256, 254, 3, 2, 2, 2, 256, 257, 3, 2, 2, 2, 257, 259, 3, 2, 2, 2, 258, 256, 3, 2, 2, 2, 259, 260, 7, 28, 2, 2, 260, 261, 7, 38, 2, 2, 261, 265, 7, 8, 2, 2, 262, 264, 5, 46, 24, 2, 263, 262, 3, 2, 2, 2, 264, 267, 3, 2, 2, 2, 265, 263, 3, 2, 2, 2, 265, 266, 3, 2, 2, 2, 266, 268, 3, 2, 2, 2, 267, 265, 3, 2, 2, 2, 268, 270, 7, 9, 2, 2, 269, 271, 7, 4, 2, 2, 270, 269, 3, 2, 2, 2, 270, 271, 3, 2, 2, 2, 271, 45, 3, 2, 2, 2, 272, 274, 7, 40, 2, 2, 273, 272, 3, 2, 2, 2, 273, 274, 3, 2, 2, 2, 274, 278, 3, 2, 2, 2, 275, 277, 5, 28, 15, 2, 276, 275, 3, 2, 2, 2, 277, 280, 3, 2, 2, 2, 278, 276, 3, 2, 2, 2, 278, 279, 3, 2, 2, 2, 279, 281, 3, 2, 2, 2, 280, 278, 3, 2, 2, 2, 281, 282, 5, 32, 17, 2, 282, 285, 7, 38, 2, 2, 283, 284, 7, 15, 2, 2, 284, 286, 7, 31, 2, 2, 285, 283, 3, 2, 2, 2, 285, 286, 3, 2, 2, 2, 286, 288, 3, 2, 2, 2, 287, 289, 7, 4, 2, 2, 288, 287, 3, 2, 2, 2, 288, 289, 3, 2, 2, 2, 289, 47, 3, 2, 2, 2, 290, 292, 7, 40, 2, 2, 291, 290, 3, 2, 2, 2, 291, 292, 3, 2, 2, 2, 292, 296, 3, 2, 2, 2, 293, 295, 5, 28, 15, 2, 294, 293, 3, 2, 2, 2, 295, 298, 3, 2, 2, 2, 296, 294, 3, 2, 2, 2, 296, 297, 3, 2, 2, 2, 297, 299, 3, 2, 2, 2, 298, 296, 3, 2, 2, 2, 299, 300, 5, 50, 26, 2, 300, 301, 7, 38, 2, 2, 301, 305, 7, 8, 2, 2, 302, 304, 5, 52, 27, 2, 303, 302, 3, 2, 2, 2, 304, 307, 3, 2, 2, 2, 305, 303, 3, 2, 2, 2, 305, 306, 3, 2, 2, 2, 306, 308, 3, 2, 2, 2, 307, 305, 3, 2, 2, 2, 308, 310, 7, 9, 2, 2, 309, 311, 7, 4, 2, 2, 310, 309, 3, 2, 2, 2, 310, 311, 3, 2, 2, 2, 311, 49, 3, 2, 2, 2, 312, 315, 7, 29, 2, 2, 313, 315, 7, 30, 2, 2, 314, 312, 3, 2, 2, 2, 314, 313, 3, 2, 2, 2, 315, 51, 3, 2, 2, 2, 316, 318, 7, 40, 2, 2, 317, 316, 3, 2, 2, 2, 317, 318, 3, 2, 2, 2, 318, 322, 3, 2, 2, 2, 319, 321, 5, 28, 15, 2, 320, 319, 3, 2, 2, 2, 321, 324, 3, 2, 2, 2, 322, 320, 3, 2, 2, 2, 322, 323, 3, 2, 2, 2, 323, 325, 3, 2, 2, 2, 324, 322, 3, 2, 2, 2, 325, 328, 7, 38, 2, 2, 326, 327, 7, 15, 2, 2, 327, 329, 5, 54, 28, 2, 328, 326, 3, 2, 2, 2, 328, 329, 3, 2, 2, 2, 329, 331, 3, 2, 2, 2, 330, 332, 7, 17, 2, 2, 331, 330, 3, 2, 2, 2, 331, 332, 3, 2, 2, 2, 332, 53, 3, 2, 2, 2, 333, 336, 7, 35, 2, 2, 334, 336, 7, 36, 2, 2, 335, 333, 3, 2, 2, 2, 335, 334, 3, 2, 2, 2, 336, 55, 3, 2, 2, 2, 54, 60, 67, 74, 77, 82, 89, 94, 97, 102, 109, 115, 120, 125, 128, 133, 138, 145, 150, 153, 158, 163, 172, 177, 180, 185, 189, 195, 198, 202, 207, 214, 217, 224, 233, 251, 256, 265, 270, 273, 278, 285, 288, 291, 296, 305, 310, 314, 317, 322, 328, 331, 335] \ No newline at end of file
diff --git a/qface/idl/parser/T.tokens b/qface/idl/parser/T.tokens
index 4f861bd..5daf716 100644
--- a/qface/idl/parser/T.tokens
+++ b/qface/idl/parser/T.tokens
@@ -26,16 +26,19 @@ T__24=25
T__25=26
T__26=27
T__27=28
-TAGLINE=29
-INTCONSTANT=30
-HEXCONSTANT=31
-TAGIDENTIFIER=32
-IDENTIFIER=33
-VERSION=34
-DOCCOMMENT=35
-WHITESPACE=36
-COMMENT=37
-MULTICOMM=38
+STRING=29
+DOUBLE_STRING=30
+SINGLE_STRING=31
+TAGLINE=32
+INTCONSTANT=33
+HEXCONSTANT=34
+TAGIDENTIFIER=35
+IDENTIFIER=36
+VERSION=37
+DOCCOMMENT=38
+WHITESPACE=39
+COMMENT=40
+MULTICOMM=41
'import'=1
';'=2
'module'=3
@@ -48,9 +51,9 @@ MULTICOMM=38
')'=10
'const'=11
'signal'=12
-'readonly'=13
-','=14
-'='=15
+'='=13
+'readonly'=14
+','=15
'bool'=16
'int'=17
'real'=18
diff --git a/qface/idl/parser/TLexer.interp b/qface/idl/parser/TLexer.interp
index 5f065b5..f75202f 100644
--- a/qface/idl/parser/TLexer.interp
+++ b/qface/idl/parser/TLexer.interp
@@ -12,9 +12,9 @@ null
')'
'const'
'signal'
+'='
'readonly'
','
-'='
'bool'
'int'
'real'
@@ -38,6 +38,9 @@ null
null
null
null
+null
+null
+null
token symbolic names:
null
@@ -69,6 +72,9 @@ null
null
null
null
+STRING
+DOUBLE_STRING
+SINGLE_STRING
TAGLINE
INTCONSTANT
HEXCONSTANT
@@ -109,6 +115,9 @@ T__24
T__25
T__26
T__27
+STRING
+DOUBLE_STRING
+SINGLE_STRING
TAGLINE
INTCONSTANT
HEXCONSTANT
@@ -119,6 +128,7 @@ DOCCOMMENT
WHITESPACE
COMMENT
MULTICOMM
+ESC
channel names:
DEFAULT_TOKEN_CHANNEL
@@ -128,4 +138,4 @@ mode names:
DEFAULT_MODE
atn:
-[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 40, 300, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 3, 2, 3, 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, 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, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 7, 30, 216, 10, 30, 12, 30, 14, 30, 219, 11, 30, 3, 31, 5, 31, 222, 10, 31, 3, 31, 6, 31, 225, 10, 31, 13, 31, 14, 31, 226, 3, 32, 3, 32, 3, 32, 3, 32, 6, 32, 233, 10, 32, 13, 32, 14, 32, 234, 3, 33, 3, 33, 3, 33, 7, 33, 240, 10, 33, 12, 33, 14, 33, 243, 11, 33, 3, 34, 3, 34, 7, 34, 247, 10, 34, 12, 34, 14, 34, 250, 11, 34, 3, 35, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 36, 7, 36, 261, 10, 36, 12, 36, 14, 36, 264, 11, 36, 3, 36, 3, 36, 3, 36, 3, 37, 6, 37, 270, 10, 37, 13, 37, 14, 37, 271, 3, 37, 3, 37, 3, 38, 3, 38, 3, 38, 3, 38, 7, 38, 280, 10, 38, 12, 38, 14, 38, 283, 11, 38, 3, 38, 3, 38, 3, 39, 3, 39, 3, 39, 3, 39, 7, 39, 291, 10, 39, 12, 39, 14, 39, 294, 11, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 4, 262, 292, 2, 40, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 3, 2, 9, 4, 2, 12, 12, 15, 15, 4, 2, 45, 45, 47, 47, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 67, 92, 97, 97, 99, 124, 7, 2, 48, 48, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 50, 59, 5, 2, 11, 12, 15, 15, 34, 34, 2, 309, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 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, 2, 2, 2, 29, 3, 2, 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, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 3, 79, 3, 2, 2, 2, 5, 86, 3, 2, 2, 2, 7, 88, 3, 2, 2, 2, 9, 95, 3, 2, 2, 2, 11, 105, 3, 2, 2, 2, 13, 113, 3, 2, 2, 2, 15, 115, 3, 2, 2, 2, 17, 117, 3, 2, 2, 2, 19, 122, 3, 2, 2, 2, 21, 124, 3, 2, 2, 2, 23, 126, 3, 2, 2, 2, 25, 132, 3, 2, 2, 2, 27, 139, 3, 2, 2, 2, 29, 148, 3, 2, 2, 2, 31, 150, 3, 2, 2, 2, 33, 152, 3, 2, 2, 2, 35, 157, 3, 2, 2, 2, 37, 161, 3, 2, 2, 2, 39, 166, 3, 2, 2, 2, 41, 173, 3, 2, 2, 2, 43, 177, 3, 2, 2, 2, 45, 182, 3, 2, 2, 2, 47, 184, 3, 2, 2, 2, 49, 186, 3, 2, 2, 2, 51, 190, 3, 2, 2, 2, 53, 196, 3, 2, 2, 2, 55, 203, 3, 2, 2, 2, 57, 208, 3, 2, 2, 2, 59, 213, 3, 2, 2, 2, 61, 221, 3, 2, 2, 2, 63, 228, 3, 2, 2, 2, 65, 236, 3, 2, 2, 2, 67, 244, 3, 2, 2, 2, 69, 251, 3, 2, 2, 2, 71, 255, 3, 2, 2, 2, 73, 269, 3, 2, 2, 2, 75, 275, 3, 2, 2, 2, 77, 286, 3, 2, 2, 2, 79, 80, 7, 107, 2, 2, 80, 81, 7, 111, 2, 2, 81, 82, 7, 114, 2, 2, 82, 83, 7, 113, 2, 2, 83, 84, 7, 116, 2, 2, 84, 85, 7, 118, 2, 2, 85, 4, 3, 2, 2, 2, 86, 87, 7, 61, 2, 2, 87, 6, 3, 2, 2, 2, 88, 89, 7, 111, 2, 2, 89, 90, 7, 113, 2, 2, 90, 91, 7, 102, 2, 2, 91, 92, 7, 119, 2, 2, 92, 93, 7, 110, 2, 2, 93, 94, 7, 103, 2, 2, 94, 8, 3, 2, 2, 2, 95, 96, 7, 107, 2, 2, 96, 97, 7, 112, 2, 2, 97, 98, 7, 118, 2, 2, 98, 99, 7, 103, 2, 2, 99, 100, 7, 116, 2, 2, 100, 101, 7, 104, 2, 2, 101, 102, 7, 99, 2, 2, 102, 103, 7, 101, 2, 2, 103, 104, 7, 103, 2, 2, 104, 10, 3, 2, 2, 2, 105, 106, 7, 103, 2, 2, 106, 107, 7, 122, 2, 2, 107, 108, 7, 118, 2, 2, 108, 109, 7, 103, 2, 2, 109, 110, 7, 112, 2, 2, 110, 111, 7, 102, 2, 2, 111, 112, 7, 117, 2, 2, 112, 12, 3, 2, 2, 2, 113, 114, 7, 125, 2, 2, 114, 14, 3, 2, 2, 2, 115, 116, 7, 127, 2, 2, 116, 16, 3, 2, 2, 2, 117, 118, 7, 120, 2, 2, 118, 119, 7, 113, 2, 2, 119, 120, 7, 107, 2, 2, 120, 121, 7, 102, 2, 2, 121, 18, 3, 2, 2, 2, 122, 123, 7, 42, 2, 2, 123, 20, 3, 2, 2, 2, 124, 125, 7, 43, 2, 2, 125, 22, 3, 2, 2, 2, 126, 127, 7, 101, 2, 2, 127, 128, 7, 113, 2, 2, 128, 129, 7, 112, 2, 2, 129, 130, 7, 117, 2, 2, 130, 131, 7, 118, 2, 2, 131, 24, 3, 2, 2, 2, 132, 133, 7, 117, 2, 2, 133, 134, 7, 107, 2, 2, 134, 135, 7, 105, 2, 2, 135, 136, 7, 112, 2, 2, 136, 137, 7, 99, 2, 2, 137, 138, 7, 110, 2, 2, 138, 26, 3, 2, 2, 2, 139, 140, 7, 116, 2, 2, 140, 141, 7, 103, 2, 2, 141, 142, 7, 99, 2, 2, 142, 143, 7, 102, 2, 2, 143, 144, 7, 113, 2, 2, 144, 145, 7, 112, 2, 2, 145, 146, 7, 110, 2, 2, 146, 147, 7, 123, 2, 2, 147, 28, 3, 2, 2, 2, 148, 149, 7, 46, 2, 2, 149, 30, 3, 2, 2, 2, 150, 151, 7, 63, 2, 2, 151, 32, 3, 2, 2, 2, 152, 153, 7, 100, 2, 2, 153, 154, 7, 113, 2, 2, 154, 155, 7, 113, 2, 2, 155, 156, 7, 110, 2, 2, 156, 34, 3, 2, 2, 2, 157, 158, 7, 107, 2, 2, 158, 159, 7, 112, 2, 2, 159, 160, 7, 118, 2, 2, 160, 36, 3, 2, 2, 2, 161, 162, 7, 116, 2, 2, 162, 163, 7, 103, 2, 2, 163, 164, 7, 99, 2, 2, 164, 165, 7, 110, 2, 2, 165, 38, 3, 2, 2, 2, 166, 167, 7, 117, 2, 2, 167, 168, 7, 118, 2, 2, 168, 169, 7, 116, 2, 2, 169, 170, 7, 107, 2, 2, 170, 171, 7, 112, 2, 2, 171, 172, 7, 105, 2, 2, 172, 40, 3, 2, 2, 2, 173, 174, 7, 120, 2, 2, 174, 175, 7, 99, 2, 2, 175, 176, 7, 116, 2, 2, 176, 42, 3, 2, 2, 2, 177, 178, 7, 110, 2, 2, 178, 179, 7, 107, 2, 2, 179, 180, 7, 117, 2, 2, 180, 181, 7, 118, 2, 2, 181, 44, 3, 2, 2, 2, 182, 183, 7, 62, 2, 2, 183, 46, 3, 2, 2, 2, 184, 185, 7, 64, 2, 2, 185, 48, 3, 2, 2, 2, 186, 187, 7, 111, 2, 2, 187, 188, 7, 99, 2, 2, 188, 189, 7, 114, 2, 2, 189, 50, 3, 2, 2, 2, 190, 191, 7, 111, 2, 2, 191, 192, 7, 113, 2, 2, 192, 193, 7, 102, 2, 2, 193, 194, 7, 103, 2, 2, 194, 195, 7, 110, 2, 2, 195, 52, 3, 2, 2, 2, 196, 197, 7, 117, 2, 2, 197, 198, 7, 118, 2, 2, 198, 199, 7, 116, 2, 2, 199, 200, 7, 119, 2, 2, 200, 201, 7, 101, 2, 2, 201, 202, 7, 118, 2, 2, 202, 54, 3, 2, 2, 2, 203, 204, 7, 103, 2, 2, 204, 205, 7, 112, 2, 2, 205, 206, 7, 119, 2, 2, 206, 207, 7, 111, 2, 2, 207, 56, 3, 2, 2, 2, 208, 209, 7, 104, 2, 2, 209, 210, 7, 110, 2, 2, 210, 211, 7, 99, 2, 2, 211, 212, 7, 105, 2, 2, 212, 58, 3, 2, 2, 2, 213, 217, 7, 66, 2, 2, 214, 216, 10, 2, 2, 2, 215, 214, 3, 2, 2, 2, 216, 219, 3, 2, 2, 2, 217, 215, 3, 2, 2, 2, 217, 218, 3, 2, 2, 2, 218, 60, 3, 2, 2, 2, 219, 217, 3, 2, 2, 2, 220, 222, 9, 3, 2, 2, 221, 220, 3, 2, 2, 2, 221, 222, 3, 2, 2, 2, 222, 224, 3, 2, 2, 2, 223, 225, 4, 50, 59, 2, 224, 223, 3, 2, 2, 2, 225, 226, 3, 2, 2, 2, 226, 224, 3, 2, 2, 2, 226, 227, 3, 2, 2, 2, 227, 62, 3, 2, 2, 2, 228, 229, 7, 50, 2, 2, 229, 230, 7, 122, 2, 2, 230, 232, 3, 2, 2, 2, 231, 233, 9, 4, 2, 2, 232, 231, 3, 2, 2, 2, 233, 234, 3, 2, 2, 2, 234, 232, 3, 2, 2, 2, 234, 235, 3, 2, 2, 2, 235, 64, 3, 2, 2, 2, 236, 237, 7, 66, 2, 2, 237, 241, 9, 5, 2, 2, 238, 240, 9, 6, 2, 2, 239, 238, 3, 2, 2, 2, 240, 243, 3, 2, 2, 2, 241, 239, 3, 2, 2, 2, 241, 242, 3, 2, 2, 2, 242, 66, 3, 2, 2, 2, 243, 241, 3, 2, 2, 2, 244, 248, 9, 5, 2, 2, 245, 247, 9, 6, 2, 2, 246, 245, 3, 2, 2, 2, 247, 250, 3, 2, 2, 2, 248, 246, 3, 2, 2, 2, 248, 249, 3, 2, 2, 2, 249, 68, 3, 2, 2, 2, 250, 248, 3, 2, 2, 2, 251, 252, 9, 7, 2, 2, 252, 253, 7, 48, 2, 2, 253, 254, 9, 7, 2, 2, 254, 70, 3, 2, 2, 2, 255, 256, 7, 49, 2, 2, 256, 257, 7, 44, 2, 2, 257, 258, 7, 44, 2, 2, 258, 262, 3, 2, 2, 2, 259, 261, 11, 2, 2, 2, 260, 259, 3, 2, 2, 2, 261, 264, 3, 2, 2, 2, 262, 263, 3, 2, 2, 2, 262, 260, 3, 2, 2, 2, 263, 265, 3, 2, 2, 2, 264, 262, 3, 2, 2, 2, 265, 266, 7, 44, 2, 2, 266, 267, 7, 49, 2, 2, 267, 72, 3, 2, 2, 2, 268, 270, 9, 8, 2, 2, 269, 268, 3, 2, 2, 2, 270, 271, 3, 2, 2, 2, 271, 269, 3, 2, 2, 2, 271, 272, 3, 2, 2, 2, 272, 273, 3, 2, 2, 2, 273, 274, 8, 37, 2, 2, 274, 74, 3, 2, 2, 2, 275, 276, 7, 49, 2, 2, 276, 277, 7, 49, 2, 2, 277, 281, 3, 2, 2, 2, 278, 280, 10, 2, 2, 2, 279, 278, 3, 2, 2, 2, 280, 283, 3, 2, 2, 2, 281, 279, 3, 2, 2, 2, 281, 282, 3, 2, 2, 2, 282, 284, 3, 2, 2, 2, 283, 281, 3, 2, 2, 2, 284, 285, 8, 38, 2, 2, 285, 76, 3, 2, 2, 2, 286, 287, 7, 49, 2, 2, 287, 288, 7, 44, 2, 2, 288, 292, 3, 2, 2, 2, 289, 291, 11, 2, 2, 2, 290, 289, 3, 2, 2, 2, 291, 294, 3, 2, 2, 2, 292, 293, 3, 2, 2, 2, 292, 290, 3, 2, 2, 2, 293, 295, 3, 2, 2, 2, 294, 292, 3, 2, 2, 2, 295, 296, 7, 44, 2, 2, 296, 297, 7, 49, 2, 2, 297, 298, 3, 2, 2, 2, 298, 299, 8, 39, 2, 2, 299, 78, 3, 2, 2, 2, 13, 2, 217, 221, 226, 234, 241, 248, 262, 271, 281, 292, 3, 8, 2, 2] \ No newline at end of file
+[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 43, 335, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 3, 2, 3, 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, 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, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 5, 30, 224, 10, 30, 3, 31, 3, 31, 3, 31, 7, 31, 229, 10, 31, 12, 31, 14, 31, 232, 11, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 7, 32, 239, 10, 32, 12, 32, 14, 32, 242, 11, 32, 3, 32, 3, 32, 3, 33, 3, 33, 7, 33, 248, 10, 33, 12, 33, 14, 33, 251, 11, 33, 3, 34, 5, 34, 254, 10, 34, 3, 34, 6, 34, 257, 10, 34, 13, 34, 14, 34, 258, 3, 35, 3, 35, 3, 35, 3, 35, 6, 35, 265, 10, 35, 13, 35, 14, 35, 266, 3, 36, 3, 36, 3, 36, 7, 36, 272, 10, 36, 12, 36, 14, 36, 275, 11, 36, 3, 37, 3, 37, 7, 37, 279, 10, 37, 12, 37, 14, 37, 282, 11, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 7, 39, 293, 10, 39, 12, 39, 14, 39, 296, 11, 39, 3, 39, 3, 39, 3, 39, 3, 40, 6, 40, 302, 10, 40, 13, 40, 14, 40, 303, 3, 40, 3, 40, 3, 41, 3, 41, 3, 41, 3, 41, 7, 41, 312, 10, 41, 12, 41, 14, 41, 315, 11, 41, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 7, 42, 323, 10, 42, 12, 42, 14, 42, 326, 11, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 4, 294, 324, 2, 44, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 42, 83, 43, 85, 2, 3, 2, 12, 4, 2, 36, 36, 94, 94, 4, 2, 41, 41, 94, 94, 4, 2, 12, 12, 15, 15, 4, 2, 45, 45, 47, 47, 5, 2, 50, 59, 67, 72, 99, 104, 5, 2, 67, 92, 97, 97, 99, 124, 7, 2, 48, 48, 50, 59, 67, 92, 97, 97, 99, 124, 3, 2, 50, 59, 5, 2, 11, 12, 15, 15, 34, 34, 10, 2, 36, 36, 49, 49, 94, 94, 100, 100, 104, 104, 112, 112, 116, 116, 118, 118, 2, 348, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 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, 2, 2, 2, 29, 3, 2, 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, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 3, 87, 3, 2, 2, 2, 5, 94, 3, 2, 2, 2, 7, 96, 3, 2, 2, 2, 9, 103, 3, 2, 2, 2, 11, 113, 3, 2, 2, 2, 13, 121, 3, 2, 2, 2, 15, 123, 3, 2, 2, 2, 17, 125, 3, 2, 2, 2, 19, 130, 3, 2, 2, 2, 21, 132, 3, 2, 2, 2, 23, 134, 3, 2, 2, 2, 25, 140, 3, 2, 2, 2, 27, 147, 3, 2, 2, 2, 29, 149, 3, 2, 2, 2, 31, 158, 3, 2, 2, 2, 33, 160, 3, 2, 2, 2, 35, 165, 3, 2, 2, 2, 37, 169, 3, 2, 2, 2, 39, 174, 3, 2, 2, 2, 41, 181, 3, 2, 2, 2, 43, 185, 3, 2, 2, 2, 45, 190, 3, 2, 2, 2, 47, 192, 3, 2, 2, 2, 49, 194, 3, 2, 2, 2, 51, 198, 3, 2, 2, 2, 53, 204, 3, 2, 2, 2, 55, 211, 3, 2, 2, 2, 57, 216, 3, 2, 2, 2, 59, 223, 3, 2, 2, 2, 61, 225, 3, 2, 2, 2, 63, 235, 3, 2, 2, 2, 65, 245, 3, 2, 2, 2, 67, 253, 3, 2, 2, 2, 69, 260, 3, 2, 2, 2, 71, 268, 3, 2, 2, 2, 73, 276, 3, 2, 2, 2, 75, 283, 3, 2, 2, 2, 77, 287, 3, 2, 2, 2, 79, 301, 3, 2, 2, 2, 81, 307, 3, 2, 2, 2, 83, 318, 3, 2, 2, 2, 85, 332, 3, 2, 2, 2, 87, 88, 7, 107, 2, 2, 88, 89, 7, 111, 2, 2, 89, 90, 7, 114, 2, 2, 90, 91, 7, 113, 2, 2, 91, 92, 7, 116, 2, 2, 92, 93, 7, 118, 2, 2, 93, 4, 3, 2, 2, 2, 94, 95, 7, 61, 2, 2, 95, 6, 3, 2, 2, 2, 96, 97, 7, 111, 2, 2, 97, 98, 7, 113, 2, 2, 98, 99, 7, 102, 2, 2, 99, 100, 7, 119, 2, 2, 100, 101, 7, 110, 2, 2, 101, 102, 7, 103, 2, 2, 102, 8, 3, 2, 2, 2, 103, 104, 7, 107, 2, 2, 104, 105, 7, 112, 2, 2, 105, 106, 7, 118, 2, 2, 106, 107, 7, 103, 2, 2, 107, 108, 7, 116, 2, 2, 108, 109, 7, 104, 2, 2, 109, 110, 7, 99, 2, 2, 110, 111, 7, 101, 2, 2, 111, 112, 7, 103, 2, 2, 112, 10, 3, 2, 2, 2, 113, 114, 7, 103, 2, 2, 114, 115, 7, 122, 2, 2, 115, 116, 7, 118, 2, 2, 116, 117, 7, 103, 2, 2, 117, 118, 7, 112, 2, 2, 118, 119, 7, 102, 2, 2, 119, 120, 7, 117, 2, 2, 120, 12, 3, 2, 2, 2, 121, 122, 7, 125, 2, 2, 122, 14, 3, 2, 2, 2, 123, 124, 7, 127, 2, 2, 124, 16, 3, 2, 2, 2, 125, 126, 7, 120, 2, 2, 126, 127, 7, 113, 2, 2, 127, 128, 7, 107, 2, 2, 128, 129, 7, 102, 2, 2, 129, 18, 3, 2, 2, 2, 130, 131, 7, 42, 2, 2, 131, 20, 3, 2, 2, 2, 132, 133, 7, 43, 2, 2, 133, 22, 3, 2, 2, 2, 134, 135, 7, 101, 2, 2, 135, 136, 7, 113, 2, 2, 136, 137, 7, 112, 2, 2, 137, 138, 7, 117, 2, 2, 138, 139, 7, 118, 2, 2, 139, 24, 3, 2, 2, 2, 140, 141, 7, 117, 2, 2, 141, 142, 7, 107, 2, 2, 142, 143, 7, 105, 2, 2, 143, 144, 7, 112, 2, 2, 144, 145, 7, 99, 2, 2, 145, 146, 7, 110, 2, 2, 146, 26, 3, 2, 2, 2, 147, 148, 7, 63, 2, 2, 148, 28, 3, 2, 2, 2, 149, 150, 7, 116, 2, 2, 150, 151, 7, 103, 2, 2, 151, 152, 7, 99, 2, 2, 152, 153, 7, 102, 2, 2, 153, 154, 7, 113, 2, 2, 154, 155, 7, 112, 2, 2, 155, 156, 7, 110, 2, 2, 156, 157, 7, 123, 2, 2, 157, 30, 3, 2, 2, 2, 158, 159, 7, 46, 2, 2, 159, 32, 3, 2, 2, 2, 160, 161, 7, 100, 2, 2, 161, 162, 7, 113, 2, 2, 162, 163, 7, 113, 2, 2, 163, 164, 7, 110, 2, 2, 164, 34, 3, 2, 2, 2, 165, 166, 7, 107, 2, 2, 166, 167, 7, 112, 2, 2, 167, 168, 7, 118, 2, 2, 168, 36, 3, 2, 2, 2, 169, 170, 7, 116, 2, 2, 170, 171, 7, 103, 2, 2, 171, 172, 7, 99, 2, 2, 172, 173, 7, 110, 2, 2, 173, 38, 3, 2, 2, 2, 174, 175, 7, 117, 2, 2, 175, 176, 7, 118, 2, 2, 176, 177, 7, 116, 2, 2, 177, 178, 7, 107, 2, 2, 178, 179, 7, 112, 2, 2, 179, 180, 7, 105, 2, 2, 180, 40, 3, 2, 2, 2, 181, 182, 7, 120, 2, 2, 182, 183, 7, 99, 2, 2, 183, 184, 7, 116, 2, 2, 184, 42, 3, 2, 2, 2, 185, 186, 7, 110, 2, 2, 186, 187, 7, 107, 2, 2, 187, 188, 7, 117, 2, 2, 188, 189, 7, 118, 2, 2, 189, 44, 3, 2, 2, 2, 190, 191, 7, 62, 2, 2, 191, 46, 3, 2, 2, 2, 192, 193, 7, 64, 2, 2, 193, 48, 3, 2, 2, 2, 194, 195, 7, 111, 2, 2, 195, 196, 7, 99, 2, 2, 196, 197, 7, 114, 2, 2, 197, 50, 3, 2, 2, 2, 198, 199, 7, 111, 2, 2, 199, 200, 7, 113, 2, 2, 200, 201, 7, 102, 2, 2, 201, 202, 7, 103, 2, 2, 202, 203, 7, 110, 2, 2, 203, 52, 3, 2, 2, 2, 204, 205, 7, 117, 2, 2, 205, 206, 7, 118, 2, 2, 206, 207, 7, 116, 2, 2, 207, 208, 7, 119, 2, 2, 208, 209, 7, 101, 2, 2, 209, 210, 7, 118, 2, 2, 210, 54, 3, 2, 2, 2, 211, 212, 7, 103, 2, 2, 212, 213, 7, 112, 2, 2, 213, 214, 7, 119, 2, 2, 214, 215, 7, 111, 2, 2, 215, 56, 3, 2, 2, 2, 216, 217, 7, 104, 2, 2, 217, 218, 7, 110, 2, 2, 218, 219, 7, 99, 2, 2, 219, 220, 7, 105, 2, 2, 220, 58, 3, 2, 2, 2, 221, 224, 5, 61, 31, 2, 222, 224, 5, 63, 32, 2, 223, 221, 3, 2, 2, 2, 223, 222, 3, 2, 2, 2, 224, 60, 3, 2, 2, 2, 225, 230, 7, 36, 2, 2, 226, 229, 5, 85, 43, 2, 227, 229, 10, 2, 2, 2, 228, 226, 3, 2, 2, 2, 228, 227, 3, 2, 2, 2, 229, 232, 3, 2, 2, 2, 230, 228, 3, 2, 2, 2, 230, 231, 3, 2, 2, 2, 231, 233, 3, 2, 2, 2, 232, 230, 3, 2, 2, 2, 233, 234, 7, 36, 2, 2, 234, 62, 3, 2, 2, 2, 235, 240, 7, 41, 2, 2, 236, 239, 5, 85, 43, 2, 237, 239, 10, 3, 2, 2, 238, 236, 3, 2, 2, 2, 238, 237, 3, 2, 2, 2, 239, 242, 3, 2, 2, 2, 240, 238, 3, 2, 2, 2, 240, 241, 3, 2, 2, 2, 241, 243, 3, 2, 2, 2, 242, 240, 3, 2, 2, 2, 243, 244, 7, 41, 2, 2, 244, 64, 3, 2, 2, 2, 245, 249, 7, 66, 2, 2, 246, 248, 10, 4, 2, 2, 247, 246, 3, 2, 2, 2, 248, 251, 3, 2, 2, 2, 249, 247, 3, 2, 2, 2, 249, 250, 3, 2, 2, 2, 250, 66, 3, 2, 2, 2, 251, 249, 3, 2, 2, 2, 252, 254, 9, 5, 2, 2, 253, 252, 3, 2, 2, 2, 253, 254, 3, 2, 2, 2, 254, 256, 3, 2, 2, 2, 255, 257, 4, 50, 59, 2, 256, 255, 3, 2, 2, 2, 257, 258, 3, 2, 2, 2, 258, 256, 3, 2, 2, 2, 258, 259, 3, 2, 2, 2, 259, 68, 3, 2, 2, 2, 260, 261, 7, 50, 2, 2, 261, 262, 7, 122, 2, 2, 262, 264, 3, 2, 2, 2, 263, 265, 9, 6, 2, 2, 264, 263, 3, 2, 2, 2, 265, 266, 3, 2, 2, 2, 266, 264, 3, 2, 2, 2, 266, 267, 3, 2, 2, 2, 267, 70, 3, 2, 2, 2, 268, 269, 7, 66, 2, 2, 269, 273, 9, 7, 2, 2, 270, 272, 9, 8, 2, 2, 271, 270, 3, 2, 2, 2, 272, 275, 3, 2, 2, 2, 273, 271, 3, 2, 2, 2, 273, 274, 3, 2, 2, 2, 274, 72, 3, 2, 2, 2, 275, 273, 3, 2, 2, 2, 276, 280, 9, 7, 2, 2, 277, 279, 9, 8, 2, 2, 278, 277, 3, 2, 2, 2, 279, 282, 3, 2, 2, 2, 280, 278, 3, 2, 2, 2, 280, 281, 3, 2, 2, 2, 281, 74, 3, 2, 2, 2, 282, 280, 3, 2, 2, 2, 283, 284, 9, 9, 2, 2, 284, 285, 7, 48, 2, 2, 285, 286, 9, 9, 2, 2, 286, 76, 3, 2, 2, 2, 287, 288, 7, 49, 2, 2, 288, 289, 7, 44, 2, 2, 289, 290, 7, 44, 2, 2, 290, 294, 3, 2, 2, 2, 291, 293, 11, 2, 2, 2, 292, 291, 3, 2, 2, 2, 293, 296, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 294, 292, 3, 2, 2, 2, 295, 297, 3, 2, 2, 2, 296, 294, 3, 2, 2, 2, 297, 298, 7, 44, 2, 2, 298, 299, 7, 49, 2, 2, 299, 78, 3, 2, 2, 2, 300, 302, 9, 10, 2, 2, 301, 300, 3, 2, 2, 2, 302, 303, 3, 2, 2, 2, 303, 301, 3, 2, 2, 2, 303, 304, 3, 2, 2, 2, 304, 305, 3, 2, 2, 2, 305, 306, 8, 40, 2, 2, 306, 80, 3, 2, 2, 2, 307, 308, 7, 49, 2, 2, 308, 309, 7, 49, 2, 2, 309, 313, 3, 2, 2, 2, 310, 312, 10, 4, 2, 2, 311, 310, 3, 2, 2, 2, 312, 315, 3, 2, 2, 2, 313, 311, 3, 2, 2, 2, 313, 314, 3, 2, 2, 2, 314, 316, 3, 2, 2, 2, 315, 313, 3, 2, 2, 2, 316, 317, 8, 41, 2, 2, 317, 82, 3, 2, 2, 2, 318, 319, 7, 49, 2, 2, 319, 320, 7, 44, 2, 2, 320, 324, 3, 2, 2, 2, 321, 323, 11, 2, 2, 2, 322, 321, 3, 2, 2, 2, 323, 326, 3, 2, 2, 2, 324, 325, 3, 2, 2, 2, 324, 322, 3, 2, 2, 2, 325, 327, 3, 2, 2, 2, 326, 324, 3, 2, 2, 2, 327, 328, 7, 44, 2, 2, 328, 329, 7, 49, 2, 2, 329, 330, 3, 2, 2, 2, 330, 331, 8, 42, 2, 2, 331, 84, 3, 2, 2, 2, 332, 333, 7, 94, 2, 2, 333, 334, 9, 11, 2, 2, 334, 86, 3, 2, 2, 2, 18, 2, 223, 228, 230, 238, 240, 249, 253, 258, 266, 273, 280, 294, 303, 313, 324, 3, 8, 2, 2] \ No newline at end of file
diff --git a/qface/idl/parser/TLexer.py b/qface/idl/parser/TLexer.py
index ec6e345..e8ce49a 100644
--- a/qface/idl/parser/TLexer.py
+++ b/qface/idl/parser/TLexer.py
@@ -7,131 +7,149 @@ import sys
def serializedATN():
with StringIO() as buf:
- buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2(")
- buf.write("\u012c\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("\u014f\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$\4%\t%")
- buf.write("\4&\t&\4\'\t\'\3\2\3\2\3\2\3\2\3\2\3\2\3\2\3\3\3\3\3\4")
- buf.write("\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3")
- buf.write("\5\3\5\3\5\3\6\3\6\3\6\3\6\3\6\3\6\3\6\3\6\3\7\3\7\3\b")
- buf.write("\3\b\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\13\3\13\3\f\3\f\3\f")
- buf.write("\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3\16\3\16")
- buf.write("\3\16\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\20\3\20\3\21")
- buf.write("\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\23\3\23\3\23")
- buf.write("\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\25\3\25")
- buf.write("\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\27\3\27\3\30\3\30")
- buf.write("\3\31\3\31\3\31\3\31\3\32\3\32\3\32\3\32\3\32\3\32\3\33")
- buf.write("\3\33\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\3\35\3\35\3\35\3\36\3\36\7\36\u00d8\n\36\f")
- buf.write("\36\16\36\u00db\13\36\3\37\5\37\u00de\n\37\3\37\6\37\u00e1")
- buf.write("\n\37\r\37\16\37\u00e2\3 \3 \3 \3 \6 \u00e9\n \r \16 ")
- buf.write("\u00ea\3!\3!\3!\7!\u00f0\n!\f!\16!\u00f3\13!\3\"\3\"\7")
- buf.write("\"\u00f7\n\"\f\"\16\"\u00fa\13\"\3#\3#\3#\3#\3$\3$\3$")
- buf.write("\3$\3$\7$\u0105\n$\f$\16$\u0108\13$\3$\3$\3$\3%\6%\u010e")
- buf.write("\n%\r%\16%\u010f\3%\3%\3&\3&\3&\3&\7&\u0118\n&\f&\16&")
- buf.write("\u011b\13&\3&\3&\3\'\3\'\3\'\3\'\7\'\u0123\n\'\f\'\16")
- buf.write("\'\u0126\13\'\3\'\3\'\3\'\3\'\3\'\4\u0106\u0124\2(\3\3")
- buf.write("\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16")
- buf.write("\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61")
- buf.write("\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(\3\2")
- buf.write("\t\4\2\f\f\17\17\4\2--//\5\2\62;CHch\5\2C\\aac|\7\2\60")
- buf.write("\60\62;C\\aac|\3\2\62;\5\2\13\f\17\17\"\"\2\u0135\2\3")
- buf.write("\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2")
- buf.write("\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2")
- buf.write("\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2")
- buf.write("\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3")
- buf.write("\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2")
- buf.write("/\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67")
- buf.write("\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2")
- buf.write("A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2")
- buf.write("\2K\3\2\2\2\2M\3\2\2\2\3O\3\2\2\2\5V\3\2\2\2\7X\3\2\2")
- buf.write("\2\t_\3\2\2\2\13i\3\2\2\2\rq\3\2\2\2\17s\3\2\2\2\21u\3")
- buf.write("\2\2\2\23z\3\2\2\2\25|\3\2\2\2\27~\3\2\2\2\31\u0084\3")
- buf.write("\2\2\2\33\u008b\3\2\2\2\35\u0094\3\2\2\2\37\u0096\3\2")
- buf.write("\2\2!\u0098\3\2\2\2#\u009d\3\2\2\2%\u00a1\3\2\2\2\'\u00a6")
- buf.write("\3\2\2\2)\u00ad\3\2\2\2+\u00b1\3\2\2\2-\u00b6\3\2\2\2")
- buf.write("/\u00b8\3\2\2\2\61\u00ba\3\2\2\2\63\u00be\3\2\2\2\65\u00c4")
- buf.write("\3\2\2\2\67\u00cb\3\2\2\29\u00d0\3\2\2\2;\u00d5\3\2\2")
- buf.write("\2=\u00dd\3\2\2\2?\u00e4\3\2\2\2A\u00ec\3\2\2\2C\u00f4")
- buf.write("\3\2\2\2E\u00fb\3\2\2\2G\u00ff\3\2\2\2I\u010d\3\2\2\2")
- buf.write("K\u0113\3\2\2\2M\u011e\3\2\2\2OP\7k\2\2PQ\7o\2\2QR\7r")
- buf.write("\2\2RS\7q\2\2ST\7t\2\2TU\7v\2\2U\4\3\2\2\2VW\7=\2\2W\6")
- buf.write("\3\2\2\2XY\7o\2\2YZ\7q\2\2Z[\7f\2\2[\\\7w\2\2\\]\7n\2")
- buf.write("\2]^\7g\2\2^\b\3\2\2\2_`\7k\2\2`a\7p\2\2ab\7v\2\2bc\7")
- buf.write("g\2\2cd\7t\2\2de\7h\2\2ef\7c\2\2fg\7e\2\2gh\7g\2\2h\n")
- buf.write("\3\2\2\2ij\7g\2\2jk\7z\2\2kl\7v\2\2lm\7g\2\2mn\7p\2\2")
- buf.write("no\7f\2\2op\7u\2\2p\f\3\2\2\2qr\7}\2\2r\16\3\2\2\2st\7")
- buf.write("\177\2\2t\20\3\2\2\2uv\7x\2\2vw\7q\2\2wx\7k\2\2xy\7f\2")
- buf.write("\2y\22\3\2\2\2z{\7*\2\2{\24\3\2\2\2|}\7+\2\2}\26\3\2\2")
- buf.write("\2~\177\7e\2\2\177\u0080\7q\2\2\u0080\u0081\7p\2\2\u0081")
- buf.write("\u0082\7u\2\2\u0082\u0083\7v\2\2\u0083\30\3\2\2\2\u0084")
- buf.write("\u0085\7u\2\2\u0085\u0086\7k\2\2\u0086\u0087\7i\2\2\u0087")
- buf.write("\u0088\7p\2\2\u0088\u0089\7c\2\2\u0089\u008a\7n\2\2\u008a")
- buf.write("\32\3\2\2\2\u008b\u008c\7t\2\2\u008c\u008d\7g\2\2\u008d")
- buf.write("\u008e\7c\2\2\u008e\u008f\7f\2\2\u008f\u0090\7q\2\2\u0090")
- buf.write("\u0091\7p\2\2\u0091\u0092\7n\2\2\u0092\u0093\7{\2\2\u0093")
- buf.write("\34\3\2\2\2\u0094\u0095\7.\2\2\u0095\36\3\2\2\2\u0096")
- buf.write("\u0097\7?\2\2\u0097 \3\2\2\2\u0098\u0099\7d\2\2\u0099")
- buf.write("\u009a\7q\2\2\u009a\u009b\7q\2\2\u009b\u009c\7n\2\2\u009c")
- buf.write("\"\3\2\2\2\u009d\u009e\7k\2\2\u009e\u009f\7p\2\2\u009f")
- buf.write("\u00a0\7v\2\2\u00a0$\3\2\2\2\u00a1\u00a2\7t\2\2\u00a2")
- buf.write("\u00a3\7g\2\2\u00a3\u00a4\7c\2\2\u00a4\u00a5\7n\2\2\u00a5")
- buf.write("&\3\2\2\2\u00a6\u00a7\7u\2\2\u00a7\u00a8\7v\2\2\u00a8")
- buf.write("\u00a9\7t\2\2\u00a9\u00aa\7k\2\2\u00aa\u00ab\7p\2\2\u00ab")
- buf.write("\u00ac\7i\2\2\u00ac(\3\2\2\2\u00ad\u00ae\7x\2\2\u00ae")
- buf.write("\u00af\7c\2\2\u00af\u00b0\7t\2\2\u00b0*\3\2\2\2\u00b1")
- buf.write("\u00b2\7n\2\2\u00b2\u00b3\7k\2\2\u00b3\u00b4\7u\2\2\u00b4")
- buf.write("\u00b5\7v\2\2\u00b5,\3\2\2\2\u00b6\u00b7\7>\2\2\u00b7")
- buf.write(".\3\2\2\2\u00b8\u00b9\7@\2\2\u00b9\60\3\2\2\2\u00ba\u00bb")
- buf.write("\7o\2\2\u00bb\u00bc\7c\2\2\u00bc\u00bd\7r\2\2\u00bd\62")
- buf.write("\3\2\2\2\u00be\u00bf\7o\2\2\u00bf\u00c0\7q\2\2\u00c0\u00c1")
- buf.write("\7f\2\2\u00c1\u00c2\7g\2\2\u00c2\u00c3\7n\2\2\u00c3\64")
- buf.write("\3\2\2\2\u00c4\u00c5\7u\2\2\u00c5\u00c6\7v\2\2\u00c6\u00c7")
- buf.write("\7t\2\2\u00c7\u00c8\7w\2\2\u00c8\u00c9\7e\2\2\u00c9\u00ca")
- buf.write("\7v\2\2\u00ca\66\3\2\2\2\u00cb\u00cc\7g\2\2\u00cc\u00cd")
- buf.write("\7p\2\2\u00cd\u00ce\7w\2\2\u00ce\u00cf\7o\2\2\u00cf8\3")
- buf.write("\2\2\2\u00d0\u00d1\7h\2\2\u00d1\u00d2\7n\2\2\u00d2\u00d3")
- buf.write("\7c\2\2\u00d3\u00d4\7i\2\2\u00d4:\3\2\2\2\u00d5\u00d9")
- buf.write("\7B\2\2\u00d6\u00d8\n\2\2\2\u00d7\u00d6\3\2\2\2\u00d8")
- buf.write("\u00db\3\2\2\2\u00d9\u00d7\3\2\2\2\u00d9\u00da\3\2\2\2")
- buf.write("\u00da<\3\2\2\2\u00db\u00d9\3\2\2\2\u00dc\u00de\t\3\2")
- buf.write("\2\u00dd\u00dc\3\2\2\2\u00dd\u00de\3\2\2\2\u00de\u00e0")
- buf.write("\3\2\2\2\u00df\u00e1\4\62;\2\u00e0\u00df\3\2\2\2\u00e1")
- buf.write("\u00e2\3\2\2\2\u00e2\u00e0\3\2\2\2\u00e2\u00e3\3\2\2\2")
- buf.write("\u00e3>\3\2\2\2\u00e4\u00e5\7\62\2\2\u00e5\u00e6\7z\2")
- buf.write("\2\u00e6\u00e8\3\2\2\2\u00e7\u00e9\t\4\2\2\u00e8\u00e7")
- buf.write("\3\2\2\2\u00e9\u00ea\3\2\2\2\u00ea\u00e8\3\2\2\2\u00ea")
- buf.write("\u00eb\3\2\2\2\u00eb@\3\2\2\2\u00ec\u00ed\7B\2\2\u00ed")
- buf.write("\u00f1\t\5\2\2\u00ee\u00f0\t\6\2\2\u00ef\u00ee\3\2\2\2")
- buf.write("\u00f0\u00f3\3\2\2\2\u00f1\u00ef\3\2\2\2\u00f1\u00f2\3")
- buf.write("\2\2\2\u00f2B\3\2\2\2\u00f3\u00f1\3\2\2\2\u00f4\u00f8")
- buf.write("\t\5\2\2\u00f5\u00f7\t\6\2\2\u00f6\u00f5\3\2\2\2\u00f7")
- buf.write("\u00fa\3\2\2\2\u00f8\u00f6\3\2\2\2\u00f8\u00f9\3\2\2\2")
- buf.write("\u00f9D\3\2\2\2\u00fa\u00f8\3\2\2\2\u00fb\u00fc\t\7\2")
- buf.write("\2\u00fc\u00fd\7\60\2\2\u00fd\u00fe\t\7\2\2\u00feF\3\2")
- buf.write("\2\2\u00ff\u0100\7\61\2\2\u0100\u0101\7,\2\2\u0101\u0102")
- buf.write("\7,\2\2\u0102\u0106\3\2\2\2\u0103\u0105\13\2\2\2\u0104")
- buf.write("\u0103\3\2\2\2\u0105\u0108\3\2\2\2\u0106\u0107\3\2\2\2")
- buf.write("\u0106\u0104\3\2\2\2\u0107\u0109\3\2\2\2\u0108\u0106\3")
- buf.write("\2\2\2\u0109\u010a\7,\2\2\u010a\u010b\7\61\2\2\u010bH")
- buf.write("\3\2\2\2\u010c\u010e\t\b\2\2\u010d\u010c\3\2\2\2\u010e")
- buf.write("\u010f\3\2\2\2\u010f\u010d\3\2\2\2\u010f\u0110\3\2\2\2")
- buf.write("\u0110\u0111\3\2\2\2\u0111\u0112\b%\2\2\u0112J\3\2\2\2")
- buf.write("\u0113\u0114\7\61\2\2\u0114\u0115\7\61\2\2\u0115\u0119")
- buf.write("\3\2\2\2\u0116\u0118\n\2\2\2\u0117\u0116\3\2\2\2\u0118")
- buf.write("\u011b\3\2\2\2\u0119\u0117\3\2\2\2\u0119\u011a\3\2\2\2")
- buf.write("\u011a\u011c\3\2\2\2\u011b\u0119\3\2\2\2\u011c\u011d\b")
- buf.write("&\2\2\u011dL\3\2\2\2\u011e\u011f\7\61\2\2\u011f\u0120")
- buf.write("\7,\2\2\u0120\u0124\3\2\2\2\u0121\u0123\13\2\2\2\u0122")
- buf.write("\u0121\3\2\2\2\u0123\u0126\3\2\2\2\u0124\u0125\3\2\2\2")
- buf.write("\u0124\u0122\3\2\2\2\u0125\u0127\3\2\2\2\u0126\u0124\3")
- buf.write("\2\2\2\u0127\u0128\7,\2\2\u0128\u0129\7\61\2\2\u0129\u012a")
- buf.write("\3\2\2\2\u012a\u012b\b\'\2\2\u012bN\3\2\2\2\r\2\u00d9")
- buf.write("\u00dd\u00e2\u00ea\u00f1\u00f8\u0106\u010f\u0119\u0124")
- buf.write("\3\b\2\2")
+ buf.write("\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\3\2\3\2\3\2\3\2")
+ buf.write("\3\2\3\2\3\2\3\3\3\3\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\5\3")
+ buf.write("\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3\6\3\6\3\6")
+ buf.write("\3\6\3\6\3\6\3\7\3\7\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\n\3")
+ buf.write("\n\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\r\3\r\3")
+ buf.write("\r\3\r\3\r\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\17\3\17")
+ buf.write("\3\17\3\17\3\20\3\20\3\21\3\21\3\21\3\21\3\21\3\22\3\22")
+ buf.write("\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24")
+ buf.write("\3\24\3\24\3\24\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26")
+ buf.write("\3\26\3\27\3\27\3\30\3\30\3\31\3\31\3\31\3\31\3\32\3\32")
+ buf.write("\3\32\3\32\3\32\3\32\3\33\3\33\3\33\3\33\3\33\3\33\3\33")
+ buf.write("\3\34\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\3\36")
+ buf.write("\3\36\5\36\u00e0\n\36\3\37\3\37\3\37\7\37\u00e5\n\37\f")
+ buf.write("\37\16\37\u00e8\13\37\3\37\3\37\3 \3 \3 \7 \u00ef\n \f")
+ buf.write(" \16 \u00f2\13 \3 \3 \3!\3!\7!\u00f8\n!\f!\16!\u00fb\13")
+ buf.write("!\3\"\5\"\u00fe\n\"\3\"\6\"\u0101\n\"\r\"\16\"\u0102\3")
+ buf.write("#\3#\3#\3#\6#\u0109\n#\r#\16#\u010a\3$\3$\3$\7$\u0110")
+ buf.write("\n$\f$\16$\u0113\13$\3%\3%\7%\u0117\n%\f%\16%\u011a\13")
+ buf.write("%\3&\3&\3&\3&\3\'\3\'\3\'\3\'\3\'\7\'\u0125\n\'\f\'\16")
+ buf.write("\'\u0128\13\'\3\'\3\'\3\'\3(\6(\u012e\n(\r(\16(\u012f")
+ buf.write("\3(\3(\3)\3)\3)\3)\7)\u0138\n)\f)\16)\u013b\13)\3)\3)")
+ buf.write("\3*\3*\3*\3*\7*\u0143\n*\f*\16*\u0146\13*\3*\3*\3*\3*")
+ buf.write("\3*\3+\3+\3+\4\u0126\u0144\2,\3\3\5\4\7\5\t\6\13\7\r\b")
+ buf.write("\17\t\21\n\23\13\25\f\27\r\31\16\33\17\35\20\37\21!\22")
+ buf.write("#\23%\24\'\25)\26+\27-\30/\31\61\32\63\33\65\34\67\35")
+ buf.write("9\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U\2\3\2\f\4\2$$^^\4")
+ buf.write("\2))^^\4\2\f\f\17\17\4\2--//\5\2\62;CHch\5\2C\\aac|\7")
+ buf.write("\2\60\60\62;C\\aac|\3\2\62;\5\2\13\f\17\17\"\"\n\2$$\61")
+ buf.write("\61^^ddhhppttvv\2\u015c\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3")
+ buf.write("\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\2")
+ buf.write("\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3\2\2\2")
+ buf.write("\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2")
+ buf.write("!\3\2\2\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2")
+ buf.write("\2+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2\2\2\63\3")
+ buf.write("\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2")
+ buf.write("\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2")
+ buf.write("\2\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2")
+ buf.write("\2\2\2Q\3\2\2\2\2S\3\2\2\2\3W\3\2\2\2\5^\3\2\2\2\7`\3")
+ buf.write("\2\2\2\tg\3\2\2\2\13q\3\2\2\2\ry\3\2\2\2\17{\3\2\2\2\21")
+ buf.write("}\3\2\2\2\23\u0082\3\2\2\2\25\u0084\3\2\2\2\27\u0086\3")
+ buf.write("\2\2\2\31\u008c\3\2\2\2\33\u0093\3\2\2\2\35\u0095\3\2")
+ buf.write("\2\2\37\u009e\3\2\2\2!\u00a0\3\2\2\2#\u00a5\3\2\2\2%\u00a9")
+ buf.write("\3\2\2\2\'\u00ae\3\2\2\2)\u00b5\3\2\2\2+\u00b9\3\2\2\2")
+ buf.write("-\u00be\3\2\2\2/\u00c0\3\2\2\2\61\u00c2\3\2\2\2\63\u00c6")
+ buf.write("\3\2\2\2\65\u00cc\3\2\2\2\67\u00d3\3\2\2\29\u00d8\3\2")
+ buf.write("\2\2;\u00df\3\2\2\2=\u00e1\3\2\2\2?\u00eb\3\2\2\2A\u00f5")
+ buf.write("\3\2\2\2C\u00fd\3\2\2\2E\u0104\3\2\2\2G\u010c\3\2\2\2")
+ buf.write("I\u0114\3\2\2\2K\u011b\3\2\2\2M\u011f\3\2\2\2O\u012d\3")
+ buf.write("\2\2\2Q\u0133\3\2\2\2S\u013e\3\2\2\2U\u014c\3\2\2\2WX")
+ buf.write("\7k\2\2XY\7o\2\2YZ\7r\2\2Z[\7q\2\2[\\\7t\2\2\\]\7v\2\2")
+ buf.write("]\4\3\2\2\2^_\7=\2\2_\6\3\2\2\2`a\7o\2\2ab\7q\2\2bc\7")
+ buf.write("f\2\2cd\7w\2\2de\7n\2\2ef\7g\2\2f\b\3\2\2\2gh\7k\2\2h")
+ buf.write("i\7p\2\2ij\7v\2\2jk\7g\2\2kl\7t\2\2lm\7h\2\2mn\7c\2\2")
+ buf.write("no\7e\2\2op\7g\2\2p\n\3\2\2\2qr\7g\2\2rs\7z\2\2st\7v\2")
+ buf.write("\2tu\7g\2\2uv\7p\2\2vw\7f\2\2wx\7u\2\2x\f\3\2\2\2yz\7")
+ buf.write("}\2\2z\16\3\2\2\2{|\7\177\2\2|\20\3\2\2\2}~\7x\2\2~\177")
+ buf.write("\7q\2\2\177\u0080\7k\2\2\u0080\u0081\7f\2\2\u0081\22\3")
+ buf.write("\2\2\2\u0082\u0083\7*\2\2\u0083\24\3\2\2\2\u0084\u0085")
+ buf.write("\7+\2\2\u0085\26\3\2\2\2\u0086\u0087\7e\2\2\u0087\u0088")
+ buf.write("\7q\2\2\u0088\u0089\7p\2\2\u0089\u008a\7u\2\2\u008a\u008b")
+ buf.write("\7v\2\2\u008b\30\3\2\2\2\u008c\u008d\7u\2\2\u008d\u008e")
+ buf.write("\7k\2\2\u008e\u008f\7i\2\2\u008f\u0090\7p\2\2\u0090\u0091")
+ buf.write("\7c\2\2\u0091\u0092\7n\2\2\u0092\32\3\2\2\2\u0093\u0094")
+ buf.write("\7?\2\2\u0094\34\3\2\2\2\u0095\u0096\7t\2\2\u0096\u0097")
+ buf.write("\7g\2\2\u0097\u0098\7c\2\2\u0098\u0099\7f\2\2\u0099\u009a")
+ buf.write("\7q\2\2\u009a\u009b\7p\2\2\u009b\u009c\7n\2\2\u009c\u009d")
+ buf.write("\7{\2\2\u009d\36\3\2\2\2\u009e\u009f\7.\2\2\u009f \3\2")
+ buf.write("\2\2\u00a0\u00a1\7d\2\2\u00a1\u00a2\7q\2\2\u00a2\u00a3")
+ buf.write("\7q\2\2\u00a3\u00a4\7n\2\2\u00a4\"\3\2\2\2\u00a5\u00a6")
+ buf.write("\7k\2\2\u00a6\u00a7\7p\2\2\u00a7\u00a8\7v\2\2\u00a8$\3")
+ buf.write("\2\2\2\u00a9\u00aa\7t\2\2\u00aa\u00ab\7g\2\2\u00ab\u00ac")
+ buf.write("\7c\2\2\u00ac\u00ad\7n\2\2\u00ad&\3\2\2\2\u00ae\u00af")
+ buf.write("\7u\2\2\u00af\u00b0\7v\2\2\u00b0\u00b1\7t\2\2\u00b1\u00b2")
+ buf.write("\7k\2\2\u00b2\u00b3\7p\2\2\u00b3\u00b4\7i\2\2\u00b4(\3")
+ buf.write("\2\2\2\u00b5\u00b6\7x\2\2\u00b6\u00b7\7c\2\2\u00b7\u00b8")
+ buf.write("\7t\2\2\u00b8*\3\2\2\2\u00b9\u00ba\7n\2\2\u00ba\u00bb")
+ buf.write("\7k\2\2\u00bb\u00bc\7u\2\2\u00bc\u00bd\7v\2\2\u00bd,\3")
+ buf.write("\2\2\2\u00be\u00bf\7>\2\2\u00bf.\3\2\2\2\u00c0\u00c1\7")
+ buf.write("@\2\2\u00c1\60\3\2\2\2\u00c2\u00c3\7o\2\2\u00c3\u00c4")
+ buf.write("\7c\2\2\u00c4\u00c5\7r\2\2\u00c5\62\3\2\2\2\u00c6\u00c7")
+ buf.write("\7o\2\2\u00c7\u00c8\7q\2\2\u00c8\u00c9\7f\2\2\u00c9\u00ca")
+ buf.write("\7g\2\2\u00ca\u00cb\7n\2\2\u00cb\64\3\2\2\2\u00cc\u00cd")
+ buf.write("\7u\2\2\u00cd\u00ce\7v\2\2\u00ce\u00cf\7t\2\2\u00cf\u00d0")
+ buf.write("\7w\2\2\u00d0\u00d1\7e\2\2\u00d1\u00d2\7v\2\2\u00d2\66")
+ buf.write("\3\2\2\2\u00d3\u00d4\7g\2\2\u00d4\u00d5\7p\2\2\u00d5\u00d6")
+ buf.write("\7w\2\2\u00d6\u00d7\7o\2\2\u00d78\3\2\2\2\u00d8\u00d9")
+ buf.write("\7h\2\2\u00d9\u00da\7n\2\2\u00da\u00db\7c\2\2\u00db\u00dc")
+ buf.write("\7i\2\2\u00dc:\3\2\2\2\u00dd\u00e0\5=\37\2\u00de\u00e0")
+ buf.write("\5? \2\u00df\u00dd\3\2\2\2\u00df\u00de\3\2\2\2\u00e0<")
+ buf.write("\3\2\2\2\u00e1\u00e6\7$\2\2\u00e2\u00e5\5U+\2\u00e3\u00e5")
+ buf.write("\n\2\2\2\u00e4\u00e2\3\2\2\2\u00e4\u00e3\3\2\2\2\u00e5")
+ buf.write("\u00e8\3\2\2\2\u00e6\u00e4\3\2\2\2\u00e6\u00e7\3\2\2\2")
+ buf.write("\u00e7\u00e9\3\2\2\2\u00e8\u00e6\3\2\2\2\u00e9\u00ea\7")
+ buf.write("$\2\2\u00ea>\3\2\2\2\u00eb\u00f0\7)\2\2\u00ec\u00ef\5")
+ buf.write("U+\2\u00ed\u00ef\n\3\2\2\u00ee\u00ec\3\2\2\2\u00ee\u00ed")
+ buf.write("\3\2\2\2\u00ef\u00f2\3\2\2\2\u00f0\u00ee\3\2\2\2\u00f0")
+ buf.write("\u00f1\3\2\2\2\u00f1\u00f3\3\2\2\2\u00f2\u00f0\3\2\2\2")
+ buf.write("\u00f3\u00f4\7)\2\2\u00f4@\3\2\2\2\u00f5\u00f9\7B\2\2")
+ buf.write("\u00f6\u00f8\n\4\2\2\u00f7\u00f6\3\2\2\2\u00f8\u00fb\3")
+ buf.write("\2\2\2\u00f9\u00f7\3\2\2\2\u00f9\u00fa\3\2\2\2\u00faB")
+ buf.write("\3\2\2\2\u00fb\u00f9\3\2\2\2\u00fc\u00fe\t\5\2\2\u00fd")
+ buf.write("\u00fc\3\2\2\2\u00fd\u00fe\3\2\2\2\u00fe\u0100\3\2\2\2")
+ buf.write("\u00ff\u0101\4\62;\2\u0100\u00ff\3\2\2\2\u0101\u0102\3")
+ buf.write("\2\2\2\u0102\u0100\3\2\2\2\u0102\u0103\3\2\2\2\u0103D")
+ buf.write("\3\2\2\2\u0104\u0105\7\62\2\2\u0105\u0106\7z\2\2\u0106")
+ buf.write("\u0108\3\2\2\2\u0107\u0109\t\6\2\2\u0108\u0107\3\2\2\2")
+ buf.write("\u0109\u010a\3\2\2\2\u010a\u0108\3\2\2\2\u010a\u010b\3")
+ buf.write("\2\2\2\u010bF\3\2\2\2\u010c\u010d\7B\2\2\u010d\u0111\t")
+ buf.write("\7\2\2\u010e\u0110\t\b\2\2\u010f\u010e\3\2\2\2\u0110\u0113")
+ buf.write("\3\2\2\2\u0111\u010f\3\2\2\2\u0111\u0112\3\2\2\2\u0112")
+ buf.write("H\3\2\2\2\u0113\u0111\3\2\2\2\u0114\u0118\t\7\2\2\u0115")
+ buf.write("\u0117\t\b\2\2\u0116\u0115\3\2\2\2\u0117\u011a\3\2\2\2")
+ buf.write("\u0118\u0116\3\2\2\2\u0118\u0119\3\2\2\2\u0119J\3\2\2")
+ buf.write("\2\u011a\u0118\3\2\2\2\u011b\u011c\t\t\2\2\u011c\u011d")
+ buf.write("\7\60\2\2\u011d\u011e\t\t\2\2\u011eL\3\2\2\2\u011f\u0120")
+ buf.write("\7\61\2\2\u0120\u0121\7,\2\2\u0121\u0122\7,\2\2\u0122")
+ buf.write("\u0126\3\2\2\2\u0123\u0125\13\2\2\2\u0124\u0123\3\2\2")
+ buf.write("\2\u0125\u0128\3\2\2\2\u0126\u0127\3\2\2\2\u0126\u0124")
+ buf.write("\3\2\2\2\u0127\u0129\3\2\2\2\u0128\u0126\3\2\2\2\u0129")
+ buf.write("\u012a\7,\2\2\u012a\u012b\7\61\2\2\u012bN\3\2\2\2\u012c")
+ buf.write("\u012e\t\n\2\2\u012d\u012c\3\2\2\2\u012e\u012f\3\2\2\2")
+ buf.write("\u012f\u012d\3\2\2\2\u012f\u0130\3\2\2\2\u0130\u0131\3")
+ buf.write("\2\2\2\u0131\u0132\b(\2\2\u0132P\3\2\2\2\u0133\u0134\7")
+ buf.write("\61\2\2\u0134\u0135\7\61\2\2\u0135\u0139\3\2\2\2\u0136")
+ buf.write("\u0138\n\4\2\2\u0137\u0136\3\2\2\2\u0138\u013b\3\2\2\2")
+ buf.write("\u0139\u0137\3\2\2\2\u0139\u013a\3\2\2\2\u013a\u013c\3")
+ buf.write("\2\2\2\u013b\u0139\3\2\2\2\u013c\u013d\b)\2\2\u013dR\3")
+ buf.write("\2\2\2\u013e\u013f\7\61\2\2\u013f\u0140\7,\2\2\u0140\u0144")
+ buf.write("\3\2\2\2\u0141\u0143\13\2\2\2\u0142\u0141\3\2\2\2\u0143")
+ buf.write("\u0146\3\2\2\2\u0144\u0145\3\2\2\2\u0144\u0142\3\2\2\2")
+ buf.write("\u0145\u0147\3\2\2\2\u0146\u0144\3\2\2\2\u0147\u0148\7")
+ buf.write(",\2\2\u0148\u0149\7\61\2\2\u0149\u014a\3\2\2\2\u014a\u014b")
+ buf.write("\b*\2\2\u014bT\3\2\2\2\u014c\u014d\7^\2\2\u014d\u014e")
+ buf.write("\t\13\2\2\u014eV\3\2\2\2\22\2\u00df\u00e4\u00e6\u00ee")
+ buf.write("\u00f0\u00f9\u00fd\u0102\u010a\u0111\u0118\u0126\u012f")
+ buf.write("\u0139\u0144\3\b\2\2")
return buf.getvalue()
@@ -169,16 +187,19 @@ class TLexer(Lexer):
T__25 = 26
T__26 = 27
T__27 = 28
- TAGLINE = 29
- INTCONSTANT = 30
- HEXCONSTANT = 31
- TAGIDENTIFIER = 32
- IDENTIFIER = 33
- VERSION = 34
- DOCCOMMENT = 35
- WHITESPACE = 36
- COMMENT = 37
- MULTICOMM = 38
+ STRING = 29
+ DOUBLE_STRING = 30
+ SINGLE_STRING = 31
+ TAGLINE = 32
+ INTCONSTANT = 33
+ HEXCONSTANT = 34
+ TAGIDENTIFIER = 35
+ IDENTIFIER = 36
+ VERSION = 37
+ DOCCOMMENT = 38
+ WHITESPACE = 39
+ COMMENT = 40
+ MULTICOMM = 41
channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ]
@@ -186,22 +207,24 @@ class TLexer(Lexer):
literalNames = [ "<INVALID>",
"'import'", "';'", "'module'", "'interface'", "'extends'", "'{'",
- "'}'", "'void'", "'('", "')'", "'const'", "'signal'", "'readonly'",
- "','", "'='", "'bool'", "'int'", "'real'", "'string'", "'var'",
- "'list'", "'<'", "'>'", "'map'", "'model'", "'struct'", "'enum'",
- "'flag'" ]
+ "'}'", "'void'", "'('", "')'", "'const'", "'signal'", "'='",
+ "'readonly'", "','", "'bool'", "'int'", "'real'", "'string'",
+ "'var'", "'list'", "'<'", "'>'", "'map'", "'model'", "'struct'",
+ "'enum'", "'flag'" ]
symbolicNames = [ "<INVALID>",
- "TAGLINE", "INTCONSTANT", "HEXCONSTANT", "TAGIDENTIFIER", "IDENTIFIER",
- "VERSION", "DOCCOMMENT", "WHITESPACE", "COMMENT", "MULTICOMM" ]
+ "STRING", "DOUBLE_STRING", "SINGLE_STRING", "TAGLINE", "INTCONSTANT",
+ "HEXCONSTANT", "TAGIDENTIFIER", "IDENTIFIER", "VERSION", "DOCCOMMENT",
+ "WHITESPACE", "COMMENT", "MULTICOMM" ]
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", "T__25",
- "T__26", "T__27", "TAGLINE", "INTCONSTANT", "HEXCONSTANT",
- "TAGIDENTIFIER", "IDENTIFIER", "VERSION", "DOCCOMMENT",
- "WHITESPACE", "COMMENT", "MULTICOMM" ]
+ "T__26", "T__27", "STRING", "DOUBLE_STRING", "SINGLE_STRING",
+ "TAGLINE", "INTCONSTANT", "HEXCONSTANT", "TAGIDENTIFIER",
+ "IDENTIFIER", "VERSION", "DOCCOMMENT", "WHITESPACE", "COMMENT",
+ "MULTICOMM", "ESC" ]
grammarFileName = "T.g4"
diff --git a/qface/idl/parser/TLexer.tokens b/qface/idl/parser/TLexer.tokens
index 4f861bd..5daf716 100644
--- a/qface/idl/parser/TLexer.tokens
+++ b/qface/idl/parser/TLexer.tokens
@@ -26,16 +26,19 @@ T__24=25
T__25=26
T__26=27
T__27=28
-TAGLINE=29
-INTCONSTANT=30
-HEXCONSTANT=31
-TAGIDENTIFIER=32
-IDENTIFIER=33
-VERSION=34
-DOCCOMMENT=35
-WHITESPACE=36
-COMMENT=37
-MULTICOMM=38
+STRING=29
+DOUBLE_STRING=30
+SINGLE_STRING=31
+TAGLINE=32
+INTCONSTANT=33
+HEXCONSTANT=34
+TAGIDENTIFIER=35
+IDENTIFIER=36
+VERSION=37
+DOCCOMMENT=38
+WHITESPACE=39
+COMMENT=40
+MULTICOMM=41
'import'=1
';'=2
'module'=3
@@ -48,9 +51,9 @@ MULTICOMM=38
')'=10
'const'=11
'signal'=12
-'readonly'=13
-','=14
-'='=15
+'='=13
+'readonly'=14
+','=15
'bool'=16
'int'=17
'real'=18
diff --git a/qface/idl/parser/TParser.py b/qface/idl/parser/TParser.py
index e8a929c..4b411a9 100644
--- a/qface/idl/parser/TParser.py
+++ b/qface/idl/parser/TParser.py
@@ -7,8 +7,8 @@ import sys
def serializedATN():
with StringIO() as buf:
- buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3(")
- buf.write("\u014a\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("\u0152\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")
@@ -26,141 +26,146 @@ def serializedATN():
buf.write("\3\13\3\13\3\13\7\13\u00ab\n\13\f\13\16\13\u00ae\13\13")
buf.write("\3\13\3\13\5\13\u00b2\n\13\3\f\5\f\u00b5\n\f\3\f\7\f\u00b8")
buf.write("\n\f\f\f\16\f\u00bb\13\f\3\f\5\f\u00be\n\f\3\f\3\f\3\f")
- buf.write("\5\f\u00c3\n\f\3\r\3\r\5\r\u00c7\n\r\3\16\3\16\3\16\5")
- buf.write("\16\u00cc\n\16\3\17\3\17\3\20\3\20\3\20\5\20\u00d3\n\20")
- buf.write("\3\20\5\20\u00d6\n\20\3\21\3\21\3\21\3\21\3\21\5\21\u00dd")
- buf.write("\n\21\3\22\3\22\3\23\3\23\3\23\3\23\3\23\5\23\u00e6\n")
- buf.write("\23\3\24\3\24\3\24\3\24\3\24\3\25\3\25\3\25\3\25\3\25")
- buf.write("\3\26\3\26\3\26\3\26\3\26\3\27\5\27\u00f8\n\27\3\27\7")
- buf.write("\27\u00fb\n\27\f\27\16\27\u00fe\13\27\3\27\3\27\3\27\3")
- buf.write("\27\7\27\u0104\n\27\f\27\16\27\u0107\13\27\3\27\3\27\5")
- buf.write("\27\u010b\n\27\3\30\5\30\u010e\n\30\3\30\7\30\u0111\n")
- buf.write("\30\f\30\16\30\u0114\13\30\3\30\3\30\3\30\5\30\u0119\n")
- buf.write("\30\3\31\5\31\u011c\n\31\3\31\7\31\u011f\n\31\f\31\16")
- buf.write("\31\u0122\13\31\3\31\3\31\3\31\3\31\7\31\u0128\n\31\f")
- buf.write("\31\16\31\u012b\13\31\3\31\3\31\5\31\u012f\n\31\3\32\3")
- buf.write("\32\5\32\u0133\n\32\3\33\5\33\u0136\n\33\3\33\7\33\u0139")
- buf.write("\n\33\f\33\16\33\u013c\13\33\3\33\3\33\3\33\5\33\u0141")
- buf.write("\n\33\3\33\5\33\u0144\n\33\3\34\3\34\5\34\u0148\n\34\3")
- buf.write("\34\2\2\35\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$")
- buf.write("&(*,.\60\62\64\66\2\2\2\u0168\28\3\2\2\2\4?\3\2\2\2\6")
- buf.write("F\3\2\2\2\bM\3\2\2\2\n^\3\2\2\2\fa\3\2\2\2\16}\3\2\2\2")
- buf.write("\20\u0080\3\2\2\2\22\u009b\3\2\2\2\24\u009e\3\2\2\2\26")
- buf.write("\u00b4\3\2\2\2\30\u00c6\3\2\2\2\32\u00c8\3\2\2\2\34\u00cd")
- buf.write("\3\2\2\2\36\u00cf\3\2\2\2 \u00dc\3\2\2\2\"\u00de\3\2\2")
- buf.write("\2$\u00e5\3\2\2\2&\u00e7\3\2\2\2(\u00ec\3\2\2\2*\u00f1")
- buf.write("\3\2\2\2,\u00f7\3\2\2\2.\u010d\3\2\2\2\60\u011b\3\2\2")
- buf.write("\2\62\u0132\3\2\2\2\64\u0135\3\2\2\2\66\u0147\3\2\2\2")
- buf.write("8<\5\4\3\29;\5\n\6\2:9\3\2\2\2;>\3\2\2\2<:\3\2\2\2<=\3")
- buf.write("\2\2\2=\3\3\2\2\2><\3\2\2\2?C\5\b\5\2@B\5\6\4\2A@\3\2")
- buf.write("\2\2BE\3\2\2\2CA\3\2\2\2CD\3\2\2\2D\5\3\2\2\2EC\3\2\2")
- buf.write("\2FG\7\3\2\2GH\7#\2\2HJ\7$\2\2IK\7\4\2\2JI\3\2\2\2JK\3")
- buf.write("\2\2\2K\7\3\2\2\2LN\7%\2\2ML\3\2\2\2MN\3\2\2\2NR\3\2\2")
+ buf.write("\3\f\5\f\u00c4\n\f\3\f\5\f\u00c7\n\f\3\r\3\r\5\r\u00cb")
+ buf.write("\n\r\3\16\3\16\3\16\5\16\u00d0\n\16\3\17\3\17\3\20\3\20")
+ buf.write("\3\20\5\20\u00d7\n\20\3\20\5\20\u00da\n\20\3\21\3\21\3")
+ buf.write("\21\3\21\3\21\5\21\u00e1\n\21\3\22\3\22\3\23\3\23\3\23")
+ buf.write("\3\23\3\23\5\23\u00ea\n\23\3\24\3\24\3\24\3\24\3\24\3")
+ buf.write("\25\3\25\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\26\3\27")
+ buf.write("\5\27\u00fc\n\27\3\27\7\27\u00ff\n\27\f\27\16\27\u0102")
+ buf.write("\13\27\3\27\3\27\3\27\3\27\7\27\u0108\n\27\f\27\16\27")
+ buf.write("\u010b\13\27\3\27\3\27\5\27\u010f\n\27\3\30\5\30\u0112")
+ buf.write("\n\30\3\30\7\30\u0115\n\30\f\30\16\30\u0118\13\30\3\30")
+ buf.write("\3\30\3\30\3\30\5\30\u011e\n\30\3\30\5\30\u0121\n\30\3")
+ buf.write("\31\5\31\u0124\n\31\3\31\7\31\u0127\n\31\f\31\16\31\u012a")
+ buf.write("\13\31\3\31\3\31\3\31\3\31\7\31\u0130\n\31\f\31\16\31")
+ buf.write("\u0133\13\31\3\31\3\31\5\31\u0137\n\31\3\32\3\32\5\32")
+ buf.write("\u013b\n\32\3\33\5\33\u013e\n\33\3\33\7\33\u0141\n\33")
+ buf.write("\f\33\16\33\u0144\13\33\3\33\3\33\3\33\5\33\u0149\n\33")
+ buf.write("\3\33\5\33\u014c\n\33\3\34\3\34\5\34\u0150\n\34\3\34\2")
+ buf.write("\2\35\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*,.")
+ buf.write("\60\62\64\66\2\2\2\u0172\28\3\2\2\2\4?\3\2\2\2\6F\3\2")
+ buf.write("\2\2\bM\3\2\2\2\n^\3\2\2\2\fa\3\2\2\2\16}\3\2\2\2\20\u0080")
+ buf.write("\3\2\2\2\22\u009b\3\2\2\2\24\u009e\3\2\2\2\26\u00b4\3")
+ buf.write("\2\2\2\30\u00ca\3\2\2\2\32\u00cc\3\2\2\2\34\u00d1\3\2")
+ buf.write("\2\2\36\u00d3\3\2\2\2 \u00e0\3\2\2\2\"\u00e2\3\2\2\2$")
+ buf.write("\u00e9\3\2\2\2&\u00eb\3\2\2\2(\u00f0\3\2\2\2*\u00f5\3")
+ buf.write("\2\2\2,\u00fb\3\2\2\2.\u0111\3\2\2\2\60\u0123\3\2\2\2")
+ buf.write("\62\u013a\3\2\2\2\64\u013d\3\2\2\2\66\u014f\3\2\2\28<")
+ buf.write("\5\4\3\29;\5\n\6\2:9\3\2\2\2;>\3\2\2\2<:\3\2\2\2<=\3\2")
+ buf.write("\2\2=\3\3\2\2\2><\3\2\2\2?C\5\b\5\2@B\5\6\4\2A@\3\2\2")
+ buf.write("\2BE\3\2\2\2CA\3\2\2\2CD\3\2\2\2D\5\3\2\2\2EC\3\2\2\2")
+ buf.write("FG\7\3\2\2GH\7&\2\2HJ\7\'\2\2IK\7\4\2\2JI\3\2\2\2JK\3")
+ buf.write("\2\2\2K\7\3\2\2\2LN\7(\2\2ML\3\2\2\2MN\3\2\2\2NR\3\2\2")
buf.write("\2OQ\5\34\17\2PO\3\2\2\2QT\3\2\2\2RP\3\2\2\2RS\3\2\2\2")
- buf.write("SU\3\2\2\2TR\3\2\2\2UV\7\5\2\2VW\7#\2\2WY\7$\2\2XZ\7\4")
- buf.write("\2\2YX\3\2\2\2YZ\3\2\2\2Z\t\3\2\2\2[_\5\f\7\2\\_\5,\27")
- buf.write("\2]_\5\60\31\2^[\3\2\2\2^\\\3\2\2\2^]\3\2\2\2_\13\3\2")
- buf.write("\2\2`b\7%\2\2a`\3\2\2\2ab\3\2\2\2bf\3\2\2\2ce\5\34\17")
+ buf.write("SU\3\2\2\2TR\3\2\2\2UV\7\5\2\2VW\7&\2\2WY\7\'\2\2XZ\7")
+ buf.write("\4\2\2YX\3\2\2\2YZ\3\2\2\2Z\t\3\2\2\2[_\5\f\7\2\\_\5,")
+ buf.write("\27\2]_\5\60\31\2^[\3\2\2\2^\\\3\2\2\2^]\3\2\2\2_\13\3")
+ buf.write("\2\2\2`b\7(\2\2a`\3\2\2\2ab\3\2\2\2bf\3\2\2\2ce\5\34\17")
buf.write("\2dc\3\2\2\2eh\3\2\2\2fd\3\2\2\2fg\3\2\2\2gi\3\2\2\2h")
- buf.write("f\3\2\2\2ij\7\6\2\2jm\7#\2\2kl\7\7\2\2ln\7#\2\2mk\3\2")
+ buf.write("f\3\2\2\2ij\7\6\2\2jm\7&\2\2kl\7\7\2\2ln\7&\2\2mk\3\2")
buf.write("\2\2mn\3\2\2\2no\3\2\2\2os\7\b\2\2pr\5\16\b\2qp\3\2\2")
buf.write("\2ru\3\2\2\2sq\3\2\2\2st\3\2\2\2tv\3\2\2\2us\3\2\2\2v")
buf.write("x\7\t\2\2wy\7\4\2\2xw\3\2\2\2xy\3\2\2\2y\r\3\2\2\2z~\5")
buf.write("\20\t\2{~\5\26\f\2|~\5\24\13\2}z\3\2\2\2}{\3\2\2\2}|\3")
- buf.write("\2\2\2~\17\3\2\2\2\177\u0081\7%\2\2\u0080\177\3\2\2\2")
+ buf.write("\2\2\2~\17\3\2\2\2\177\u0081\7(\2\2\u0080\177\3\2\2\2")
buf.write("\u0080\u0081\3\2\2\2\u0081\u0085\3\2\2\2\u0082\u0084\5")
buf.write("\34\17\2\u0083\u0082\3\2\2\2\u0084\u0087\3\2\2\2\u0085")
buf.write("\u0083\3\2\2\2\u0085\u0086\3\2\2\2\u0086\u008a\3\2\2\2")
buf.write("\u0087\u0085\3\2\2\2\u0088\u008b\5 \21\2\u0089\u008b\7")
buf.write("\n\2\2\u008a\u0088\3\2\2\2\u008a\u0089\3\2\2\2\u008b\u008c")
- buf.write("\3\2\2\2\u008c\u008d\7#\2\2\u008d\u0091\7\13\2\2\u008e")
+ buf.write("\3\2\2\2\u008c\u008d\7&\2\2\u008d\u0091\7\13\2\2\u008e")
buf.write("\u0090\5\32\16\2\u008f\u008e\3\2\2\2\u0090\u0093\3\2\2")
buf.write("\2\u0091\u008f\3\2\2\2\u0091\u0092\3\2\2\2\u0092\u0094")
buf.write("\3\2\2\2\u0093\u0091\3\2\2\2\u0094\u0096\7\f\2\2\u0095")
buf.write("\u0097\5\22\n\2\u0096\u0095\3\2\2\2\u0096\u0097\3\2\2")
buf.write("\2\u0097\u0099\3\2\2\2\u0098\u009a\7\4\2\2\u0099\u0098")
buf.write("\3\2\2\2\u0099\u009a\3\2\2\2\u009a\21\3\2\2\2\u009b\u009c")
- buf.write("\7\r\2\2\u009c\23\3\2\2\2\u009d\u009f\7%\2\2\u009e\u009d")
+ buf.write("\7\r\2\2\u009c\23\3\2\2\2\u009d\u009f\7(\2\2\u009e\u009d")
buf.write("\3\2\2\2\u009e\u009f\3\2\2\2\u009f\u00a3\3\2\2\2\u00a0")
buf.write("\u00a2\5\34\17\2\u00a1\u00a0\3\2\2\2\u00a2\u00a5\3\2\2")
buf.write("\2\u00a3\u00a1\3\2\2\2\u00a3\u00a4\3\2\2\2\u00a4\u00a6")
buf.write("\3\2\2\2\u00a5\u00a3\3\2\2\2\u00a6\u00a7\7\16\2\2\u00a7")
- buf.write("\u00a8\7#\2\2\u00a8\u00ac\7\13\2\2\u00a9\u00ab\5\32\16")
+ buf.write("\u00a8\7&\2\2\u00a8\u00ac\7\13\2\2\u00a9\u00ab\5\32\16")
buf.write("\2\u00aa\u00a9\3\2\2\2\u00ab\u00ae\3\2\2\2\u00ac\u00aa")
buf.write("\3\2\2\2\u00ac\u00ad\3\2\2\2\u00ad\u00af\3\2\2\2\u00ae")
buf.write("\u00ac\3\2\2\2\u00af\u00b1\7\f\2\2\u00b0\u00b2\7\4\2\2")
buf.write("\u00b1\u00b0\3\2\2\2\u00b1\u00b2\3\2\2\2\u00b2\25\3\2")
- buf.write("\2\2\u00b3\u00b5\7%\2\2\u00b4\u00b3\3\2\2\2\u00b4\u00b5")
+ buf.write("\2\2\u00b3\u00b5\7(\2\2\u00b4\u00b3\3\2\2\2\u00b4\u00b5")
buf.write("\3\2\2\2\u00b5\u00b9\3\2\2\2\u00b6\u00b8\5\34\17\2\u00b7")
buf.write("\u00b6\3\2\2\2\u00b8\u00bb\3\2\2\2\u00b9\u00b7\3\2\2\2")
buf.write("\u00b9\u00ba\3\2\2\2\u00ba\u00bd\3\2\2\2\u00bb\u00b9\3")
buf.write("\2\2\2\u00bc\u00be\5\30\r\2\u00bd\u00bc\3\2\2\2\u00bd")
buf.write("\u00be\3\2\2\2\u00be\u00bf\3\2\2\2\u00bf\u00c0\5 \21\2")
- buf.write("\u00c0\u00c2\7#\2\2\u00c1\u00c3\7\4\2\2\u00c2\u00c1\3")
- buf.write("\2\2\2\u00c2\u00c3\3\2\2\2\u00c3\27\3\2\2\2\u00c4\u00c7")
- buf.write("\7\17\2\2\u00c5\u00c7\7\r\2\2\u00c6\u00c4\3\2\2\2\u00c6")
- buf.write("\u00c5\3\2\2\2\u00c7\31\3\2\2\2\u00c8\u00c9\5 \21\2\u00c9")
- buf.write("\u00cb\7#\2\2\u00ca\u00cc\7\20\2\2\u00cb\u00ca\3\2\2\2")
- buf.write("\u00cb\u00cc\3\2\2\2\u00cc\33\3\2\2\2\u00cd\u00ce\7\37")
- buf.write("\2\2\u00ce\35\3\2\2\2\u00cf\u00d2\7#\2\2\u00d0\u00d1\7")
- buf.write("\21\2\2\u00d1\u00d3\7#\2\2\u00d2\u00d0\3\2\2\2\u00d2\u00d3")
- buf.write("\3\2\2\2\u00d3\u00d5\3\2\2\2\u00d4\u00d6\7\20\2\2\u00d5")
- buf.write("\u00d4\3\2\2\2\u00d5\u00d6\3\2\2\2\u00d6\37\3\2\2\2\u00d7")
- buf.write("\u00dd\5$\23\2\u00d8\u00dd\5\"\22\2\u00d9\u00dd\5&\24")
- buf.write("\2\u00da\u00dd\5(\25\2\u00db\u00dd\5*\26\2\u00dc\u00d7")
- buf.write("\3\2\2\2\u00dc\u00d8\3\2\2\2\u00dc\u00d9\3\2\2\2\u00dc")
- buf.write("\u00da\3\2\2\2\u00dc\u00db\3\2\2\2\u00dd!\3\2\2\2\u00de")
- buf.write("\u00df\7#\2\2\u00df#\3\2\2\2\u00e0\u00e6\7\22\2\2\u00e1")
- buf.write("\u00e6\7\23\2\2\u00e2\u00e6\7\24\2\2\u00e3\u00e6\7\25")
- buf.write("\2\2\u00e4\u00e6\7\26\2\2\u00e5\u00e0\3\2\2\2\u00e5\u00e1")
- buf.write("\3\2\2\2\u00e5\u00e2\3\2\2\2\u00e5\u00e3\3\2\2\2\u00e5")
- buf.write("\u00e4\3\2\2\2\u00e6%\3\2\2\2\u00e7\u00e8\7\27\2\2\u00e8")
- buf.write("\u00e9\7\30\2\2\u00e9\u00ea\5 \21\2\u00ea\u00eb\7\31\2")
- buf.write("\2\u00eb\'\3\2\2\2\u00ec\u00ed\7\32\2\2\u00ed\u00ee\7")
- buf.write("\30\2\2\u00ee\u00ef\5 \21\2\u00ef\u00f0\7\31\2\2\u00f0")
- buf.write(")\3\2\2\2\u00f1\u00f2\7\33\2\2\u00f2\u00f3\7\30\2\2\u00f3")
- buf.write("\u00f4\5 \21\2\u00f4\u00f5\7\31\2\2\u00f5+\3\2\2\2\u00f6")
- buf.write("\u00f8\7%\2\2\u00f7\u00f6\3\2\2\2\u00f7\u00f8\3\2\2\2")
- buf.write("\u00f8\u00fc\3\2\2\2\u00f9\u00fb\5\34\17\2\u00fa\u00f9")
- buf.write("\3\2\2\2\u00fb\u00fe\3\2\2\2\u00fc\u00fa\3\2\2\2\u00fc")
- buf.write("\u00fd\3\2\2\2\u00fd\u00ff\3\2\2\2\u00fe\u00fc\3\2\2\2")
- buf.write("\u00ff\u0100\7\34\2\2\u0100\u0101\7#\2\2\u0101\u0105\7")
- buf.write("\b\2\2\u0102\u0104\5.\30\2\u0103\u0102\3\2\2\2\u0104\u0107")
- buf.write("\3\2\2\2\u0105\u0103\3\2\2\2\u0105\u0106\3\2\2\2\u0106")
- buf.write("\u0108\3\2\2\2\u0107\u0105\3\2\2\2\u0108\u010a\7\t\2\2")
- buf.write("\u0109\u010b\7\4\2\2\u010a\u0109\3\2\2\2\u010a\u010b\3")
- buf.write("\2\2\2\u010b-\3\2\2\2\u010c\u010e\7%\2\2\u010d\u010c\3")
- buf.write("\2\2\2\u010d\u010e\3\2\2\2\u010e\u0112\3\2\2\2\u010f\u0111")
- buf.write("\5\34\17\2\u0110\u010f\3\2\2\2\u0111\u0114\3\2\2\2\u0112")
- buf.write("\u0110\3\2\2\2\u0112\u0113\3\2\2\2\u0113\u0115\3\2\2\2")
- buf.write("\u0114\u0112\3\2\2\2\u0115\u0116\5 \21\2\u0116\u0118\7")
- buf.write("#\2\2\u0117\u0119\7\4\2\2\u0118\u0117\3\2\2\2\u0118\u0119")
- buf.write("\3\2\2\2\u0119/\3\2\2\2\u011a\u011c\7%\2\2\u011b\u011a")
- buf.write("\3\2\2\2\u011b\u011c\3\2\2\2\u011c\u0120\3\2\2\2\u011d")
- buf.write("\u011f\5\34\17\2\u011e\u011d\3\2\2\2\u011f\u0122\3\2\2")
- buf.write("\2\u0120\u011e\3\2\2\2\u0120\u0121\3\2\2\2\u0121\u0123")
- buf.write("\3\2\2\2\u0122\u0120\3\2\2\2\u0123\u0124\5\62\32\2\u0124")
- buf.write("\u0125\7#\2\2\u0125\u0129\7\b\2\2\u0126\u0128\5\64\33")
- buf.write("\2\u0127\u0126\3\2\2\2\u0128\u012b\3\2\2\2\u0129\u0127")
- buf.write("\3\2\2\2\u0129\u012a\3\2\2\2\u012a\u012c\3\2\2\2\u012b")
- buf.write("\u0129\3\2\2\2\u012c\u012e\7\t\2\2\u012d\u012f\7\4\2\2")
- buf.write("\u012e\u012d\3\2\2\2\u012e\u012f\3\2\2\2\u012f\61\3\2")
- buf.write("\2\2\u0130\u0133\7\35\2\2\u0131\u0133\7\36\2\2\u0132\u0130")
- buf.write("\3\2\2\2\u0132\u0131\3\2\2\2\u0133\63\3\2\2\2\u0134\u0136")
- buf.write("\7%\2\2\u0135\u0134\3\2\2\2\u0135\u0136\3\2\2\2\u0136")
- buf.write("\u013a\3\2\2\2\u0137\u0139\5\34\17\2\u0138\u0137\3\2\2")
- buf.write("\2\u0139\u013c\3\2\2\2\u013a\u0138\3\2\2\2\u013a\u013b")
- buf.write("\3\2\2\2\u013b\u013d\3\2\2\2\u013c\u013a\3\2\2\2\u013d")
- buf.write("\u0140\7#\2\2\u013e\u013f\7\21\2\2\u013f\u0141\5\66\34")
- buf.write("\2\u0140\u013e\3\2\2\2\u0140\u0141\3\2\2\2\u0141\u0143")
- buf.write("\3\2\2\2\u0142\u0144\7\20\2\2\u0143\u0142\3\2\2\2\u0143")
- buf.write("\u0144\3\2\2\2\u0144\65\3\2\2\2\u0145\u0148\7 \2\2\u0146")
- buf.write("\u0148\7!\2\2\u0147\u0145\3\2\2\2\u0147\u0146\3\2\2\2")
- buf.write("\u0148\67\3\2\2\2\64<CJMRY^afmsx}\u0080\u0085\u008a\u0091")
- buf.write("\u0096\u0099\u009e\u00a3\u00ac\u00b1\u00b4\u00b9\u00bd")
- buf.write("\u00c2\u00c6\u00cb\u00d2\u00d5\u00dc\u00e5\u00f7\u00fc")
- buf.write("\u0105\u010a\u010d\u0112\u0118\u011b\u0120\u0129\u012e")
- buf.write("\u0132\u0135\u013a\u0140\u0143\u0147")
+ buf.write("\u00c0\u00c3\7&\2\2\u00c1\u00c2\7\17\2\2\u00c2\u00c4\7")
+ buf.write("\37\2\2\u00c3\u00c1\3\2\2\2\u00c3\u00c4\3\2\2\2\u00c4")
+ buf.write("\u00c6\3\2\2\2\u00c5\u00c7\7\4\2\2\u00c6\u00c5\3\2\2\2")
+ buf.write("\u00c6\u00c7\3\2\2\2\u00c7\27\3\2\2\2\u00c8\u00cb\7\20")
+ buf.write("\2\2\u00c9\u00cb\7\r\2\2\u00ca\u00c8\3\2\2\2\u00ca\u00c9")
+ buf.write("\3\2\2\2\u00cb\31\3\2\2\2\u00cc\u00cd\5 \21\2\u00cd\u00cf")
+ buf.write("\7&\2\2\u00ce\u00d0\7\21\2\2\u00cf\u00ce\3\2\2\2\u00cf")
+ buf.write("\u00d0\3\2\2\2\u00d0\33\3\2\2\2\u00d1\u00d2\7\"\2\2\u00d2")
+ buf.write("\35\3\2\2\2\u00d3\u00d6\7&\2\2\u00d4\u00d5\7\17\2\2\u00d5")
+ buf.write("\u00d7\7&\2\2\u00d6\u00d4\3\2\2\2\u00d6\u00d7\3\2\2\2")
+ buf.write("\u00d7\u00d9\3\2\2\2\u00d8\u00da\7\21\2\2\u00d9\u00d8")
+ buf.write("\3\2\2\2\u00d9\u00da\3\2\2\2\u00da\37\3\2\2\2\u00db\u00e1")
+ buf.write("\5$\23\2\u00dc\u00e1\5\"\22\2\u00dd\u00e1\5&\24\2\u00de")
+ buf.write("\u00e1\5(\25\2\u00df\u00e1\5*\26\2\u00e0\u00db\3\2\2\2")
+ buf.write("\u00e0\u00dc\3\2\2\2\u00e0\u00dd\3\2\2\2\u00e0\u00de\3")
+ buf.write("\2\2\2\u00e0\u00df\3\2\2\2\u00e1!\3\2\2\2\u00e2\u00e3")
+ buf.write("\7&\2\2\u00e3#\3\2\2\2\u00e4\u00ea\7\22\2\2\u00e5\u00ea")
+ buf.write("\7\23\2\2\u00e6\u00ea\7\24\2\2\u00e7\u00ea\7\25\2\2\u00e8")
+ buf.write("\u00ea\7\26\2\2\u00e9\u00e4\3\2\2\2\u00e9\u00e5\3\2\2")
+ buf.write("\2\u00e9\u00e6\3\2\2\2\u00e9\u00e7\3\2\2\2\u00e9\u00e8")
+ buf.write("\3\2\2\2\u00ea%\3\2\2\2\u00eb\u00ec\7\27\2\2\u00ec\u00ed")
+ buf.write("\7\30\2\2\u00ed\u00ee\5 \21\2\u00ee\u00ef\7\31\2\2\u00ef")
+ buf.write("\'\3\2\2\2\u00f0\u00f1\7\32\2\2\u00f1\u00f2\7\30\2\2\u00f2")
+ buf.write("\u00f3\5 \21\2\u00f3\u00f4\7\31\2\2\u00f4)\3\2\2\2\u00f5")
+ buf.write("\u00f6\7\33\2\2\u00f6\u00f7\7\30\2\2\u00f7\u00f8\5 \21")
+ buf.write("\2\u00f8\u00f9\7\31\2\2\u00f9+\3\2\2\2\u00fa\u00fc\7(")
+ buf.write("\2\2\u00fb\u00fa\3\2\2\2\u00fb\u00fc\3\2\2\2\u00fc\u0100")
+ buf.write("\3\2\2\2\u00fd\u00ff\5\34\17\2\u00fe\u00fd\3\2\2\2\u00ff")
+ buf.write("\u0102\3\2\2\2\u0100\u00fe\3\2\2\2\u0100\u0101\3\2\2\2")
+ buf.write("\u0101\u0103\3\2\2\2\u0102\u0100\3\2\2\2\u0103\u0104\7")
+ buf.write("\34\2\2\u0104\u0105\7&\2\2\u0105\u0109\7\b\2\2\u0106\u0108")
+ buf.write("\5.\30\2\u0107\u0106\3\2\2\2\u0108\u010b\3\2\2\2\u0109")
+ buf.write("\u0107\3\2\2\2\u0109\u010a\3\2\2\2\u010a\u010c\3\2\2\2")
+ buf.write("\u010b\u0109\3\2\2\2\u010c\u010e\7\t\2\2\u010d\u010f\7")
+ buf.write("\4\2\2\u010e\u010d\3\2\2\2\u010e\u010f\3\2\2\2\u010f-")
+ buf.write("\3\2\2\2\u0110\u0112\7(\2\2\u0111\u0110\3\2\2\2\u0111")
+ buf.write("\u0112\3\2\2\2\u0112\u0116\3\2\2\2\u0113\u0115\5\34\17")
+ buf.write("\2\u0114\u0113\3\2\2\2\u0115\u0118\3\2\2\2\u0116\u0114")
+ buf.write("\3\2\2\2\u0116\u0117\3\2\2\2\u0117\u0119\3\2\2\2\u0118")
+ buf.write("\u0116\3\2\2\2\u0119\u011a\5 \21\2\u011a\u011d\7&\2\2")
+ buf.write("\u011b\u011c\7\17\2\2\u011c\u011e\7\37\2\2\u011d\u011b")
+ buf.write("\3\2\2\2\u011d\u011e\3\2\2\2\u011e\u0120\3\2\2\2\u011f")
+ buf.write("\u0121\7\4\2\2\u0120\u011f\3\2\2\2\u0120\u0121\3\2\2\2")
+ buf.write("\u0121/\3\2\2\2\u0122\u0124\7(\2\2\u0123\u0122\3\2\2\2")
+ buf.write("\u0123\u0124\3\2\2\2\u0124\u0128\3\2\2\2\u0125\u0127\5")
+ buf.write("\34\17\2\u0126\u0125\3\2\2\2\u0127\u012a\3\2\2\2\u0128")
+ buf.write("\u0126\3\2\2\2\u0128\u0129\3\2\2\2\u0129\u012b\3\2\2\2")
+ buf.write("\u012a\u0128\3\2\2\2\u012b\u012c\5\62\32\2\u012c\u012d")
+ buf.write("\7&\2\2\u012d\u0131\7\b\2\2\u012e\u0130\5\64\33\2\u012f")
+ buf.write("\u012e\3\2\2\2\u0130\u0133\3\2\2\2\u0131\u012f\3\2\2\2")
+ buf.write("\u0131\u0132\3\2\2\2\u0132\u0134\3\2\2\2\u0133\u0131\3")
+ buf.write("\2\2\2\u0134\u0136\7\t\2\2\u0135\u0137\7\4\2\2\u0136\u0135")
+ buf.write("\3\2\2\2\u0136\u0137\3\2\2\2\u0137\61\3\2\2\2\u0138\u013b")
+ buf.write("\7\35\2\2\u0139\u013b\7\36\2\2\u013a\u0138\3\2\2\2\u013a")
+ buf.write("\u0139\3\2\2\2\u013b\63\3\2\2\2\u013c\u013e\7(\2\2\u013d")
+ buf.write("\u013c\3\2\2\2\u013d\u013e\3\2\2\2\u013e\u0142\3\2\2\2")
+ buf.write("\u013f\u0141\5\34\17\2\u0140\u013f\3\2\2\2\u0141\u0144")
+ buf.write("\3\2\2\2\u0142\u0140\3\2\2\2\u0142\u0143\3\2\2\2\u0143")
+ buf.write("\u0145\3\2\2\2\u0144\u0142\3\2\2\2\u0145\u0148\7&\2\2")
+ buf.write("\u0146\u0147\7\17\2\2\u0147\u0149\5\66\34\2\u0148\u0146")
+ buf.write("\3\2\2\2\u0148\u0149\3\2\2\2\u0149\u014b\3\2\2\2\u014a")
+ buf.write("\u014c\7\21\2\2\u014b\u014a\3\2\2\2\u014b\u014c\3\2\2")
+ buf.write("\2\u014c\65\3\2\2\2\u014d\u0150\7#\2\2\u014e\u0150\7$")
+ buf.write("\2\2\u014f\u014d\3\2\2\2\u014f\u014e\3\2\2\2\u0150\67")
+ buf.write("\3\2\2\2\66<CJMRY^afmsx}\u0080\u0085\u008a\u0091\u0096")
+ buf.write("\u0099\u009e\u00a3\u00ac\u00b1\u00b4\u00b9\u00bd\u00c3")
+ buf.write("\u00c6\u00ca\u00cf\u00d6\u00d9\u00e0\u00e9\u00fb\u0100")
+ buf.write("\u0109\u010e\u0111\u0116\u011d\u0120\u0123\u0128\u0131")
+ buf.write("\u0136\u013a\u013d\u0142\u0148\u014b\u014f")
return buf.getvalue()
@@ -176,7 +181,7 @@ class TParser ( Parser ):
literalNames = [ "<INVALID>", "'import'", "';'", "'module'", "'interface'",
"'extends'", "'{'", "'}'", "'void'", "'('", "')'",
- "'const'", "'signal'", "'readonly'", "','", "'='",
+ "'const'", "'signal'", "'='", "'readonly'", "','",
"'bool'", "'int'", "'real'", "'string'", "'var'", "'list'",
"'<'", "'>'", "'map'", "'model'", "'struct'", "'enum'",
"'flag'" ]
@@ -188,9 +193,10 @@ class TParser ( Parser ):
"<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>",
"<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>",
"<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>",
- "<INVALID>", "TAGLINE", "INTCONSTANT", "HEXCONSTANT",
- "TAGIDENTIFIER", "IDENTIFIER", "VERSION", "DOCCOMMENT",
- "WHITESPACE", "COMMENT", "MULTICOMM" ]
+ "<INVALID>", "STRING", "DOUBLE_STRING", "SINGLE_STRING",
+ "TAGLINE", "INTCONSTANT", "HEXCONSTANT", "TAGIDENTIFIER",
+ "IDENTIFIER", "VERSION", "DOCCOMMENT", "WHITESPACE",
+ "COMMENT", "MULTICOMM" ]
RULE_documentSymbol = 0
RULE_headerSymbol = 1
@@ -258,16 +264,19 @@ class TParser ( Parser ):
T__25=26
T__26=27
T__27=28
- TAGLINE=29
- INTCONSTANT=30
- HEXCONSTANT=31
- TAGIDENTIFIER=32
- IDENTIFIER=33
- VERSION=34
- DOCCOMMENT=35
- WHITESPACE=36
- COMMENT=37
- MULTICOMM=38
+ STRING=29
+ DOUBLE_STRING=30
+ SINGLE_STRING=31
+ TAGLINE=32
+ INTCONSTANT=33
+ HEXCONSTANT=34
+ TAGIDENTIFIER=35
+ IDENTIFIER=36
+ VERSION=37
+ DOCCOMMENT=38
+ WHITESPACE=39
+ COMMENT=40
+ MULTICOMM=41
def __init__(self, input:TokenStream, output:TextIO = sys.stdout):
super().__init__(input, output)
@@ -729,7 +738,7 @@ class TParser ( Parser ):
self.state = 113
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.T__24) | (1 << TParser.TAGLINE) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0):
+ while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__7) | (1 << TParser.T__10) | (1 << TParser.T__11) | (1 << TParser.T__13) | (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.T__24) | (1 << TParser.TAGLINE) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0):
self.state = 110
self.interfaceMemberSymbol()
self.state = 115
@@ -1120,6 +1129,7 @@ class TParser ( Parser ):
self.parser = parser
self.comment = None # Token
self.name = None # Token
+ self.value = None # Token
def typeSymbol(self):
return self.getTypedRuleContext(TParser.TypeSymbolContext,0)
@@ -1142,6 +1152,9 @@ class TParser ( Parser ):
def DOCCOMMENT(self):
return self.getToken(TParser.DOCCOMMENT, 0)
+ def STRING(self):
+ return self.getToken(TParser.STRING, 0)
+
def getRuleIndex(self):
return TParser.RULE_propertySymbol
@@ -1190,7 +1203,7 @@ class TParser ( Parser ):
self.state = 187
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__10 or _la==TParser.T__12:
+ if _la==TParser.T__10 or _la==TParser.T__13:
self.state = 186
self.propertyModifierSymbol()
@@ -1199,11 +1212,21 @@ class TParser ( Parser ):
self.typeSymbol()
self.state = 190
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 192
+ self.state = 193
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__1:
+ if _la==TParser.T__12:
self.state = 191
+ self.match(TParser.T__12)
+ self.state = 192
+ localctx.value = self.match(TParser.STRING)
+
+
+ self.state = 196
+ self._errHandler.sync(self)
+ _la = self._input.LA(1)
+ if _la==TParser.T__1:
+ self.state = 195
self.match(TParser.T__1)
@@ -1249,17 +1272,17 @@ class TParser ( Parser ):
localctx = TParser.PropertyModifierSymbolContext(self, self._ctx, self.state)
self.enterRule(localctx, 22, self.RULE_propertyModifierSymbol)
try:
- self.state = 196
+ self.state = 200
self._errHandler.sync(self)
token = self._input.LA(1)
- if token in [TParser.T__12]:
+ if token in [TParser.T__13]:
self.enterOuterAlt(localctx, 1)
- self.state = 194
- localctx.is_readonly = self.match(TParser.T__12)
+ self.state = 198
+ localctx.is_readonly = self.match(TParser.T__13)
pass
elif token in [TParser.T__10]:
self.enterOuterAlt(localctx, 2)
- self.state = 195
+ self.state = 199
localctx.is_const = self.match(TParser.T__10)
pass
else:
@@ -1314,16 +1337,16 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 198
+ self.state = 202
self.typeSymbol()
- self.state = 199
+ self.state = 203
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 201
+ self.state = 205
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__13:
- self.state = 200
- self.match(TParser.T__13)
+ if _la==TParser.T__14:
+ self.state = 204
+ self.match(TParser.T__14)
except RecognitionException as re:
@@ -1370,7 +1393,7 @@ class TParser ( Parser ):
self.enterRule(localctx, 26, self.RULE_tagSymbol)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 203
+ self.state = 207
localctx.line = self.match(TParser.TAGLINE)
except RecognitionException as re:
localctx.exception = re
@@ -1421,24 +1444,24 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 205
+ self.state = 209
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 208
+ self.state = 212
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__14:
- self.state = 206
- self.match(TParser.T__14)
- self.state = 207
+ if _la==TParser.T__12:
+ self.state = 210
+ self.match(TParser.T__12)
+ self.state = 211
localctx.value = self.match(TParser.IDENTIFIER)
- self.state = 211
+ self.state = 215
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__13:
- self.state = 210
- self.match(TParser.T__13)
+ if _la==TParser.T__14:
+ self.state = 214
+ self.match(TParser.T__14)
except RecognitionException as re:
@@ -1500,32 +1523,32 @@ class TParser ( Parser ):
localctx = TParser.TypeSymbolContext(self, self._ctx, self.state)
self.enterRule(localctx, 30, self.RULE_typeSymbol)
try:
- self.state = 218
+ self.state = 222
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [TParser.T__15, TParser.T__16, TParser.T__17, TParser.T__18, TParser.T__19]:
self.enterOuterAlt(localctx, 1)
- self.state = 213
+ self.state = 217
self.primitiveTypeSymbol()
pass
elif token in [TParser.IDENTIFIER]:
self.enterOuterAlt(localctx, 2)
- self.state = 214
+ self.state = 218
self.complexTypeSymbol()
pass
elif token in [TParser.T__20]:
self.enterOuterAlt(localctx, 3)
- self.state = 215
+ self.state = 219
self.listTypeSymbol()
pass
elif token in [TParser.T__23]:
self.enterOuterAlt(localctx, 4)
- self.state = 216
+ self.state = 220
self.mapTypeSymbol()
pass
elif token in [TParser.T__24]:
self.enterOuterAlt(localctx, 5)
- self.state = 217
+ self.state = 221
self.modelTypeSymbol()
pass
else:
@@ -1575,7 +1598,7 @@ class TParser ( Parser ):
self.enterRule(localctx, 32, self.RULE_complexTypeSymbol)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 220
+ self.state = 224
localctx.name = self.match(TParser.IDENTIFIER)
except RecognitionException as re:
localctx.exception = re
@@ -1618,32 +1641,32 @@ class TParser ( Parser ):
localctx = TParser.PrimitiveTypeSymbolContext(self, self._ctx, self.state)
self.enterRule(localctx, 34, self.RULE_primitiveTypeSymbol)
try:
- self.state = 227
+ self.state = 231
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [TParser.T__15]:
self.enterOuterAlt(localctx, 1)
- self.state = 222
+ self.state = 226
localctx.name = self.match(TParser.T__15)
pass
elif token in [TParser.T__16]:
self.enterOuterAlt(localctx, 2)
- self.state = 223
+ self.state = 227
localctx.name = self.match(TParser.T__16)
pass
elif token in [TParser.T__17]:
self.enterOuterAlt(localctx, 3)
- self.state = 224
+ self.state = 228
localctx.name = self.match(TParser.T__17)
pass
elif token in [TParser.T__18]:
self.enterOuterAlt(localctx, 4)
- self.state = 225
+ self.state = 229
localctx.name = self.match(TParser.T__18)
pass
elif token in [TParser.T__19]:
self.enterOuterAlt(localctx, 5)
- self.state = 226
+ self.state = 230
localctx.name = self.match(TParser.T__19)
pass
else:
@@ -1694,13 +1717,13 @@ class TParser ( Parser ):
self.enterRule(localctx, 36, self.RULE_listTypeSymbol)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 229
+ self.state = 233
self.match(TParser.T__20)
- self.state = 230
+ self.state = 234
self.match(TParser.T__21)
- self.state = 231
+ self.state = 235
localctx.valueType = self.typeSymbol()
- self.state = 232
+ self.state = 236
self.match(TParser.T__22)
except RecognitionException as re:
localctx.exception = re
@@ -1747,13 +1770,13 @@ class TParser ( Parser ):
self.enterRule(localctx, 38, self.RULE_mapTypeSymbol)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 234
+ self.state = 238
self.match(TParser.T__23)
- self.state = 235
+ self.state = 239
self.match(TParser.T__21)
- self.state = 236
+ self.state = 240
localctx.valueType = self.typeSymbol()
- self.state = 237
+ self.state = 241
self.match(TParser.T__22)
except RecognitionException as re:
localctx.exception = re
@@ -1800,13 +1823,13 @@ class TParser ( Parser ):
self.enterRule(localctx, 40, self.RULE_modelTypeSymbol)
try:
self.enterOuterAlt(localctx, 1)
- self.state = 239
+ self.state = 243
self.match(TParser.T__24)
- self.state = 240
+ self.state = 244
self.match(TParser.T__21)
- self.state = 241
+ self.state = 245
localctx.valueType = self.typeSymbol()
- self.state = 242
+ self.state = 246
self.match(TParser.T__22)
except RecognitionException as re:
localctx.exception = re
@@ -1871,47 +1894,47 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 245
+ self.state = 249
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 244
+ self.state = 248
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 250
+ self.state = 254
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 247
+ self.state = 251
self.tagSymbol()
- self.state = 252
+ self.state = 256
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 253
+ self.state = 257
self.match(TParser.T__25)
- self.state = 254
+ self.state = 258
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 255
- self.match(TParser.T__5)
self.state = 259
+ self.match(TParser.T__5)
+ self.state = 263
self._errHandler.sync(self)
_la = self._input.LA(1)
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.T__24) | (1 << TParser.TAGLINE) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0):
- self.state = 256
+ self.state = 260
self.structFieldSymbol()
- self.state = 261
+ self.state = 265
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 262
+ self.state = 266
self.match(TParser.T__6)
- self.state = 264
+ self.state = 268
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 263
+ self.state = 267
self.match(TParser.T__1)
@@ -1930,6 +1953,7 @@ class TParser ( Parser ):
self.parser = parser
self.comment = None # Token
self.name = None # Token
+ self.value = None # Token
def typeSymbol(self):
return self.getTypedRuleContext(TParser.TypeSymbolContext,0)
@@ -1948,6 +1972,9 @@ class TParser ( Parser ):
def DOCCOMMENT(self):
return self.getToken(TParser.DOCCOMMENT, 0)
+ def STRING(self):
+ return self.getToken(TParser.STRING, 0)
+
def getRuleIndex(self):
return TParser.RULE_structFieldSymbol
@@ -1975,33 +2002,43 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 267
+ self.state = 271
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 266
+ self.state = 270
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 272
+ self.state = 276
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 269
+ self.state = 273
self.tagSymbol()
- self.state = 274
+ self.state = 278
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 275
+ self.state = 279
self.typeSymbol()
- self.state = 276
+ self.state = 280
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 278
+ self.state = 283
+ self._errHandler.sync(self)
+ _la = self._input.LA(1)
+ if _la==TParser.T__12:
+ self.state = 281
+ self.match(TParser.T__12)
+ self.state = 282
+ localctx.value = self.match(TParser.STRING)
+
+
+ self.state = 286
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 277
+ self.state = 285
self.match(TParser.T__1)
@@ -2072,47 +2109,47 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 281
+ self.state = 289
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 280
+ self.state = 288
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 286
+ self.state = 294
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 283
+ self.state = 291
self.tagSymbol()
- self.state = 288
+ self.state = 296
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 289
+ self.state = 297
self.enumTypeSymbol()
- self.state = 290
+ self.state = 298
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 291
+ self.state = 299
self.match(TParser.T__5)
- self.state = 295
+ self.state = 303
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 = 292
+ self.state = 300
self.enumMemberSymbol()
- self.state = 297
+ self.state = 305
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 298
+ self.state = 306
self.match(TParser.T__6)
- self.state = 300
+ self.state = 308
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.T__1:
- self.state = 299
+ self.state = 307
self.match(TParser.T__1)
@@ -2158,17 +2195,17 @@ class TParser ( Parser ):
localctx = TParser.EnumTypeSymbolContext(self, self._ctx, self.state)
self.enterRule(localctx, 48, self.RULE_enumTypeSymbol)
try:
- self.state = 304
+ self.state = 312
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [TParser.T__26]:
self.enterOuterAlt(localctx, 1)
- self.state = 302
+ self.state = 310
localctx.isEnum = self.match(TParser.T__26)
pass
elif token in [TParser.T__27]:
self.enterOuterAlt(localctx, 2)
- self.state = 303
+ self.state = 311
localctx.isFlag = self.match(TParser.T__27)
pass
else:
@@ -2234,42 +2271,42 @@ class TParser ( Parser ):
self._la = 0 # Token type
try:
self.enterOuterAlt(localctx, 1)
- self.state = 307
+ self.state = 315
self._errHandler.sync(self)
_la = self._input.LA(1)
if _la==TParser.DOCCOMMENT:
- self.state = 306
+ self.state = 314
localctx.comment = self.match(TParser.DOCCOMMENT)
- self.state = 312
+ self.state = 320
self._errHandler.sync(self)
_la = self._input.LA(1)
while _la==TParser.TAGLINE:
- self.state = 309
+ self.state = 317
self.tagSymbol()
- self.state = 314
+ self.state = 322
self._errHandler.sync(self)
_la = self._input.LA(1)
- self.state = 315
+ self.state = 323
localctx.name = self.match(TParser.IDENTIFIER)
- self.state = 318
+ self.state = 326
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__14:
- self.state = 316
- self.match(TParser.T__14)
- self.state = 317
+ if _la==TParser.T__12:
+ self.state = 324
+ self.match(TParser.T__12)
+ self.state = 325
self.intSymbol()
- self.state = 321
+ self.state = 329
self._errHandler.sync(self)
_la = self._input.LA(1)
- if _la==TParser.T__13:
- self.state = 320
- self.match(TParser.T__13)
+ if _la==TParser.T__14:
+ self.state = 328
+ self.match(TParser.T__14)
except RecognitionException as re:
@@ -2318,17 +2355,17 @@ class TParser ( Parser ):
localctx = TParser.IntSymbolContext(self, self._ctx, self.state)
self.enterRule(localctx, 52, self.RULE_intSymbol)
try:
- self.state = 325
+ self.state = 333
self._errHandler.sync(self)
token = self._input.LA(1)
if token in [TParser.INTCONSTANT]:
self.enterOuterAlt(localctx, 1)
- self.state = 323
+ self.state = 331
localctx.value = self.match(TParser.INTCONSTANT)
pass
elif token in [TParser.HEXCONSTANT]:
self.enterOuterAlt(localctx, 2)
- self.state = 324
+ self.state = 332
localctx.value = self.match(TParser.HEXCONSTANT)
pass
else:
diff --git a/qface/idl/profile.py b/qface/idl/profile.py
index b75aecc..2dd4b23 100644
--- a/qface/idl/profile.py
+++ b/qface/idl/profile.py
@@ -21,6 +21,7 @@ class EFeature(Enum):
EXTEND_INTERFACE = 'extend_interface'
IMPORT = 'import'
MAPS = 'maps'
+ DEFAULT_VALUES = 'default_values'
class EProfile(Enum):
@@ -34,7 +35,8 @@ _profiles = {
EProfile.ADVANCED: set([
EFeature.EXTEND_INTERFACE,
EFeature.IMPORT,
- EFeature.MAPS
+ EFeature.MAPS,
+ EFeature.DEFAULT_VALUES
]),
EProfile.FULL: set(EFeature)
}
diff --git a/qface/shell.py b/qface/shell.py
index 3d34d89..bf76f7c 100644
--- a/qface/shell.py
+++ b/qface/shell.py
@@ -6,11 +6,11 @@ API for interacting with the system shell
"""
-def sh(cmd, **kwargs):
+def sh(args, **kwargs):
"""
runs the given cmd as shell command
"""
- if not cmd:
+ if not args:
return
- click.echo('$ {0}'.format(cmd))
- return call(cmd, shell=True, **kwargs)
+ click.echo('$ {0}'.format(' '.join(args)))
+ return call(args, **kwargs)
diff --git a/qface/templates/qface/qtcpp.j2 b/qface/templates/qface/qtcpp.j2
index 97e1c8d..b2e3bff 100644
--- a/qface/templates/qface/qtcpp.j2
+++ b/qface/templates/qface/qtcpp.j2
@@ -13,53 +13,50 @@
{% 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 %})
+{% macro property_decl(property, notifiable=True) -%}
+Q_PROPERTY({{property|qt.returnType}} {{property}} READ {{property}} {% if not property.readonly %}WRITE push{{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}}
+{% macro property_setter_decl(property, ending=";", prefix='virtual') -%}
+{{prefix}} void push{{property|upperfirst}}({{ property|qt.parameterType }}){{ending}}
{%- endmacro %}
-{% macro property_getter_decl(property, ending=";") -%}
-{{property|returnType}} {{property}}() const{{ending}}
+{% macro property_getter_decl(property, ending=";", prefix='virtual') -%}
+{{prefix}} {{property|qt.returnType}} {{property}}() const{{ending}}
{%- endmacro %}
{% macro signal_decl(symbol, postfix="") -%}
-void {{symbol}}{{postfix}}({{symbol|parameters}});
+void {{symbol}}{{postfix}}();
{%- endmacro %}
{% macro property_member_decl(property) -%}
-{{property|returnType}} m_{{property}};
+{{property|qt.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}}
+ \brief {{doc.brief|join(" ")}}
+ {{doc.description|join("\n ")}}
{% endwith %}
*/
-
-void {{class}}::set{{property|upperfirst}}({{ property|parameterType }})
+void {{class}}::push{{property|upperfirst}}({{ property|qt.parameterType }})
{
{% if notifiable %}
if (m_{{property}} != {{property}}) {
m_{{property}} = {{property}};
- Q_EMIT {{property}}Changed({{property}});
+ Q_EMIT {{property}}Changed();
}
{% else %}
m_{{property}} = {{property}};
{% endif %}
-
}
{%- endmacro %}
{% macro property_getter_impl(class, property) -%}
-{{property|returnType}} {{class}}::{{property}}() const
+{{property|qt.returnType}} {{class}}::{{property}}() const
{
return m_{{property}};
}
@@ -68,24 +65,24 @@ void {{class}}::set{{property|upperfirst}}({{ property|parameterType }})
{% macro operation_impl(class, operation) -%}
/*!
- \qmlmethod {{operation.type}} {{class}}::{{operation}}({{operation|parameters}})
+ \qmlmethod {{operation.type}} {{class}}::{{operation}}({{operation|qt.parameters}})
{% with doc = operation.comment|parse_doc %}
\brief {{doc.brief}}
- {{doc.description}}
+ {{doc.description|join("\n ")}}
{% endwith %}
*/
-{{operation|returnType}} {{class}}::{{operation}}({{operation|parameters}})
+{{operation|qt.returnType}} {{class}}::{{operation}}({{operation|qt.parameters}})
{
{% for parameter in operation.parameters %}
Q_UNUSED({{parameter.name}});
{% endfor %}
qWarning() << "{{class}}::{{operation}}(...) not implemented";
- return {{operation|defaultValue}};
+ return {{operation|qt.defaultValue}};
}
{%- endmacro %}
{% macro operation_decl(operation, ending=";") -%}
- virtual {{operation|returnType}} {{operation}}({{operation|parameters}}){{ending}}
+ virtual {{operation|qt.returnType}} {{operation}}({{operation|qt.parameters}}){{ending}}
{%- endmacro %}
{% macro autogenerated(prefix="//") -%}
diff --git a/qface/utils.py b/qface/utils.py
index 3122d38..889d862 100644
--- a/qface/utils.py
+++ b/qface/utils.py
@@ -1,10 +1,24 @@
+from .generator import FileSystem
+from .helper import doc
-def merge(a, b):
- "merges b into a recursively if a and b are dicts"
- for key in b:
- if isinstance(a.get(key), dict) and isinstance(b.get(key), dict):
- merge(a[key], b[key])
- else:
- a[key] = b[key]
- return a
+def module_info(text):
+ system = FileSystem.parse_text(text)
+ module = list(system.modules)[0]
+ return {
+ 'title': module.name,
+ 'brief': " ".join(doc.parse_doc(module.comment).brief)
+ }
+
+
+def load_filters(path):
+ if not path.exists():
+ print('filter module does not exist')
+ return {}
+
+ ctx = {
+ 'filters': {}
+ }
+ exec(path.text(), ctx)
+ return ctx['filters']
+
diff --git a/qface/watch.py b/qface/watch.py
index 9501f25..29bc30f 100644
--- a/qface/watch.py
+++ b/qface/watch.py
@@ -3,16 +3,17 @@ from watchdog.observers import Observer
import click
from path import Path
import time
-from .shell import sh
+from subprocess import call
"""
Provides an API to monitor the file system
"""
+
class RunScriptChangeHandler(FileSystemEventHandler):
- def __init__(self, script):
+ def __init__(self, args):
super().__init__()
- self.script = script
+ self.args = args
self.is_running = False
def on_modified(self, event):
@@ -24,24 +25,21 @@ class RunScriptChangeHandler(FileSystemEventHandler):
if self.is_running:
return
self.is_running = True
- sh(str(self.script), cwd=Path.getcwd())
+ call(self.args, cwd=Path.getcwd())
self.is_running = False
-def monitor(script, src, dst, args):
+def monitor(args, watch):
"""
reloads the script given by argv when src files changes
"""
- src = src if isinstance(src, (list, tuple)) else [src]
- dst = Path(dst).expand().abspath()
- src = [Path(entry).expand().abspath() for entry in src]
- command = ' '.join(args)
- print('command: ', command)
- event_handler = RunScriptChangeHandler(command)
+ watch = watch if isinstance(watch, (list, tuple)) else [watch]
+ watch = [Path(entry).expand().abspath() for entry in watch]
+ event_handler = RunScriptChangeHandler(args)
observer = Observer()
- click.secho('watch recursive: {0}'.format(script.dirname()), fg='blue')
- observer.schedule(event_handler, script.dirname(), recursive=True)
- for entry in src:
+ for entry in watch:
+ if entry.isfile():
+ entry = entry.parent
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/setup.py b/setup.py
index 8792426..d7b65eb 100644
--- a/setup.py
+++ b/setup.py
@@ -64,5 +64,10 @@ setup(
'watchdog',
'ipdb',
],
- }
+ },
+ entry_points={
+ 'console_scripts': [
+ 'qface = qface.app:main'
+ ],
+ },
)
diff --git a/tests/in/com.pelagicore.test.qface b/tests/in/com.pelagicore.test.qface
index ae8a4f0..a5be518 100644
--- a/tests/in/com.pelagicore.test.qface
+++ b/tests/in/com.pelagicore.test.qface
@@ -2,13 +2,12 @@ module com.pelagicore.test 1.0;
import common 1.0;
-@service: { singleton: true}
interface ContactService {
State state;
- int intValue;
- readonly string stringValue;
- bool boolValue;
- real realValue;
+ int intValue = "2";
+ readonly string stringValue = "hello";
+ bool boolValue = "true";
+ real realValue = "0.1";
var varValue;
Contact currentContact;
common.Date today;
@@ -39,7 +38,7 @@ flag Phase {
* The contact information
*/
struct Contact {
- string name;
- int age;
- bool isMarried;
+ string name = "name";
+ int age = "99";
+ bool isMarried = "false";
}
diff --git a/tests/in/values.qface b/tests/in/values.qface
new file mode 100644
index 0000000..3b7035d
--- /dev/null
+++ b/tests/in/values.qface
@@ -0,0 +1,13 @@
+module values 1.0
+
+interface Namespace {
+ int intValue = "99"
+ real realValue = "0.99"
+ string message = "foo"
+ Person person = '{ name: "Hello", age: 101 }'
+}
+
+struct Person {
+ string name = "hello";
+ int age = "99";
+} \ No newline at end of file
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 61d680c..62b661c 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -261,3 +261,11 @@ def test_parser_exceptions():
system = FileSystem.parse_document('not-exists')
+def test_default_values():
+ system = load_test()
+ interface = system.lookup('com.pelagicore.test.ContactService')
+ symbol = system.lookup('com.pelagicore.test.ContactService#intValue')
+ assert symbol.value == "2"
+ symbol = system.lookup('com.pelagicore.test.ContactService#realValue')
+ assert symbol.value == "0.1"
+
diff --git a/tests/test_values.py b/tests/test_values.py
new file mode 100644
index 0000000..9ce93d1
--- /dev/null
+++ b/tests/test_values.py
@@ -0,0 +1,36 @@
+from qface.generator import FileSystem
+import logging
+import logging.config
+from path import Path
+
+
+# logging.config.fileConfig('logging.ini')
+logging.basicConfig()
+
+log = logging.getLogger(__name__)
+
+inputPath = Path('tests/in')
+
+
+def loadValues():
+ path = inputPath / 'values.qface'
+ return FileSystem.parse_document(path)
+
+
+def test_values():
+ system = loadValues()
+ assert system
+ # lookup module
+ interface = system.lookup('values.Namespace')
+ assert interface
+ properties = interface._propertyMap
+ assert properties['intValue'].value == "99"
+ assert properties['realValue'].value == "0.99"
+ assert properties['message'].value == "foo"
+ assert properties['person'].value == '{ name: "Hello", age: 101 }'
+ struct = system.lookup('values.Person')
+ assert struct
+ fields = struct._fieldMap
+ assert fields["name"].value == "hello"
+ assert fields["age"].value == "99"
+