diff options
author | Juergen Bocklage-Ryannel <juergen.bocklage-ryannel@pelagicore.com> | 2017-01-17 12:29:27 +0100 |
---|---|---|
committer | Juergen Bocklage-Ryannel <juergen.bocklage-ryannel@pelagicore.com> | 2017-01-17 12:29:27 +0100 |
commit | 92dc0631922f8b2faaf1c1772d0f8534b884f326 (patch) | |
tree | 29420e952530a825739a1f884e93e20836aee7cc | |
parent | 0d747ca6d9647f212a0d853987faed46e66408b7 (diff) | |
parent | 978c6058064f9f0384c913b94ed8266563e572a7 (diff) |
Merge branch 'release/1.0b1'1.0b1
-rw-r--r-- | README.md | 7 | ||||
-rw-r--r-- | builtin/qtcpp/log.yaml (renamed from examples/qtcpp/generator/log.yaml) | 2 | ||||
-rwxr-xr-x | builtin/qtcpp/qtcpp.py | 69 | ||||
-rw-r--r-- | builtin/qtcpp/templates/abstractinterface.cpp (renamed from examples/qtcpp/generator/templates/abstractinterface.cpp) | 25 | ||||
-rw-r--r-- | builtin/qtcpp/templates/abstractinterface.h (renamed from examples/qtcpp/generator/templates/abstractinterface.h) | 20 | ||||
-rw-r--r-- | builtin/qtcpp/templates/generated.pri (renamed from examples/qtcpp/generator/templates/generated.pri) | 4 | ||||
-rw-r--r-- | builtin/qtcpp/templates/interface.cpp (renamed from examples/qtcpp/generator/templates/interface.cpp) | 14 | ||||
-rw-r--r-- | builtin/qtcpp/templates/interface.h (renamed from examples/qtcpp/generator/templates/interface.h) | 1 | ||||
-rw-r--r-- | builtin/qtcpp/templates/module.cpp (renamed from examples/qtcpp/generator/templates/module.cpp) | 5 | ||||
-rw-r--r-- | builtin/qtcpp/templates/module.h (renamed from examples/qtcpp/generator/templates/module.h) | 4 | ||||
-rw-r--r-- | builtin/qtcpp/templates/plugin.cpp (renamed from examples/qtcpp/generator/templates/plugin.cpp) | 0 | ||||
-rw-r--r-- | builtin/qtcpp/templates/plugin.h (renamed from examples/qtcpp/generator/templates/plugin.h) | 0 | ||||
-rw-r--r-- | builtin/qtcpp/templates/plugin.pro (renamed from examples/qtcpp/generator/templates/plugin.pro) | 0 | ||||
-rw-r--r-- | builtin/qtcpp/templates/qmldir (renamed from examples/qtcpp/generator/templates/qmldir) | 0 | ||||
-rw-r--r-- | builtin/qtcpp/templates/struct.cpp (renamed from examples/qtcpp/generator/templates/struct.cpp) | 0 | ||||
-rw-r--r-- | builtin/qtcpp/templates/struct.h (renamed from examples/qtcpp/generator/templates/struct.h) | 0 | ||||
-rw-r--r-- | builtin/qtcpp/templates/structmodel.cpp (renamed from examples/qtcpp/generator/templates/structmodel.cpp) | 26 | ||||
-rw-r--r-- | builtin/qtcpp/templates/structmodel.h (renamed from examples/qtcpp/generator/templates/structmodel.h) | 9 | ||||
-rw-r--r-- | builtin/qtcpp/templates/variantmodel.cpp | 102 | ||||
-rw-r--r-- | builtin/qtcpp/templates/variantmodel.h | 38 | ||||
-rw-r--r-- | builtin/qtqml/log.yaml | 18 | ||||
-rw-r--r-- | builtin/qtqml/qtqml.py | 62 | ||||
-rw-r--r-- | builtin/qtqml/templates/AbstractInterface.qml | 20 | ||||
-rw-r--r-- | builtin/qtqml/templates/Interface.qml | 11 | ||||
-rw-r--r-- | builtin/qtqml/templates/InterfaceProvider.qml | 23 | ||||
-rw-r--r-- | builtin/qtqml/templates/Module.qml | 24 | ||||
-rw-r--r-- | builtin/qtqml/templates/module.js | 18 | ||||
-rw-r--r-- | builtin/qtqml/templates/private_qmldir | 5 | ||||
-rw-r--r-- | builtin/qtqml/templates/public_qmldir | 4 | ||||
-rwxr-xr-x | cli.py | 2 | ||||
-rw-r--r-- | docs/api.rst | 8 | ||||
-rw-r--r-- | docs/builtin.rst | 60 | ||||
-rw-r--r-- | docs/extending.rst | 2 | ||||
-rw-r--r-- | docs/index.rst | 9 | ||||
-rw-r--r-- | docs/qtcpp.rst | 125 | ||||
-rw-r--r-- | docs/qtqml.rst | 27 | ||||
-rw-r--r-- | examples/csv/README.md | 8 | ||||
-rwxr-xr-x | examples/csv/csv.py | 26 | ||||
-rw-r--r-- | examples/csv/templates/modules.csv (renamed from generator/csv/templates/modules.csv) | 0 | ||||
-rw-r--r-- | examples/echo/README.md | 30 | ||||
-rw-r--r-- | examples/echo/echo.pro (renamed from examples/qtcpp/src/echo/echo.pro) | 0 | ||||
-rw-r--r-- | examples/echo/main.cpp (renamed from examples/qtcpp/src/echo/main.cpp) | 0 | ||||
-rw-r--r-- | examples/examples.pro | 7 | ||||
-rw-r--r-- | examples/interfaces/echo.qface (renamed from examples/qtcpp/interface/echo.qdl) | 0 | ||||
-rw-r--r-- | examples/plugins/plugins.pro (renamed from examples/qtcpp/src/plugins/plugins.pro) | 2 | ||||
-rwxr-xr-x | examples/qtcpp/generator/qtcpp.py | 95 | ||||
-rw-r--r-- | examples/qtcpp/qtcpp.pro | 2 | ||||
-rw-r--r-- | examples/qtcpp/src/src.pro | 2 | ||||
-rwxr-xr-x | generator/csv/csv.py | 22 | ||||
-rw-r--r-- | qface/__about__.py | 13 | ||||
-rw-r--r-- | qface/generator.py | 41 | ||||
-rw-r--r-- | qface/helper/__init__.py (renamed from examples/qtcpp/src/plugins/.gitkeep) | 0 | ||||
-rw-r--r-- | qface/helper/qtcpp.py | 107 | ||||
-rw-r--r-- | qface/helper/qtqml.py | 52 | ||||
-rw-r--r-- | qface/idl/domain.py | 36 | ||||
-rw-r--r-- | qface/idl/listener.py | 24 | ||||
-rw-r--r-- | qface/idl/parser/T.g4 | 26 | ||||
-rw-r--r-- | qface/idl/parser/T.tokens | 39 | ||||
-rw-r--r-- | qface/idl/parser/TLexer.py | 233 | ||||
-rw-r--r-- | qface/idl/parser/TLexer.tokens | 39 | ||||
-rw-r--r-- | qface/idl/parser/TListener.py | 18 | ||||
-rw-r--r-- | qface/idl/parser/TParser.py | 875 | ||||
-rw-r--r-- | qface/idl/parser/TVisitor.py | 10 | ||||
-rw-r--r-- | setup.py | 17 | ||||
-rw-r--r-- | tests/in/com.pelagicore.ivi.climate.qface (renamed from tests/in/com.pelagicore.ivi.climate.qdl) | 0 | ||||
-rw-r--r-- | tests/in/com.pelagicore.ivi.tuner.qface (renamed from tests/in/com.pelagicore.ivi.tuner.qdl) | 3 | ||||
-rw-r--r-- | tests/in/com.pelagicore.one.qface (renamed from tests/in/com.pelagicore.one.qdl) | 0 | ||||
-rw-r--r-- | tests/in/com.pelagicore.test.qface (renamed from tests/in/com.pelagicore.test.qdl) | 1 | ||||
-rw-r--r-- | tests/templates/module.txt | 1 | ||||
-rw-r--r-- | tests/test_climate.py | 3 | ||||
-rw-r--r-- | tests/test_generator.py | 32 | ||||
-rw-r--r-- | tests/test_lookup.py | 11 | ||||
-rw-r--r-- | tests/test_parser.py | 39 | ||||
-rw-r--r-- | tests/test_qtcpp_helper.py | 202 | ||||
-rw-r--r-- | tests/test_tags.py | 39 | ||||
-rw-r--r-- | tests/test_validation.py | 26 |
76 files changed, 2084 insertions, 741 deletions
@@ -1,6 +1,7 @@ # Qt Interface Builder (QFace) -[![Build Status](https://travis-ci.org/travis-ci/travis-web.svg?branch=master)](https://travis-ci.org/travis-ci/travis-web) +[![Build Status](https://travis-ci.org/Pelagicore/qface.svg?branch=develop)](https://travis-ci.org/Pelagicore/qface) +[![Documentation Status](https://readthedocs.org/projects/qface/badge/?version=latest)](http://qface.readthedocs.io/en/latest/?badge=latest) QFace is an generator framework based on a common modern IDL. It is not a generator a such but enforces a common IDL format and provides a library to write your own generator. It is actually very easy to create your own generator and generate your custom solution based on your needs from the same IDL. @@ -23,7 +24,7 @@ The source code in this repository is subject to the terms of the GPLv3 licence, ```js -// echo.qdl +// echo.qface module org.example 1.0; /**! @@ -48,7 +49,7 @@ Now you write a small script using qface to generate your code from qface.generator import FileSystem, Generator # load the interface files -system = FileSystem.parse_document('echo.qdl') +system = FileSystem.parse('echo.qface') # prepare the generator generator = Generator(searchpath='.') diff --git a/examples/qtcpp/generator/log.yaml b/builtin/qtcpp/log.yaml index 61e7815..21b5bba 100644 --- a/examples/qtcpp/generator/log.yaml +++ b/builtin/qtcpp/log.yaml @@ -5,7 +5,7 @@ formatters: handlers: console: class: logging.StreamHandler - level: DEBUG + level: INFO formatter: simple stream: ext://sys.stdout loggers: diff --git a/builtin/qtcpp/qtcpp.py b/builtin/qtcpp/qtcpp.py new file mode 100755 index 0000000..56882a7 --- /dev/null +++ b/builtin/qtcpp/qtcpp.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# Copyright (c) Pelagicore AB 2016 + +import click +import logging +import logging.config +import yaml +from path import Path + +from qface.generator import FileSystem, Generator +from qface.helper.qtcpp import Filters + + +here = Path(__file__).dirname() + +logging.config.dictConfig(yaml.load(open(here / 'log.yaml'))) + +log = logging.getLogger(__file__) + + +def run(src, dst): + log.debug('run {0} {1}'.format(src, dst)) + system = FileSystem.parse(src) + generator = Generator(searchpath=here / 'templates') + generator.register_filter('returnType', Filters.returnType) + generator.register_filter('parameterType', Filters.parameterType) + generator.register_filter('defaultValue', Filters.defaultValue) + ctx = {'dst': dst} + for module in system.modules: + log.debug('generate code for module %s', module) + ctx.update({'module': module}) + dst = generator.apply('{{dst}}/{{module|lower|replace(".", "-")}}', ctx) + generator.destination = dst + generator.write('qmldir', 'qmldir', ctx, preserve=True) + generator.write('plugin.cpp', 'plugin.cpp', ctx, preserve=True) + generator.write('plugin.h', 'plugin.h', ctx, preserve=True) + generator.write('{{module|lower|replace(".", "-")}}.pro', 'plugin.pro', ctx, preserve=True) + generator.write('generated/generated.pri', 'generated.pri', ctx) + generator.write('generated/qml{{module.module_name|lower}}module.h', 'module.h', ctx) + generator.write('generated/qml{{module.module_name|lower}}module.cpp', 'module.cpp', ctx) + for interface in module.interfaces: + log.debug('generate code for interface %s', interface) + ctx.update({'interface': interface}) + generator.write('qml{{interface|lower}}.h', 'interface.h', ctx, preserve=True) + generator.write('qml{{interface|lower}}.cpp', 'interface.cpp', ctx, preserve=True) + generator.write('generated/qmlabstract{{interface|lower}}.h', 'abstractinterface.h', ctx) + generator.write('generated/qmlabstract{{interface|lower}}.cpp', 'abstractinterface.cpp', ctx) + for struct in module.structs: + log.debug('generate code for struct %s', struct) + ctx.update({'struct': struct}) + generator.write('generated/qml{{struct|lower}}.h', 'struct.h', ctx) + generator.write('generated/qml{{struct|lower}}.cpp', 'struct.cpp', ctx) + generator.write('generated/qml{{struct|lower}}model.h', 'structmodel.h', ctx) + generator.write('generated/qml{{struct|lower}}model.cpp', 'structmodel.cpp', ctx) + generator.write('generated/qmlvariantmodel.h', 'variantmodel.h', ctx) + generator.write('generated/qmlvariantmodel.cpp', 'variantmodel.cpp', ctx) + + +@click.command() +@click.argument('src', nargs=-1, type=click.Path(exists=True)) +@click.argument('dst', nargs=1, type=click.Path(exists=True)) +def app(src, dst): + """Takes several files or directories as src and generates the code + in the given dst directory.""" + run(src, dst) + + +if __name__ == '__main__': + app() diff --git a/examples/qtcpp/generator/templates/abstractinterface.cpp b/builtin/qtcpp/templates/abstractinterface.cpp index 9bf6ec7..e0ac7cc 100644 --- a/examples/qtcpp/generator/templates/abstractinterface.cpp +++ b/builtin/qtcpp/templates/abstractinterface.cpp @@ -12,27 +12,42 @@ {{interface.comment}} {{class}}::{{class}}(QObject *parent) : QObject(parent) -{ {% for property in interface.properties %} -{% if property.type.is_model %} - m_{{property}} = new {{property.type.nested}}Model(this); -{% endif %} + , m_{{property}}({{property|defaultValue}}) {% endfor %} +{ +} + +{{class}}::~{{class}}() +{ } {% for property in interface.properties %} +{% if not property.is_readonly %} void {{class}}::set{{property|upperfirst}}({{ property|parameterType }}) { if(m_{{property}} == {{property}}) { return; } m_{{property}} = {{property}}; - emit {{property}}Changed({{property}}); + emit {{property}}Changed(); } +{% endif %} {{property|returnType}} {{class}}::{{property}}() const { return m_{{property}}; } +{% endfor %} +{%- for operation in interface.operations %} +{{operation|returnType}} {{class}}::{{operation}}({{operation.parameters|map('parameterType')|join(', ')}}) +{ + {% for parameter in operation.parameters %} + Q_UNUSED({{parameter.name}}); + {% endfor %} + qWarning() << "{{class}}::{{operation}}(...) not implemented"; + return {{operation|defaultValue}}; +} {% endfor %} + diff --git a/examples/qtcpp/generator/templates/abstractinterface.h b/builtin/qtcpp/templates/abstractinterface.h index aac9ac8..d6921ca 100644 --- a/examples/qtcpp/generator/templates/abstractinterface.h +++ b/builtin/qtcpp/templates/abstractinterface.h @@ -15,32 +15,36 @@ class {{class}} : public QObject { Q_OBJECT {% for property in interface.properties %} - Q_PROPERTY({{property|returnType}} {{property}} READ {{property}} {%if not property.is_readonly%}WRITE set{{property|upperfirst}} {%endif%}NOTIFY {{property}}Changed) + Q_PROPERTY({{property|returnType}} {{property}} READ {{property}} NOTIFY {{property}}Changed) {% endfor %} public: {{class}}(QObject *parent=0); + ~{{class}}(); -{%- for operation in interface.operations %} - virtual {{operation|returnType}} {{operation}}({{operation.parameters|map('parameterType')|join(', ')}}) = 0; +public Q_SLOTS: +{% for operation in interface.operations %} + virtual {{operation|returnType}} {{operation}}({{operation.parameters|map('parameterType')|join(', ')}}); {% endfor %} -public Q_SLOTS: +public: {% for property in interface.properties %} - void set{{property|upperfirst}}({{ property|parameterType }}); +{% if not property.is_readonly %} + virtual void set{{property|upperfirst}}({{ property|parameterType }}); +{% endif %} {% endfor %} public: {% for property in interface.properties %} - {{property|returnType}} {{property}}() const; + virtual {{property|returnType}} {{property}}() const; {% endfor %} Q_SIGNALS: {% for property in interface.properties %} - void {{property}}Changed({{property|parameterType}}); + void {{property}}Changed(); {% endfor %} -private: +protected: {% for property in interface.properties %} {{property|returnType}} m_{{property}}; {% endfor %} diff --git a/examples/qtcpp/generator/templates/generated.pri b/builtin/qtcpp/templates/generated.pri index 31f9aac..4baac95 100644 --- a/examples/qtcpp/generator/templates/generated.pri +++ b/builtin/qtcpp/templates/generated.pri @@ -12,17 +12,19 @@ HEADERS += \ {% for interface in module.interfaces %} $$PWD/qmlabstract{{interface|lower}}.h \ {% endfor %} + $$PWD/qmlvariantmodel.h \ {% for struct in module.structs %} $$PWD/qml{{struct|lower}}.h \ $$PWD/qml{{struct|lower}}model.h {% if not loop.last %}\{% endif %} {% endfor %} - + SOURCES += \ $$PWD/qml{{module.module_name|lower}}module.cpp \ {% for interface in module.interfaces %} $$PWD/qmlabstract{{interface|lower}}.cpp \ {% endfor %} + $$PWD/qmlvariantmodel.cpp \ {% for struct in module.structs %} $$PWD/qml{{struct|lower}}.cpp \ $$PWD/qml{{struct|lower}}model.cpp {% if not loop.last %}\{% endif %} diff --git a/examples/qtcpp/generator/templates/interface.cpp b/builtin/qtcpp/templates/interface.cpp index 3e94c47..abde3d7 100644 --- a/examples/qtcpp/generator/templates/interface.cpp +++ b/builtin/qtcpp/templates/interface.cpp @@ -9,13 +9,27 @@ #include <QtQml> +QObject* {{class|lower}}_singletontype_provider(QQmlEngine*, QJSEngine*) +{ + return new {{class}}(); +} + + {{interface.comment}} {{class}}::{{class}}(QObject *parent) : QmlAbstract{{interface}}(parent) { } +{{class}}::~{{class}}() +{ +} + void {{class}}::registerQmlTypes(const QString& uri, int majorVersion, int minorVersion) { + {% if 'singleton' in interface.tags %} + qmlRegisterSingletonType<{{class}}>(uri.toLatin1(), majorVersion, minorVersion, "{{interface}}", {{class|lower}}_singletontype_provider); + {% else %} qmlRegisterType<{{class}}>(uri.toLatin1(), majorVersion, minorVersion, "{{interface}}"); + {% endif %} } diff --git a/examples/qtcpp/generator/templates/interface.h b/builtin/qtcpp/templates/interface.h index 0d957e8..8978be5 100644 --- a/examples/qtcpp/generator/templates/interface.h +++ b/builtin/qtcpp/templates/interface.h @@ -17,6 +17,7 @@ class {{class}} : public QmlAbstract{{interface}} Q_OBJECT public: {{class}}(QObject *parent=0); + virtual ~{{class}}(); static void registerQmlTypes(const QString& uri, int majorVersion=1, int minorVersion=0); }; diff --git a/examples/qtcpp/generator/templates/module.cpp b/builtin/qtcpp/templates/module.cpp index ca0f8c6..6579b2c 100644 --- a/examples/qtcpp/generator/templates/module.cpp +++ b/builtin/qtcpp/templates/module.cpp @@ -32,6 +32,9 @@ void {{class}}::registerTypes() {% for struct in module.structs %} qRegisterMetaType<Qml{{struct}}>(); {% endfor %} + {% for enum in module.enums %} + qRegisterMetaType<{{class}}::{{enum}}>(); + {% endfor %} } void {{class}}::registerQmlTypes(const QString& uri, int majorVersion, int minorVersion) @@ -39,5 +42,5 @@ void {{class}}::registerQmlTypes(const QString& uri, int majorVersion, int minor {% for struct in module.structs %} qmlRegisterUncreatableType<Qml{{struct}}Model>(uri.toLatin1(), majorVersion, minorVersion, "{{struct}}Model", "Model can not be instantiated from QML"); {% endfor %} - qmlRegisterSingletonType<{{class}}>(uri.toLatin1(), majorVersion, minorVersion, "{{module}}", {{class|lower}}_singletontype_provider); + qmlRegisterSingletonType<{{class}}>(uri.toLatin1(), majorVersion, minorVersion, "{{module.module_name}}Module", {{class|lower}}_singletontype_provider); } diff --git a/examples/qtcpp/generator/templates/module.h b/builtin/qtcpp/templates/module.h index f6bb772..39b5026 100644 --- a/examples/qtcpp/generator/templates/module.h +++ b/builtin/qtcpp/templates/module.h @@ -9,6 +9,7 @@ #include <QtCore> +#include "qmlvariantmodel.h" {% for struct in module.structs %} #include "qml{{struct|lower}}.h" #include "qml{{struct|lower}}model.h" @@ -21,11 +22,12 @@ public: {% for enum in module.enums %} {% set comma = joiner(",") %} - enum {{enum}} { + enum {{enum}} { {%- for member in enum.members -%} {{ comma() }} {{member.name}} = {{member.value}} {%- endfor %} + }; Q_ENUM({{enum}}) {% endfor %} diff --git a/examples/qtcpp/generator/templates/plugin.cpp b/builtin/qtcpp/templates/plugin.cpp index aa8fb9a..aa8fb9a 100644 --- a/examples/qtcpp/generator/templates/plugin.cpp +++ b/builtin/qtcpp/templates/plugin.cpp diff --git a/examples/qtcpp/generator/templates/plugin.h b/builtin/qtcpp/templates/plugin.h index 1952c35..1952c35 100644 --- a/examples/qtcpp/generator/templates/plugin.h +++ b/builtin/qtcpp/templates/plugin.h diff --git a/examples/qtcpp/generator/templates/plugin.pro b/builtin/qtcpp/templates/plugin.pro index 00c9d6e..00c9d6e 100644 --- a/examples/qtcpp/generator/templates/plugin.pro +++ b/builtin/qtcpp/templates/plugin.pro diff --git a/examples/qtcpp/generator/templates/qmldir b/builtin/qtcpp/templates/qmldir index 9fe5d2b..9fe5d2b 100644 --- a/examples/qtcpp/generator/templates/qmldir +++ b/builtin/qtcpp/templates/qmldir diff --git a/examples/qtcpp/generator/templates/struct.cpp b/builtin/qtcpp/templates/struct.cpp index 5b132ec..5b132ec 100644 --- a/examples/qtcpp/generator/templates/struct.cpp +++ b/builtin/qtcpp/templates/struct.cpp diff --git a/examples/qtcpp/generator/templates/struct.h b/builtin/qtcpp/templates/struct.h index 2e0d6d1..2e0d6d1 100644 --- a/examples/qtcpp/generator/templates/struct.h +++ b/builtin/qtcpp/templates/struct.h diff --git a/examples/qtcpp/generator/templates/structmodel.cpp b/builtin/qtcpp/templates/structmodel.cpp index 12104b9..3f13cb6 100644 --- a/examples/qtcpp/generator/templates/structmodel.cpp +++ b/builtin/qtcpp/templates/structmodel.cpp @@ -41,7 +41,6 @@ QVariant {{class}}::data(const QModelIndex &index, int role) const {% for field in struct.fields %} case Roles::{{field|upperfirst}}: return QVariant::fromValue({{struct|lower}}.m_{{field}}); - break; {% endfor %} } return QVariant(); @@ -53,7 +52,7 @@ QHash<int, QByteArray> {{class}}::roleNames() const } -void {{class}}::insert{{struct}}(int row, const Qml{{struct}} &{{struct|lower}}) +void {{class}}::insert(int row, const Qml{{struct}} &{{struct|lower}}) { if (row < 0) row = 0; @@ -66,7 +65,19 @@ void {{class}}::insert{{struct}}(int row, const Qml{{struct}} &{{struct|lower}}) emit countChanged(count()); } -void {{class}}::update{{struct}}(int row, const Qml{{struct}} &{{struct|lower}}) +void {{class}}::reset(const QList<Qml{{struct}}> data) +{ + beginResetModel(); + m_data = data; + endResetModel(); +} + +void {{class}}::append(const Qml{{struct}} &{{struct|lower}}) +{ + insert(m_data.count(), {{struct|lower}}); +} + +void {{class}}::update(int row, const Qml{{struct}} &{{struct|lower}}) { if(row < 0 || row >= m_data.count()) { return; @@ -76,7 +87,7 @@ void {{class}}::update{{struct}}(int row, const Qml{{struct}} &{{struct|lower}}) emit dataChanged(index, index); } -void {{class}}::remove{{struct}}(int row) +void {{class}}::remove(int row) { if(row < 0 || row >= m_data.count()) { return; @@ -86,3 +97,10 @@ void {{class}}::remove{{struct}}(int row) endRemoveRows(); } +void {{class}}::clear() +{ + beginResetModel(); + m_data.clear(); + endResetModel(); +} + diff --git a/examples/qtcpp/generator/templates/structmodel.h b/builtin/qtcpp/templates/structmodel.h index 85ed16b..96597be 100644 --- a/examples/qtcpp/generator/templates/structmodel.h +++ b/builtin/qtcpp/templates/structmodel.h @@ -20,9 +20,12 @@ public: {{class}}(QObject *parent=0); Q_INVOKABLE Qml{{struct}} get(int index); int count() const; - Q_INVOKABLE void insert{{struct}}(int row, const Qml{{struct}} &{{struct|lower}}); - Q_INVOKABLE void update{{struct}}(int row, const Qml{{struct}} &{{struct|lower}}); - Q_INVOKABLE void remove{{struct}}(int row); + void insert(int row, const Qml{{struct}} &{{struct|lower}}); + void append(const Qml{{struct}} &{{struct|lower}}); + void update(int row, const Qml{{struct}} &{{struct|lower}}); + void remove(int row); + void reset(const QList<Qml{{struct}}> data); + void clear(); public: // from QAbstractListModel virtual int rowCount(const QModelIndex &parent) const; virtual QVariant data(const QModelIndex &index, int role) const; diff --git a/builtin/qtcpp/templates/variantmodel.cpp b/builtin/qtcpp/templates/variantmodel.cpp new file mode 100644 index 0000000..6e197f4 --- /dev/null +++ b/builtin/qtcpp/templates/variantmodel.cpp @@ -0,0 +1,102 @@ +{# Copyright (c) Pelagicore AB 2016 #} +{% set class = 'QmlVariantModel' %} +/**************************************************************************** +** This is an auto-generated file. +** Do not edit! All changes made to it will be lost. +****************************************************************************/ + +#include "{{class|lower}}.h" + +{{class}}::{{class}}(QObject *parent) + : QAbstractListModel(parent) +{ + m_roleNames.insert(Roles::ModelData, QByteArray("modelData")); +} + +int {{class}}::count() const +{ + return m_data.count(); +} + +QVariant {{class}}::get(int index) +{ + return m_data.value(index); +} + +int {{class}}::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_data.count(); +} + +QVariant {{class}}::data(const QModelIndex &index, int role) const +{ + if(index.row() < 0 || index.row() >= count()) { + return QVariant(); + } + const QVariant &entry = m_data.at(index.row()); + switch(role) { + case Roles::ModelData: + return entry; + } + return QVariant(); +} + +QHash<int, QByteArray> {{class}}::roleNames() const +{ + return m_roleNames; +} + + +void {{class}}::insert(int row, const QVariant &entry) +{ + if (row < 0) + row = 0; + if (row >= m_data.count()) + row = m_data.count(); + + beginInsertRows(QModelIndex(), row, row); + m_data.insert(row, entry); + endInsertRows(); + emit countChanged(count()); +} + +void {{class}}::reset(const QVariantList entries) +{ + beginResetModel(); + m_data = entries; + endResetModel(); +} + +void {{class}}::append(const QVariant &entry) +{ + insert(m_data.count(), entry); +} + +void {{class}}::update(int row, const QVariant &entry) +{ + if(row < 0 || row >= m_data.count()) { + return; + } + m_data[row] = entry; + const QModelIndex &index = createIndex(row, 0); + emit dataChanged(index, index); +} + +void {{class}}::remove(int row) +{ + if(row < 0 || row >= m_data.count()) { + return; + } + beginRemoveRows(QModelIndex(), row, row); + m_data.removeAt(row); + endRemoveRows(); +} + +void {{class}}::clear() +{ + beginResetModel(); + m_data.clear(); + endResetModel(); +} + diff --git a/builtin/qtcpp/templates/variantmodel.h b/builtin/qtcpp/templates/variantmodel.h new file mode 100644 index 0000000..67be224 --- /dev/null +++ b/builtin/qtcpp/templates/variantmodel.h @@ -0,0 +1,38 @@ +{# Copyright (c) Pelagicore AB 2016 #} +{% set class = 'QmlVariantModel' %} +/**************************************************************************** +** This is an auto-generated file. +** Do not edit! All changes made to it will be lost. +****************************************************************************/ + +#pragma once + +#include <QtCore> + +class {{class}} : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(int count READ count NOTIFY countChanged) +public: + enum Roles { ModelData = Qt::UserRole }; + {{class}}(QObject *parent=0); + Q_INVOKABLE QVariant get(int index); + int count() const; + void insert(int row, const QVariant &entry); + void append(const QVariant &entry); + void update(int row, const QVariant &entry); + void remove(int row); + void reset(const QVariantList entries); + void clear(); +public: // from QAbstractListModel + virtual int rowCount(const QModelIndex &parent) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QHash<int, QByteArray> roleNames() const; +Q_SIGNALS: + void countChanged(int count); +private: + QVariantList m_data; + QHash<int, QByteArray> m_roleNames; +}; + + diff --git a/builtin/qtqml/log.yaml b/builtin/qtqml/log.yaml new file mode 100644 index 0000000..21b5bba --- /dev/null +++ b/builtin/qtqml/log.yaml @@ -0,0 +1,18 @@ +version: 1 +formatters: + simple: + format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s' +handlers: + console: + class: logging.StreamHandler + level: INFO + formatter: simple + stream: ext://sys.stdout +loggers: + qface.generator: + level: WARN + handlers: [console] + propagate: no +root: + level: DEBUG + handlers: [console] diff --git a/builtin/qtqml/qtqml.py b/builtin/qtqml/qtqml.py new file mode 100644 index 0000000..be714e0 --- /dev/null +++ b/builtin/qtqml/qtqml.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# Copyright (c) Pelagicore AB 2016 + +import click +import logging +import logging.config +import yaml +from path import Path + +from qface.generator import FileSystem, Generator +from qface.helper.qtqml import Filters + + +here = Path(__file__).dirname() + +logging.config.dictConfig(yaml.load(open(here / 'log.yaml'))) + +log = logging.getLogger(__file__) + + +def run(src, dst): + log.debug('run {0} {1}'.format(src, dst)) + system = FileSystem.parse(src) + generator = Generator(searchpath=here / 'templates') + generator.register_filter('defaultValue', Filters.defaultValue) + generator.register_filter('propertyType', Filters.propertyType) + ctx = {'dst': dst} + for module in system.modules: + module_name = module.module_name + module_path = '/'.join(module.name_parts) + plugin_name = "".join(module.name_parts[:2]) + ctx.update({ + 'module': module, + 'module_name': module_name, + 'module_path': module_path, + 'plugin_name': plugin_name, + }) + generator.destination = generator.apply("{{dst}}/{{module_path}}", ctx) + generator.write('private/{{module_name}}Module.js', 'module.js', ctx) + generator.write('qmldir', 'public_qmldir', ctx) + generator.write('private/qmldir', 'private_qmldir', ctx) + + for interface in module.interfaces: + ctx.update({ + 'interface': interface, + }) + generator.write('private/Abstract{{interface}}.qml', 'AbstractInterface.qml', ctx) + generator.write('{{interface}}.qml', 'Interface.qml', ctx, preserve=True) + generator.write('private/{{interface}}Provider.qml', 'InterfaceProvider.qml', ctx) + + +@click.command() +@click.argument('src', nargs=-1, type=click.Path(exists=True)) +@click.argument('dst', nargs=1, type=click.Path(exists=True)) +def app(src, dst): + """Takes several files or directories as src and generates the code + in the given dst directory.""" + run(src, dst) + + +if __name__ == '__main__': + app() diff --git a/builtin/qtqml/templates/AbstractInterface.qml b/builtin/qtqml/templates/AbstractInterface.qml new file mode 100644 index 0000000..d36aa5a --- /dev/null +++ b/builtin/qtqml/templates/AbstractInterface.qml @@ -0,0 +1,20 @@ +import QtQml 2.2 +import QtQml.Models 2.2 + +import "." + +{{interface.comment}} +QtObject { + id: root + {% for property in interface.properties %} + {{property.comment}} + readonly property {{property|propertyType}} {{property}} : _provider.{{property}} + {% endfor %} + + {% for operation in interface.operations %} + {{operation.comment}} + readonly property var {{operation}} : _provider.{{operation}} + {% endfor %} + + property {{interface}}Provider _provider: {{interface}}Provider {} +} diff --git a/builtin/qtqml/templates/Interface.qml b/builtin/qtqml/templates/Interface.qml new file mode 100644 index 0000000..dae8810 --- /dev/null +++ b/builtin/qtqml/templates/Interface.qml @@ -0,0 +1,11 @@ +import QtQml 2.2 + +import "private" + +Abstract{{interface}} { + id: root + + _provider : {{interface}}Provider { + // Add your code here + } +} diff --git a/builtin/qtqml/templates/InterfaceProvider.qml b/builtin/qtqml/templates/InterfaceProvider.qml new file mode 100644 index 0000000..bbcaaf5 --- /dev/null +++ b/builtin/qtqml/templates/InterfaceProvider.qml @@ -0,0 +1,23 @@ +import QtQml 2.2 +import QtQml.Models 2.2 + +import "." + +QtObject { + {% for property in interface.properties %} + property {{property|propertyType}} {{property}} : {{property|defaultValue}} + {% endfor %} + + {% for operation in interface.operations %} + property var {{operation}} : function({{operation.parameters|join(', ')}}) {} + {% endfor %} + + {% for event in interface.events %} + signal {{event}}( + {%- for parameter in event.parameters %} + {{- parameter.type|propertyType }} {{ parameter.name -}} + {% if not loop.last %}, {% endif %} + {% endfor -%} + ) + {% endfor %} +} diff --git a/builtin/qtqml/templates/Module.qml b/builtin/qtqml/templates/Module.qml new file mode 100644 index 0000000..7ededf2 --- /dev/null +++ b/builtin/qtqml/templates/Module.qml @@ -0,0 +1,24 @@ +pragma Singleton + +import QtQml 2.2 + +/** + * {{module.comment}} + */ +QtObject { + id: root + + {% for enum in module.enums %} + // Enum: {{enum}} + {% for member in enum.members %} + readonly property int {{member}}: {{member.value}} + {% endfor %} + + {% endfor %} + + {% for struct in module.structs %} + function create{{struct}}() { + return {}; + } + {% endfor %} +} diff --git a/builtin/qtqml/templates/module.js b/builtin/qtqml/templates/module.js new file mode 100644 index 0000000..551f5c3 --- /dev/null +++ b/builtin/qtqml/templates/module.js @@ -0,0 +1,18 @@ +.pragma library + +{% for enum in module.enums %} +// Enum: {{enum}} +{% for member in enum.members %} +var {{member}} = {{member.value}}; +{% endfor %} +{% endfor %} + +{% for struct in module.structs %} +function create{{struct}}() { + return { + {% for field in struct.fields %} + {{field}} : {{field | defaultValue}}, + {% endfor %} + }; +} +{% endfor %} diff --git a/builtin/qtqml/templates/private_qmldir b/builtin/qtqml/templates/private_qmldir new file mode 100644 index 0000000..5cd42a6 --- /dev/null +++ b/builtin/qtqml/templates/private_qmldir @@ -0,0 +1,5 @@ +{{module_name}}Module 1.0 {{module_name}}Module.js +{% for interface in module.interfaces %} +Abstract{{interface}} 1.0 Abstract{{interface}}.qml +{{interface}}Provider 1.0 {{interface}}Provider.qml +{% endfor %} diff --git a/builtin/qtqml/templates/public_qmldir b/builtin/qtqml/templates/public_qmldir new file mode 100644 index 0000000..fc465a7 --- /dev/null +++ b/builtin/qtqml/templates/public_qmldir @@ -0,0 +1,4 @@ +{{module_name}}Module 1.0 private/{{module_name}}Module.js +{% for interface in module.interfaces %} +{{interface}} 1.0 {{interface}}.qml +{% endfor %} @@ -92,8 +92,6 @@ class RunScriptChangeHandler(FileSystemEventHandler): def on_modified(self, event): if event.src_path.endswith('.cache'): return - if event.is_directory: - return self.run() def run(self): diff --git a/docs/api.rst b/docs/api.rst index 76a3970..e200730 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -22,10 +22,11 @@ FileSystem Class .. autoclass:: qface.generator.FileSystem :members: - + :show-inheritance: .. autoclass:: qface.generator.Generator :members: + :show-inheritance: Template Domain API @@ -42,6 +43,7 @@ High Level Classes .. autoclass:: qface.idl.domain.System :members: + :show-inheritance: .. autoclass:: qface.idl.domain.Module :members: @@ -53,16 +55,20 @@ Interface Related Classes .. autoclass:: qface.idl.domain.Interface :members: + :show-inheritance: .. autoclass:: qface.idl.domain.Operation :members: + :show-inheritance: .. autoclass:: qface.idl.domain.Parameter :members: + :show-inheritance: .. autoclass:: qface.idl.domain.Property :members: + :show-inheritance: Struct Related Classes diff --git a/docs/builtin.rst b/docs/builtin.rst index 7e7ec03..94bb0b6 100644 --- a/docs/builtin.rst +++ b/docs/builtin.rst @@ -1,61 +1,9 @@ Builtin Generators ================== -QtCPP Generator ---------------- -This is one of the buit-in generators to generate a QtCPP API to be exported into QML. -The structs/enums/flags are defined in an own Module Qbject which acts as a namespace and can not be instantiated. +.. toctree:: + :maxdepth: 1 -Each interface is generated into a QObject with proper properties, signals and invokables. - -For example an QDL like this: - -.. code-block:: js - - module sample 1.0 - - interface Heater { - real temperature; - Status status; - void increaseTemperature(qreal step); - void decreaseTemperature(qreal step); - event void error(string message); - } - - enum Status { - Null, - Ready, - Error - } - - -The QTCPP generator will generate all CPP code including the plugin code and project files. Additional it will generate an empy simulation stub. - -In QML you would now be able to write the following code. - -.. code-block:: qml - - import sample 1.0 - - Item { - Heater { - id: heater - onStatusChanged: { - if(status === SampleModule.Ready) { - console.log('ready ...') - } - } - onError: console.log(message) - } - Text { - anchors.centerIn: parent - text: heater.temperature - } - MouseArea { - anchors.fill: parent - onClicked: { - heater.increaseTemperature(0.5) - } - } - } + qtcpp + qtqml diff --git a/docs/extending.rst b/docs/extending.rst index c80bdd2..74aa761 100644 --- a/docs/extending.rst +++ b/docs/extending.rst @@ -18,7 +18,7 @@ See template engine documentation: def generate(input, output): # parse the interface files - system = FileSystem.parse_dir(input) + system = FileSystem.parse(input) # setup the generator generator = Generator(searchpath='templates') # create a context object diff --git a/docs/index.rst b/docs/index.rst index 562dbd8..fa2d5be 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,7 +1,7 @@ QFace ===== -QFace is a flexible Qt API generator. It uses a common IDL format (called qdl) to define an API. QFace comes with a set of predefined generators to generate QML Plugins. QFace can be easily extended with your own generator. +QFace is a flexible Qt API generator. It uses a common IDL format (called QDL) to define an API. QFace comes with a set of predefined generators to generate QML Plugins. QFace can be easily extended with your own generator. .. toctree:: :maxdepth: 1 @@ -14,10 +14,3 @@ QFace is a flexible Qt API generator. It uses a common IDL format (called qdl) t api -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/docs/qtcpp.rst b/docs/qtcpp.rst new file mode 100644 index 0000000..2eb3ede --- /dev/null +++ b/docs/qtcpp.rst @@ -0,0 +1,125 @@ +================ +Qt CPP Generator +================ + +QFace comes with a built in generator called `qtcpp`. It takes qface interface +files and generates Qt CPP as a QML plugin which can be directly used inside +your Qt5 project. + +The structs/enums/flags are defined in an own module singleton which acts as a namespace and factory methods. + +Each interface is generated into a QObject with the defined properties, signals and operations. + +For example an QFace document like this + +.. code-block:: js + + module sample 1.0 + + interface Heater { + real temperature; + Status status; + void increaseTemperature(real step); + void decreaseTemperature(real step); + event void error(string message); + } + + enum Status { + Null, + Ready, + Error + } + + +The QTCPP generator will generate all CPP code including the plugin code and project files. Additional it will generate an empty simulation stub. + +In QML you would now be able to write the following code. + +.. code-block:: qml + + import sample 1.0 + + Item { + Heater { + id: heater + onStatusChanged: { + if(status === SampleModule.Ready) { + console.log('ready ...') + } + } + onError: console.log(message) + } + Text { + anchors.centerIn: parent + text: heater.temperature + } + MouseArea { + anchors.fill: parent + onClicked: { + heater.increaseTemperature(0.5) + } + } + } + + +Code Generation +=============== + + +For each module the generator creates the qmake project files, the plugin code to register the types. A module singleton which contains the enums and factory functions for creating the structures. The structure has no signals and the values are copied over. + +.. code-block:: yml + + for each module: + - qmldir + - plugin.h - preserve + - plugin.cpp - preserve + - plugin.pro - preserve + - private/module.h + - private/module.cpp + - for each interface: + - private/abstractinterface.h + - private/abstractinterface.cpp + - interface.h - preserve + - interface.cpp - preserve + - for each struct: + - private/struct.h + - private/struct.cpp + +An base implementation of the interface is generated in the private folder. A stub implementation derived form the abstract interface is generated and registered with the plugin. + +Each structure is generates as a Q_GADGET which behaves similar as a JS object on the QML side. The interface is by default registered as a normal QML type and contains the properties and methods as also signals as defined in the interface files. + +Design Decisions +================ + +* All properties generated are read only from QML + + Writable properties on service objects are a cause of errors and confusion. It is very easy in the HMI stack to overwrite a binding property which writes to a service. It is better to offer a dedicated operation which does some work and triggers an operation update. + +* All models generated are read only from QML + + The data for a model is often stored inside another system (SQL DB, Remote, File System) and only a small subset of the data is actually in memory. Filtering, sorting or modifying the model data should be explicitly done using operations if supported by the user interface. + +* Data structures are exported as gadgets + + A Q_GADGET allows us to define a data structure and modify its contents. A gadget does not support signals, which means others are not notified about changes. This is the same behavior as for JS objects. Gadgets are copied from C++ to QML so there is no issue with memory management. QML has no means to create a gadget class, for this the module object contains a factory method for each structure. + +* Enums are collected into one module object + + All enumerations are defined inside the module object. This allows us to remove the need to additional QObjects per enum. It has the drawback that each enum value should be unique in the module. The generator currently does not enforces this. + + +Extending the Implementation +============================ + +To extend the implementation the user needs to modify the interface implementation. The document is marked as preserved, which means it will not re-generated when it exists. To trigger a regeneration the target document needs to be removed. + +In the interface document you are able to overwrite all setters and getters as also the operation methods. This is normally the only file you want to modify. + +Besides the interface files also the plugin and project files are preserved, as it is expected that these files might be required to change. This may change in the future. + + + + + diff --git a/docs/qtqml.rst b/docs/qtqml.rst new file mode 100644 index 0000000..b5795b4 --- /dev/null +++ b/docs/qtqml.rst @@ -0,0 +1,27 @@ +===================== +Qt QML Code Generator +===================== + +The Qt QML Code generator creates a pure QML implementation of the provided QFace interface files. From the QML perspective it is API compatible. This means an HMI written in QML can be run against plugins generated from the QtCPP code genrator and QtQML code generator. + +This allows developers to start early with an QML only implementation and later switch to an QtCPP based implementation, without changing the HMI code. + +.. note:: + + As the HMI is limited to the API there might still be differences in behavior of the two implementations. This is in the nature of APIs and might lead to different result. + +For each module the genrator creates a module JS file, which contains the enums and factory methods for the structure. A structure is in the pure QML implementation just a JS object with correct attributes set. + +The interfaces are generates as QtObject types and contain the typical properties, operations and signals. + +.. ruby:: Code Generation + +.. code-block:: yml + + for each module: + - qmldir + - {{module}}Module.js + - for each interface: + - interface.qml + + diff --git a/examples/csv/README.md b/examples/csv/README.md new file mode 100644 index 0000000..d42915d --- /dev/null +++ b/examples/csv/README.md @@ -0,0 +1,8 @@ +# CSV Generator + +This example provides a generator which reads in a set of interface files and generates a CSV file with an overview of the interfaces, structs and enums from the interface files. + +```sh +./csv.py ../interfaces . +``` + diff --git a/examples/csv/csv.py b/examples/csv/csv.py new file mode 100755 index 0000000..d885f91 --- /dev/null +++ b/examples/csv/csv.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# Copyright (c) Pelagicore AB 2016 + +import click +from qface.generator import FileSystem, Generator + + +def run(src, dst): + system = FileSystem.parse(src) + generator = Generator(searchpath='templates') + ctx = {'dst': dst, 'system': system} + generator.write('{{dst}}/modules.csv', 'modules.csv', ctx) + + +@click.command() +@click.argument('src', nargs=-1, type=click.Path(exists=True)) +@click.argument('dst', nargs=1, type=click.Path(exists=True)) +def app(src, dst): + """Generates a modules,csv file with statistics about all + interfaces, structs and enums from the given interface + sources""" + run(src, dst) + + +if __name__ == '__main__': + app() diff --git a/generator/csv/templates/modules.csv b/examples/csv/templates/modules.csv index 567dc43..567dc43 100644 --- a/generator/csv/templates/modules.csv +++ b/examples/csv/templates/modules.csv diff --git a/examples/echo/README.md b/examples/echo/README.md new file mode 100644 index 0000000..1975c70 --- /dev/null +++ b/examples/echo/README.md @@ -0,0 +1,30 @@ +# Echo Example + +Allow you to generate the echo QML plugins from the echo interfaces and show how to use them. + +## Running the Generator +```sh +../../builtin/qtcpp/qtcpp.py ../interfaces/echo.qface ../plugins +``` + +## Building the Plugins +Now you can open the plugins.pro file and build the plugins + +```sh +qmake +make +make install +``` + +## Running the Echo App + +Now you can build the echo app and use the generated plugins + +```sh +cd echo +qmake +make +./echo +``` + + diff --git a/examples/qtcpp/src/echo/echo.pro b/examples/echo/echo.pro index cfc7aef..cfc7aef 100644 --- a/examples/qtcpp/src/echo/echo.pro +++ b/examples/echo/echo.pro diff --git a/examples/qtcpp/src/echo/main.cpp b/examples/echo/main.cpp index 2e15127..2e15127 100644 --- a/examples/qtcpp/src/echo/main.cpp +++ b/examples/echo/main.cpp diff --git a/examples/examples.pro b/examples/examples.pro new file mode 100644 index 0000000..e2ec514 --- /dev/null +++ b/examples/examples.pro @@ -0,0 +1,7 @@ +TEMPLATE = subdirs + +SUBDIRS = \ + echo \ + plugins + +echo.depends = plugins diff --git a/examples/qtcpp/interface/echo.qdl b/examples/interfaces/echo.qface index bbde9d6..bbde9d6 100644 --- a/examples/qtcpp/interface/echo.qdl +++ b/examples/interfaces/echo.qface diff --git a/examples/qtcpp/src/plugins/plugins.pro b/examples/plugins/plugins.pro index c945fe3..6e1fdfd 100644 --- a/examples/qtcpp/src/plugins/plugins.pro +++ b/examples/plugins/plugins.pro @@ -1,3 +1,3 @@ TEMPLATE = subdirs SUBDIRS += \ - org.example + org-example diff --git a/examples/qtcpp/generator/qtcpp.py b/examples/qtcpp/generator/qtcpp.py deleted file mode 100755 index e5c1c3b..0000000 --- a/examples/qtcpp/generator/qtcpp.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) Pelagicore AB 2016 - -import click -import logging -import logging.config -import yaml -from qface.generator import FileSystem, Generator -import os -from path import Path - -here = os.path.dirname(__file__) - -def paramterType(symbol): - module_name = symbol.module.module_name - if symbol.type.is_enum: - return 'Qml{0}Module::{1} {2}'.format(module_name, symbol.type, symbol) - if symbol.type.is_void or symbol.type.is_primitive: - if symbol.type.name == 'string': - return 'const QString &{0}'.format(symbol) - if symbol.type.name == 'var': - return 'const QVariant &{0}'.format(symbol) - if symbol.type.name == 'real': - return 'float {0}'.format(symbol) - return '{0} {1}'.format(symbol.type, symbol) - elif symbol.type.is_list: - return 'const QList<{0}> &{1}'.format(symbol.type.nested, symbol) - elif symbol.type.is_model: - return '{0}Model *{1}'.format(symbol.type.nested, symbol) - else: - return 'const Qml{0} &{1}'.format(symbol.type, symbol) - - -def returnType(symbol): - module_name = symbol.module.module_name - if symbol.type.is_enum: - return 'Qml{0}Module::{1}'.format(module_name, symbol.type) - if symbol.type.is_void or symbol.type.is_primitive: - if symbol.type.name == 'string': - return 'QString' - if symbol.type.name == 'var': - return 'QVariant' - if symbol.type.name == 'real': - return 'float' - return symbol.type - elif symbol.type.is_list: - return 'QList<{0}>'.format(symbol.type.nested) - elif symbol.type.is_model: - return '{0}Model*'.format(symbol.type.nested) - else: - return 'Qml{0}'.format(symbol.type) - - -def run_generation(input, output): - system = FileSystem.parse(input) - generator = Generator(searchpath=os.path.join(here, 'templates')) - generator.register_filter('returnType', returnType) - generator.register_filter('parameterType', paramterType) - ctx = {'output': output} - for module in system.modules: - ctx.update({'module': module}) - dst = generator.apply('{{output}}/{{module|lower}}', ctx) - ctx.update({'dst': dst}) - generator.write('{{dst}}/qmldir', 'qmldir', ctx, preserve=True) - generator.write('{{dst}}/plugin.cpp', 'plugin.cpp', ctx, preserve=True) - generator.write('{{dst}}/plugin.h', 'plugin.h', ctx, preserve=True) - generator.write('{{dst}}/{{module|lower}}.pro', 'plugin.pro', ctx, preserve=True) - generator.write('{{dst}}/generated/generated.pri', 'generated.pri', ctx) - generator.write('{{dst}}/generated/qml{{module.module_name|lower}}module.h', 'module.h', ctx) - generator.write('{{dst}}/generated/qml{{module.module_name|lower}}module.cpp', 'module.cpp', ctx) - for interface in module.interfaces: - ctx.update({'interface': interface}) - generator.write('{{dst}}/qml{{interface|lower}}.h', 'interface.h', ctx, preserve=True) - generator.write('{{dst}}/qml{{interface|lower}}.cpp', 'interface.cpp', ctx, preserve=True) - generator.write('{{dst}}/generated/qmlabstract{{interface|lower}}.h', 'abstractinterface.h', ctx) - generator.write('{{dst}}/generated/qmlabstract{{interface|lower}}.cpp', 'abstractinterface.cpp', ctx) - for struct in module.structs: - ctx.update({'struct': struct}) - generator.write('{{dst}}/generated/qml{{struct|lower}}.h', 'struct.h', ctx) - generator.write('{{dst}}/generated/qml{{struct|lower}}.cpp', 'struct.cpp', ctx) - generator.write('{{dst}}/generated/qml{{struct|lower}}model.h', 'structmodel.h', ctx) - generator.write('{{dst}}/generated/qml{{struct|lower}}model.cpp', 'structmodel.cpp', ctx) - - -@click.command() -@click.argument('input', nargs=-1, type=click.Path(exists=True)) -@click.argument('output', nargs=1, type=click.Path(exists=True)) -def generate(input, output): - """Takes several files or directories as input and generates the code - in the given output directory.""" - run_generation(input, output) - - -if __name__ == '__main__': - generate() diff --git a/examples/qtcpp/qtcpp.pro b/examples/qtcpp/qtcpp.pro deleted file mode 100644 index 65d9262..0000000 --- a/examples/qtcpp/qtcpp.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = src diff --git a/examples/qtcpp/src/src.pro b/examples/qtcpp/src/src.pro deleted file mode 100644 index 64db4ad..0000000 --- a/examples/qtcpp/src/src.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = plugins diff --git a/generator/csv/csv.py b/generator/csv/csv.py deleted file mode 100755 index 3636997..0000000 --- a/generator/csv/csv.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) Pelagicore AB 2016 - -import click -from qface.generator import FileSystem, Generator - - -def generate(input, output): - system = FileSystem.parse_dir(input) - generator = Generator(searchpath='templates') - ctx = {'output': output, 'system': system} - generator.write('{{output}}/modules.csv', 'modules.csv', ctx) - - -@click.command() -@click.option('--input', type=click.Path(exists=True)) -@click.option('--output', type=click.Path(exists=True)) -def runner(input, output): - generate(input, output) - -if __name__ == '__main__': - runner() diff --git a/qface/__about__.py b/qface/__about__.py new file mode 100644 index 0000000..e4da80f --- /dev/null +++ b/qface/__about__.py @@ -0,0 +1,13 @@ +import os.path + +try: + base_dir = os.path.dirname(os.path.abspath(__file__)) +except NameError: + base_dir = None + + +__title__ = "qface" +__summary__ = "A generator framework based on a common modern IDL" +__uri__ = "https://pelagicore.github.io/qface/" +__version__ = "1.0b1" +__author__ = "JRyannel" diff --git a/qface/generator.py b/qface/generator.py index 3b27a19..6ef2aa4 100644 --- a/qface/generator.py +++ b/qface/generator.py @@ -21,6 +21,7 @@ logger = logging.getLogger(__name__) Provides an API for accessing the file system and controlling the generator """ + def upper_first_filter(s): s = str(s) return s[0].upper() + s[1:] @@ -31,8 +32,23 @@ class Generator(object): def __init__(self, searchpath: str): if searchpath: searchpath = Path(searchpath).expand() - self.env = Environment(loader=FileSystemLoader(searchpath), trim_blocks=True, lstrip_blocks=True) + self.env = Environment( + loader=FileSystemLoader(searchpath), + trim_blocks=True, + lstrip_blocks=True + ) self.env.filters['upperfirst'] = upper_first_filter + self._destination = Path() + self.prefix = '' + + @property + def destination(self): + """destination prefix for generator write""" + return self._destination + + @destination.setter + def destination(self, dst: str): + self._destination = Path(dst) def get_template(self, name: str): """Retrievs a single template file from the template loader""" @@ -51,18 +67,18 @@ class Generator(object): def write(self, fileTemplate: str, template: str, context: dict, preserve=False): """Using a templated file name it renders a template into a file given a context""" - path = Path(self.apply(fileTemplate, context)) + path = self.destination / Path(self.apply(fileTemplate, context)) path.parent.makedirs_p() logger.info('write {0}'.format(path)) data = self.render(template, context) - if self.hasDifferentContent(data, path): - if not preserve and path.exists(): - print('skip changed file: {0}'.format(path)) + if self._hasDifferentContent(data, path): + if path.exists() and preserve: + print('preserve changed file: {0}'.format(path)) else: print('write changed file: {0}'.format(path)) path.open('w').write(data) - def hasDifferentContent(self, data, path): + def _hasDifferentContent(self, data, path): if not path.exists(): return True dataHash = hashlib.new('md5', data.encode('utf-8')).digest() @@ -85,22 +101,25 @@ class FileSystem(object): :param system: system to be used (optional) """ logger.debug('parse document: {0}'.format(path)) + stream = FileStream(str(path), encoding='utf-8') + return FileSystem._parse_stream(stream, system) + @staticmethod + def _parse_stream(stream, system: System = None): + logger.debug('parse stream') system = system or System() - data = FileStream(str(path), encoding='utf-8') - lexer = TLexer(data) + lexer = TLexer(stream) stream = CommonTokenStream(lexer) parser = TParser(stream) parser.addErrorListener(DiagnosticErrorListener.DiagnosticErrorListener()) tree = parser.documentSymbol() walker = ParseTreeWalker() walker.walk(DomainListener(system), tree) - return system @staticmethod - def parse(input, identifier: str = None, use_cache=False, clear_cache=True): + def parse(input, identifier: str = None, use_cache=False, clear_cache=True, pattern="*.qface"): """Input can be either a file or directory or a list of files or directory. A directory will be parsed recursively. The function returns the resulting system. Stores the result of the run in the domain cache named after the identifier. @@ -127,7 +146,7 @@ class FileSystem(object): if path.isfile(): FileSystem.parse_document(path, system) else: - for document in path.walkfiles('*.qdl'): + for document in path.walkfiles(pattern): FileSystem.parse_document(document, system) if use_cache: cache[identifier] = system diff --git a/examples/qtcpp/src/plugins/.gitkeep b/qface/helper/__init__.py index e69de29..e69de29 100644 --- a/examples/qtcpp/src/plugins/.gitkeep +++ b/qface/helper/__init__.py diff --git a/qface/helper/qtcpp.py b/qface/helper/qtcpp.py new file mode 100644 index 0000000..aa7235a --- /dev/null +++ b/qface/helper/qtcpp.py @@ -0,0 +1,107 @@ +""" +Provides helper functionality specificially for Qt C++/QML code generators +""" + + +def upper_first(s): + s = str(s) + return s[0].upper() + s[1:] + + +class Filters(object): + """provides a set of filters to be used with the template engine""" + classPrefix = 'Qml' + + @staticmethod + def className(symbol): + classPrefix = Filters.classPrefix + return '{0}{1}'.format(classPrefix, symbol.name) + + @staticmethod + def defaultValue(symbol): + prefix = Filters.classPrefix + t = symbol.type # type: qface.domain.TypeSymbol + if t.is_primitive: + if t.is_int: + return '0' + if t.is_bool: + return 'false' + if t.is_string: + return 'QString()' + if t.is_real: + return '0.0' + if t.is_variant: + return 'QVariant()' + elif t.is_void: + return '' + elif t.is_enum: + name = t.reference.name + value = next(iter(t.reference.members)) + return '{0}::{1}'.format(name, value) + elif symbol.type.is_list: + nested = Filters.returnType(symbol.type.nested) + return 'QVariantList()'.format(nested) + elif symbol.type.is_struct: + return '{0}{1}()'.format(prefix, symbol.type) + elif symbol.type.is_model: + nested = symbol.type.nested + if nested.is_primitive: + return 'new {0}VariantModel(this)'.format(prefix) + elif nested.is_complex: + return 'new {0}{1}Model(this)'.format(prefix, nested) + return 'XXX' + + @staticmethod + def parameterType(symbol): + prefix = Filters.classPrefix + module_name = symbol.module.module_name + if symbol.type.is_enum: + return '{0}{1}Module::{2} {3}'.format(prefix, module_name, symbol.type, symbol) + if symbol.type.is_void or symbol.type.is_primitive: + if symbol.type.name == 'string': + return 'const QString &{0}'.format(symbol) + if symbol.type.name == 'var': + return 'const QVariant &{0}'.format(symbol) + if symbol.type.name == 'real': + return 'qreal {0}'.format(symbol) + return '{0} {1}'.format(symbol.type, symbol) + elif symbol.type.is_list: + nested = Filters.returnType(symbol.type.nested) + return 'const QVariantList &{1}'.format(nested, symbol) + elif symbol.type.is_model: + nested = symbol.type.nested + if nested.is_primitive: + return '{0}VariantModel *{1}'.format(prefix, symbol) + elif nested.is_complex: + return '{0}{1}Model *{2}'.format(prefix, nested, symbol) + else: + return 'const {0}{1} &{2}'.format(prefix, symbol.type, symbol) + return 'XXX' + + @staticmethod + def returnType(symbol): + prefix = Filters.classPrefix + module_name = symbol.module.module_name + if symbol.type.is_enum: + return '{0}{1}Module::{2}'.format(prefix, module_name, symbol.type) + if symbol.type.is_void or symbol.type.is_primitive: + if symbol.type.name == 'string': + return 'QString' + if symbol.type.name == 'var': + return 'QVariant' + if symbol.type.name == 'real': + return 'qreal' + return symbol.type.name + elif symbol.type.is_list: + nested = Filters.returnType(symbol.type.nested) + return 'QVariantList'.format(nested) + elif symbol.type.is_model: + nested = symbol.type.nested + if nested.is_primitive: + return '{0}VariantModel *'.format(prefix) + elif nested.is_complex: + return '{0}{1}Model *'.format(prefix, nested) + else: + return '{0}{1}'.format(prefix, symbol.type) + return 'XXX' + diff --git a/qface/helper/qtqml.py b/qface/helper/qtqml.py new file mode 100644 index 0000000..819000a --- /dev/null +++ b/qface/helper/qtqml.py @@ -0,0 +1,52 @@ +""" +Provides helper functionality specificially for Qt5 QML code generators +""" + + +class Filters(object): + """provides a set of filters to be used with the template engine""" + classPrefix = '' + + @staticmethod + def className(symbol): + classPrefix = Filters.classPrefix + return '{0}{1}'.format(classPrefix, symbol.name) + + @staticmethod + def defaultValue(symbol): + module = symbol.module.module_name + t = symbol.type + if t.is_primitive: + if t.name == 'int': + return '0' + elif t.name == 'bool': + return 'false' + elif t.name == 'string': + return "''" + elif t.is_enum: + value = next(iter(t.reference.members)) + return '{0}Module.{1}'.format(module, value) + if t.is_struct: + return '{0}Module.create{1}()'.format(module, t) + if t.is_model: + return 'ListModel {}' + return 'XXX' + + @staticmethod + def propertyType(symbol): + t = symbol.type + if t.is_enum: + return 'int' + if t.is_void or t.is_primitive: + if t.name == 'int': + return 'int' + if t.name == 'bool': + return 'bool' + if t.name == 'string': + return 'string' + if t.is_struct: + return 'var' + if t.is_model: + return 'ListModel' + return t + diff --git a/qface/idl/domain.py b/qface/idl/domain.py index e726a7b..3b944a9 100644 --- a/qface/idl/domain.py +++ b/qface/idl/domain.py @@ -27,7 +27,6 @@ import logging log = logging.getLogger(__name__) - class System(object): """The root entity which consist of modules""" def __init__(self): @@ -48,7 +47,6 @@ class System(object): def lookup(self, name: str): '''lookup a symbol by fully qualified name.''' # <module> - print('lookup: ' + name) if name in self._moduleMap: return self._moduleMap[name] # <module>.<Symbol> @@ -69,7 +67,6 @@ class System(object): return ('', '') - class Symbol(object): """A symbol represents a base class for names elements""" def __init__(self, name: str, module: 'Module'): @@ -79,6 +76,9 @@ class Symbol(object): """module the symbol belongs to""" self.comment = '' """comment which appeared in QDL right before symbol""" + self._tags = OrderedDict() + + @property def system(self): @@ -88,7 +88,10 @@ class Symbol(object): @property def qualified_name(self): '''return the fully qualified name (`module + "." + name`)''' - return '{0}.{1}'.format(self.module.name, self.name) + if self.module == self: + return self.module.name + else: + return '{0}.{1}'.format(self.module.name, self.name) def __unicode__(self): return self.name @@ -99,12 +102,31 @@ class Symbol(object): def __repr__(self): return '<{0} name={1}>'.format(type(self), self.name) + @property + def tags(self): + return self._tags + + def add_tag(self, tag): + if tag not in self._tags: + self._tags[tag] = OrderedDict() + + def add_attribute(self, tag, name, value): + self.add_tag(tag) + d = self._tags[tag] + d[name] = value + + def tag(self, name): + return self._tags[name] + + def attribute(self, tag, name): + if tag in self._tags: + return self._tags[tag][name] class TypedSymbol(Symbol): """A symbol which has a type, like an operation or property.""" def __init__(self, name: str, module: 'Module'): - super().__init__(name, module) + super().__init__(name, module) self.type = TypeSymbol("", self) """type object of the symbol""" @@ -174,6 +196,10 @@ class TypeSymbol(Symbol): type = self.nested if self.nested else self type.__reference = self.module.lookup(type.name) + @property + def type(self): + return self + class Module(Symbol): """Module is a namespace for types, e.g. interfaces, enums, structs""" diff --git a/qface/idl/listener.py b/qface/idl/listener.py index b257005..2bbad25 100644 --- a/qface/idl/listener.py +++ b/qface/idl/listener.py @@ -13,6 +13,7 @@ log = logging.getLogger(__name__) # associates parser context to domain objects contextMap = {} + class DomainListener(TListener): """The domain listener is called by the parser to fill the domain data struture. As a result a system is passed @@ -33,7 +34,6 @@ class DomainListener(TListener): def parse_type(self, ctx: ParserRuleContext, type: TypeSymbol): if not ctx.typeSymbol(): - # import pdb; pdb.set_trace() type.is_void = True type.name = 'void' else: @@ -60,10 +60,19 @@ class DomainListener(TListener): if not type.module.checkType(type): log.warn('Unknown type: {0}. Missing import?'.format(type.name)) - def parse_comment(self, ctx, symbol): + def parse_annotations(self, ctx, symbol): if ctx.comment: comment = ctx.comment.text symbol.comment = comment + if ctx.tagSymbol(): + for tag in ctx.tagSymbol(): + tag_name = tag.name.text[1:] + symbol.add_tag(tag_name) + attrs = tag.tagAttributeSymbol() + for attr in attrs: + attr_name = attr.name.text + attr_value = attr.value.text + symbol.add_attribute(tag_name, attr_name, attr_value) def enterEveryRule(self, ctx): log.debug('enter ' + ctx.__class__.__name__) @@ -86,7 +95,7 @@ class DomainListener(TListener): assert self.module name = ctx.name.text self.interface = Interface(name, self.module) - self.parse_comment(ctx, self.interface) + self.parse_annotations(ctx, self.interface) contextMap[ctx] = self.interface def exitInterfaceSymbol(self, ctx: TParser.InterfaceSymbolContext): @@ -96,7 +105,7 @@ class DomainListener(TListener): assert self.module name = ctx.name.text self.struct = Struct(name, self.module) - self.parse_comment(ctx, self.struct) + self.parse_annotations(ctx, self.struct) contextMap[ctx] = self.struct def exitStructSymbol(self, ctx: TParser.StructSymbolContext): @@ -107,7 +116,7 @@ class DomainListener(TListener): name = ctx.name.text # import ipdb; ipdb.set_trace() self.enum = Enum(name, self.module) - self.parse_comment(ctx, self.enum) + self.parse_annotations(ctx, self.enum) contextMap[ctx] = self.enum def exitEnumSymbol(self, ctx: TParser.EnumSymbolContext): @@ -130,7 +139,7 @@ class DomainListener(TListener): name = ctx.name.text is_event = bool(ctx.isEvent) self.operation = Operation(name, self.interface, is_event) - self.parse_comment(ctx, self.operation) + self.parse_annotations(ctx, self.operation) self.parse_type(ctx, self.operation.type) contextMap[ctx] = self.operation @@ -150,7 +159,7 @@ class DomainListener(TListener): name = ctx.name.text self.property = Property(name, self.interface) self.property.is_readonly = bool(ctx.isReadOnly) - self.parse_comment(ctx, self.property) + self.parse_annotations(ctx, self.property) self.parse_type(ctx, self.property.type) contextMap[ctx] = self.property @@ -194,4 +203,3 @@ class DomainListener(TListener): def exitImportSymbol(self, ctx: TParser.ImportSymbolContext): pass - diff --git a/qface/idl/parser/T.g4 b/qface/idl/parser/T.g4 index b0fdcd0..5e5bc9d 100644 --- a/qface/idl/parser/T.g4 +++ b/qface/idl/parser/T.g4 @@ -19,7 +19,7 @@ importSymbol ; moduleSymbol - : comment=DOCCOMMENT? 'module' name=IDENTIFIER version=VERSION ';'? + : comment=DOCCOMMENT? tagSymbol* 'module' name=IDENTIFIER version=VERSION ';'? ; definitionSymbol @@ -29,7 +29,7 @@ definitionSymbol ; interfaceSymbol - : comment=DOCCOMMENT? 'interface' name=IDENTIFIER '{' interfaceMemberSymbol* '}' ';'? + : comment=DOCCOMMENT? tagSymbol* 'interface' name=IDENTIFIER '{' interfaceMemberSymbol* '}' ';'? ; interfaceMemberSymbol @@ -38,17 +38,25 @@ interfaceMemberSymbol ; operationSymbol - : comment=DOCCOMMENT? isEvent='event'? (typeSymbol | 'void') name=IDENTIFIER '(' operationParameterSymbol* ')' ';'? + : comment=DOCCOMMENT? tagSymbol* isEvent='event'? (typeSymbol | 'void') name=IDENTIFIER '(' operationParameterSymbol* ')' ';'? ; propertySymbol - : comment=DOCCOMMENT? isReadOnly='readonly'? typeSymbol name=IDENTIFIER ';'? + : comment=DOCCOMMENT? tagSymbol* isReadOnly='readonly'? typeSymbol name=IDENTIFIER ';'? ; operationParameterSymbol : typeSymbol name=IDENTIFIER ','? ; +tagSymbol + : name=TAGIDENTIFIER '(' tagAttributeSymbol* ')' + ; + +tagAttributeSymbol + : name=IDENTIFIER ('=' value=IDENTIFIER)? + ; + typeSymbol : primitiveTypeSymbol | complexTypeSymbol @@ -77,15 +85,15 @@ modelTypeSymbol ; structSymbol - : comment=DOCCOMMENT? 'struct' name=IDENTIFIER '{' structFieldSymbol* '}' ';'? + : comment=DOCCOMMENT? tagSymbol* 'struct' name=IDENTIFIER '{' structFieldSymbol* '}' ';'? ; structFieldSymbol - : comment=DOCCOMMENT? typeSymbol name=IDENTIFIER ';'? + : comment=DOCCOMMENT? tagSymbol* typeSymbol name=IDENTIFIER ';'? ; enumSymbol - : comment=DOCCOMMENT? enumTypeSymbol name=IDENTIFIER '{' enumMemberSymbol* '}' ';'? + : comment=DOCCOMMENT? tagSymbol* enumTypeSymbol name=IDENTIFIER '{' enumMemberSymbol* '}' ';'? ; enumTypeSymbol @@ -94,7 +102,7 @@ enumTypeSymbol ; enumMemberSymbol - : comment=DOCCOMMENT? name=IDENTIFIER ('=' intSymbol)? ','? + : comment=DOCCOMMENT? tagSymbol* name=IDENTIFIER ('=' intSymbol)? ','? ; intSymbol @@ -104,9 +112,11 @@ intSymbol INTCONSTANT : ('+' | '-')? '0'..'9'+; HEXCONSTANT : '0x' ('0'..'9' | 'a'..'f' | 'A'..'F')+; +TAGIDENTIFIER : '@'[a-zA-Z_][a-zA-Z0-9_\.]*; IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_\.]*; VERSION : [0-9]'.'[0-9]; DOCCOMMENT : '/*!' .*? '*/'; WHITESPACE : [ \t\r\n]+ -> skip; COMMENT : '//' ~[\r\n]* -> skip; MULTICOMM : '/*' .*? '*/' -> skip; + diff --git a/qface/idl/parser/T.tokens b/qface/idl/parser/T.tokens index 505f1e4..4241ad3 100644 --- a/qface/idl/parser/T.tokens +++ b/qface/idl/parser/T.tokens @@ -25,12 +25,13 @@ T__23=24 T__24=25 INTCONSTANT=26 HEXCONSTANT=27 -IDENTIFIER=28 -VERSION=29 -DOCCOMMENT=30 -WHITESPACE=31 -COMMENT=32 -MULTICOMM=33 +TAGIDENTIFIER=28 +IDENTIFIER=29 +VERSION=30 +DOCCOMMENT=31 +WHITESPACE=32 +COMMENT=33 +MULTICOMM=34 'import'=1 ';'=2 'module'=3 @@ -43,16 +44,16 @@ MULTICOMM=33 ')'=10 'readonly'=11 ','=12 -'bool'=13 -'int'=14 -'real'=15 -'string'=16 -'var'=17 -'list'=18 -'<'=19 -'>'=20 -'model'=21 -'struct'=22 -'enum'=23 -'flag'=24 -'='=25 +'='=13 +'bool'=14 +'int'=15 +'real'=16 +'string'=17 +'var'=18 +'list'=19 +'<'=20 +'>'=21 +'model'=22 +'struct'=23 +'enum'=24 +'flag'=25 diff --git a/qface/idl/parser/TLexer.py b/qface/idl/parser/TLexer.py index 643b680..2fbc965 100644 --- a/qface/idl/parser/TLexer.py +++ b/qface/idl/parser/TLexer.py @@ -5,111 +5,115 @@ from io import StringIO def serializedATN(): with StringIO() as buf: - buf.write("\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2#") - buf.write("\u0100\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\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2$") + buf.write("\u010a\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\"\3\2\3\2\3\2\3\2\3") - buf.write("\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") - buf.write("\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3\7\3\7\3\b\3") - buf.write("\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3\13\3") - buf.write("\13\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3\16\3") - buf.write("\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\20\3\20\3\20") - buf.write("\3\20\3\20\3\21\3\21\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\25\3\25") - buf.write("\3\26\3\26\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\27\3\27") - buf.write("\3\27\3\27\3\30\3\30\3\30\3\30\3\30\3\31\3\31\3\31\3\31") - buf.write("\3\31\3\32\3\32\3\33\5\33\u00ba\n\33\3\33\6\33\u00bd\n") - buf.write("\33\r\33\16\33\u00be\3\34\3\34\3\34\3\34\6\34\u00c5\n") - buf.write("\34\r\34\16\34\u00c6\3\35\3\35\7\35\u00cb\n\35\f\35\16") - buf.write("\35\u00ce\13\35\3\36\3\36\3\36\3\36\3\37\3\37\3\37\3\37") - buf.write("\3\37\7\37\u00d9\n\37\f\37\16\37\u00dc\13\37\3\37\3\37") - buf.write("\3\37\3 \6 \u00e2\n \r \16 \u00e3\3 \3 \3!\3!\3!\3!\7") - buf.write("!\u00ec\n!\f!\16!\u00ef\13!\3!\3!\3\"\3\"\3\"\3\"\7\"") - buf.write("\u00f7\n\"\f\"\16\"\u00fa\13\"\3\"\3\"\3\"\3\"\3\"\4\u00da") - buf.write("\u00f8\2#\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25") - buf.write("\f\27\r\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+") - buf.write("\27-\30/\31\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#\3") - buf.write("\2\t\4\2--//\5\2\62;CHch\5\2C\\aac|\b\2\60\60\62;C\\^") - buf.write("^aac|\3\2\62;\5\2\13\f\17\17\"\"\4\2\f\f\17\17\u0107\2") - buf.write("\3\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") - buf.write("\2\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2") - buf.write("\2\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2") - buf.write("\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\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\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\3E\3\2\2\2\5L\3\2\2\2\7N\3\2\2\2") - buf.write("\tU\3\2\2\2\13_\3\2\2\2\ra\3\2\2\2\17c\3\2\2\2\21i\3\2") - buf.write("\2\2\23n\3\2\2\2\25p\3\2\2\2\27r\3\2\2\2\31{\3\2\2\2\33") - buf.write("}\3\2\2\2\35\u0082\3\2\2\2\37\u0086\3\2\2\2!\u008b\3\2") - buf.write("\2\2#\u0092\3\2\2\2%\u0096\3\2\2\2\'\u009b\3\2\2\2)\u009d") - buf.write("\3\2\2\2+\u009f\3\2\2\2-\u00a5\3\2\2\2/\u00ac\3\2\2\2") - buf.write("\61\u00b1\3\2\2\2\63\u00b6\3\2\2\2\65\u00b9\3\2\2\2\67") - buf.write("\u00c0\3\2\2\29\u00c8\3\2\2\2;\u00cf\3\2\2\2=\u00d3\3") - buf.write("\2\2\2?\u00e1\3\2\2\2A\u00e7\3\2\2\2C\u00f2\3\2\2\2EF") - buf.write("\7k\2\2FG\7o\2\2GH\7r\2\2HI\7q\2\2IJ\7t\2\2JK\7v\2\2K") - buf.write("\4\3\2\2\2LM\7=\2\2M\6\3\2\2\2NO\7o\2\2OP\7q\2\2PQ\7f") - buf.write("\2\2QR\7w\2\2RS\7n\2\2ST\7g\2\2T\b\3\2\2\2UV\7k\2\2VW") - buf.write("\7p\2\2WX\7v\2\2XY\7g\2\2YZ\7t\2\2Z[\7h\2\2[\\\7c\2\2") - buf.write("\\]\7e\2\2]^\7g\2\2^\n\3\2\2\2_`\7}\2\2`\f\3\2\2\2ab\7") - buf.write("\177\2\2b\16\3\2\2\2cd\7g\2\2de\7x\2\2ef\7g\2\2fg\7p\2") - buf.write("\2gh\7v\2\2h\20\3\2\2\2ij\7x\2\2jk\7q\2\2kl\7k\2\2lm\7") - buf.write("f\2\2m\22\3\2\2\2no\7*\2\2o\24\3\2\2\2pq\7+\2\2q\26\3") - buf.write("\2\2\2rs\7t\2\2st\7g\2\2tu\7c\2\2uv\7f\2\2vw\7q\2\2wx") - buf.write("\7p\2\2xy\7n\2\2yz\7{\2\2z\30\3\2\2\2{|\7.\2\2|\32\3\2") - buf.write("\2\2}~\7d\2\2~\177\7q\2\2\177\u0080\7q\2\2\u0080\u0081") - buf.write("\7n\2\2\u0081\34\3\2\2\2\u0082\u0083\7k\2\2\u0083\u0084") - buf.write("\7p\2\2\u0084\u0085\7v\2\2\u0085\36\3\2\2\2\u0086\u0087") - buf.write("\7t\2\2\u0087\u0088\7g\2\2\u0088\u0089\7c\2\2\u0089\u008a") - buf.write("\7n\2\2\u008a \3\2\2\2\u008b\u008c\7u\2\2\u008c\u008d") - buf.write("\7v\2\2\u008d\u008e\7t\2\2\u008e\u008f\7k\2\2\u008f\u0090") - buf.write("\7p\2\2\u0090\u0091\7i\2\2\u0091\"\3\2\2\2\u0092\u0093") - buf.write("\7x\2\2\u0093\u0094\7c\2\2\u0094\u0095\7t\2\2\u0095$\3") - buf.write("\2\2\2\u0096\u0097\7n\2\2\u0097\u0098\7k\2\2\u0098\u0099") - buf.write("\7u\2\2\u0099\u009a\7v\2\2\u009a&\3\2\2\2\u009b\u009c") - buf.write("\7>\2\2\u009c(\3\2\2\2\u009d\u009e\7@\2\2\u009e*\3\2\2") - buf.write("\2\u009f\u00a0\7o\2\2\u00a0\u00a1\7q\2\2\u00a1\u00a2\7") - buf.write("f\2\2\u00a2\u00a3\7g\2\2\u00a3\u00a4\7n\2\2\u00a4,\3\2") - buf.write("\2\2\u00a5\u00a6\7u\2\2\u00a6\u00a7\7v\2\2\u00a7\u00a8") - buf.write("\7t\2\2\u00a8\u00a9\7w\2\2\u00a9\u00aa\7e\2\2\u00aa\u00ab") - buf.write("\7v\2\2\u00ab.\3\2\2\2\u00ac\u00ad\7g\2\2\u00ad\u00ae") - buf.write("\7p\2\2\u00ae\u00af\7w\2\2\u00af\u00b0\7o\2\2\u00b0\60") - buf.write("\3\2\2\2\u00b1\u00b2\7h\2\2\u00b2\u00b3\7n\2\2\u00b3\u00b4") - buf.write("\7c\2\2\u00b4\u00b5\7i\2\2\u00b5\62\3\2\2\2\u00b6\u00b7") - buf.write("\7?\2\2\u00b7\64\3\2\2\2\u00b8\u00ba\t\2\2\2\u00b9\u00b8") - buf.write("\3\2\2\2\u00b9\u00ba\3\2\2\2\u00ba\u00bc\3\2\2\2\u00bb") - buf.write("\u00bd\4\62;\2\u00bc\u00bb\3\2\2\2\u00bd\u00be\3\2\2\2") - buf.write("\u00be\u00bc\3\2\2\2\u00be\u00bf\3\2\2\2\u00bf\66\3\2") - buf.write("\2\2\u00c0\u00c1\7\62\2\2\u00c1\u00c2\7z\2\2\u00c2\u00c4") - buf.write("\3\2\2\2\u00c3\u00c5\t\3\2\2\u00c4\u00c3\3\2\2\2\u00c5") - buf.write("\u00c6\3\2\2\2\u00c6\u00c4\3\2\2\2\u00c6\u00c7\3\2\2\2") - buf.write("\u00c78\3\2\2\2\u00c8\u00cc\t\4\2\2\u00c9\u00cb\t\5\2") - buf.write("\2\u00ca\u00c9\3\2\2\2\u00cb\u00ce\3\2\2\2\u00cc\u00ca") - buf.write("\3\2\2\2\u00cc\u00cd\3\2\2\2\u00cd:\3\2\2\2\u00ce\u00cc") - buf.write("\3\2\2\2\u00cf\u00d0\t\6\2\2\u00d0\u00d1\7\60\2\2\u00d1") - buf.write("\u00d2\t\6\2\2\u00d2<\3\2\2\2\u00d3\u00d4\7\61\2\2\u00d4") - buf.write("\u00d5\7,\2\2\u00d5\u00d6\7#\2\2\u00d6\u00da\3\2\2\2\u00d7") - buf.write("\u00d9\13\2\2\2\u00d8\u00d7\3\2\2\2\u00d9\u00dc\3\2\2") - buf.write("\2\u00da\u00db\3\2\2\2\u00da\u00d8\3\2\2\2\u00db\u00dd") - buf.write("\3\2\2\2\u00dc\u00da\3\2\2\2\u00dd\u00de\7,\2\2\u00de") - buf.write("\u00df\7\61\2\2\u00df>\3\2\2\2\u00e0\u00e2\t\7\2\2\u00e1") - buf.write("\u00e0\3\2\2\2\u00e2\u00e3\3\2\2\2\u00e3\u00e1\3\2\2\2") - buf.write("\u00e3\u00e4\3\2\2\2\u00e4\u00e5\3\2\2\2\u00e5\u00e6\b") - buf.write(" \2\2\u00e6@\3\2\2\2\u00e7\u00e8\7\61\2\2\u00e8\u00e9") - buf.write("\7\61\2\2\u00e9\u00ed\3\2\2\2\u00ea\u00ec\n\b\2\2\u00eb") - buf.write("\u00ea\3\2\2\2\u00ec\u00ef\3\2\2\2\u00ed\u00eb\3\2\2\2") - buf.write("\u00ed\u00ee\3\2\2\2\u00ee\u00f0\3\2\2\2\u00ef\u00ed\3") - buf.write("\2\2\2\u00f0\u00f1\b!\2\2\u00f1B\3\2\2\2\u00f2\u00f3\7") - buf.write("\61\2\2\u00f3\u00f4\7,\2\2\u00f4\u00f8\3\2\2\2\u00f5\u00f7") - buf.write("\13\2\2\2\u00f6\u00f5\3\2\2\2\u00f7\u00fa\3\2\2\2\u00f8") - buf.write("\u00f9\3\2\2\2\u00f8\u00f6\3\2\2\2\u00f9\u00fb\3\2\2\2") - buf.write("\u00fa\u00f8\3\2\2\2\u00fb\u00fc\7,\2\2\u00fc\u00fd\7") - buf.write("\61\2\2\u00fd\u00fe\3\2\2\2\u00fe\u00ff\b\"\2\2\u00ff") - buf.write("D\3\2\2\2\13\2\u00b9\u00be\u00c6\u00cc\u00da\u00e3\u00ed") - buf.write("\u00f8\3\b\2\2") + buf.write("\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\3\2\3\2\3\2") + buf.write("\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") + buf.write("\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\6\3\6\3\7\3\7") + buf.write("\3\b\3\b\3\b\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\n\3\n\3") + buf.write("\13\3\13\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\r\3\r\3") + buf.write("\16\3\16\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20\3\20") + buf.write("\3\21\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\22\3\22") + buf.write("\3\22\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\25") + buf.write("\3\25\3\26\3\26\3\27\3\27\3\27\3\27\3\27\3\27\3\30\3\30") + buf.write("\3\30\3\30\3\30\3\30\3\30\3\31\3\31\3\31\3\31\3\31\3\32") + buf.write("\3\32\3\32\3\32\3\32\3\33\5\33\u00bc\n\33\3\33\6\33\u00bf") + buf.write("\n\33\r\33\16\33\u00c0\3\34\3\34\3\34\3\34\6\34\u00c7") + buf.write("\n\34\r\34\16\34\u00c8\3\35\3\35\3\35\7\35\u00ce\n\35") + buf.write("\f\35\16\35\u00d1\13\35\3\36\3\36\7\36\u00d5\n\36\f\36") + buf.write("\16\36\u00d8\13\36\3\37\3\37\3\37\3\37\3 \3 \3 \3 \3 ") + buf.write("\7 \u00e3\n \f \16 \u00e6\13 \3 \3 \3 \3!\6!\u00ec\n!") + buf.write("\r!\16!\u00ed\3!\3!\3\"\3\"\3\"\3\"\7\"\u00f6\n\"\f\"") + buf.write("\16\"\u00f9\13\"\3\"\3\"\3#\3#\3#\3#\7#\u0101\n#\f#\16") + buf.write("#\u0104\13#\3#\3#\3#\3#\3#\4\u00e4\u0102\2$\3\3\5\4\7") + buf.write("\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33\17") + buf.write("\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32\63") + buf.write("\33\65\34\67\359\36;\37= ?!A\"C#E$\3\2\t\4\2--//\5\2\62") + buf.write(";CHch\5\2C\\aac|\b\2\60\60\62;C\\^^aac|\3\2\62;\5\2\13") + buf.write("\f\17\17\"\"\4\2\f\f\17\17\u0112\2\3\3\2\2\2\2\5\3\2\2") + buf.write("\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r\3\2\2\2\2") + buf.write("\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27") + buf.write("\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") + 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+\3\2\2\2\2-\3\2\2\2\2/\3\2\2\2\2\61\3\2\2") + buf.write("\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2\2\2") + buf.write(";\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2") + buf.write("\2E\3\2\2\2\3G\3\2\2\2\5N\3\2\2\2\7P\3\2\2\2\tW\3\2\2") + buf.write("\2\13a\3\2\2\2\rc\3\2\2\2\17e\3\2\2\2\21k\3\2\2\2\23p") + buf.write("\3\2\2\2\25r\3\2\2\2\27t\3\2\2\2\31}\3\2\2\2\33\177\3") + buf.write("\2\2\2\35\u0081\3\2\2\2\37\u0086\3\2\2\2!\u008a\3\2\2") + buf.write("\2#\u008f\3\2\2\2%\u0096\3\2\2\2\'\u009a\3\2\2\2)\u009f") + buf.write("\3\2\2\2+\u00a1\3\2\2\2-\u00a3\3\2\2\2/\u00a9\3\2\2\2") + buf.write("\61\u00b0\3\2\2\2\63\u00b5\3\2\2\2\65\u00bb\3\2\2\2\67") + buf.write("\u00c2\3\2\2\29\u00ca\3\2\2\2;\u00d2\3\2\2\2=\u00d9\3") + buf.write("\2\2\2?\u00dd\3\2\2\2A\u00eb\3\2\2\2C\u00f1\3\2\2\2E\u00fc") + buf.write("\3\2\2\2GH\7k\2\2HI\7o\2\2IJ\7r\2\2JK\7q\2\2KL\7t\2\2") + buf.write("LM\7v\2\2M\4\3\2\2\2NO\7=\2\2O\6\3\2\2\2PQ\7o\2\2QR\7") + buf.write("q\2\2RS\7f\2\2ST\7w\2\2TU\7n\2\2UV\7g\2\2V\b\3\2\2\2W") + buf.write("X\7k\2\2XY\7p\2\2YZ\7v\2\2Z[\7g\2\2[\\\7t\2\2\\]\7h\2") + buf.write("\2]^\7c\2\2^_\7e\2\2_`\7g\2\2`\n\3\2\2\2ab\7}\2\2b\f\3") + buf.write("\2\2\2cd\7\177\2\2d\16\3\2\2\2ef\7g\2\2fg\7x\2\2gh\7g") + buf.write("\2\2hi\7p\2\2ij\7v\2\2j\20\3\2\2\2kl\7x\2\2lm\7q\2\2m") + buf.write("n\7k\2\2no\7f\2\2o\22\3\2\2\2pq\7*\2\2q\24\3\2\2\2rs\7") + buf.write("+\2\2s\26\3\2\2\2tu\7t\2\2uv\7g\2\2vw\7c\2\2wx\7f\2\2") + buf.write("xy\7q\2\2yz\7p\2\2z{\7n\2\2{|\7{\2\2|\30\3\2\2\2}~\7.") + buf.write("\2\2~\32\3\2\2\2\177\u0080\7?\2\2\u0080\34\3\2\2\2\u0081") + buf.write("\u0082\7d\2\2\u0082\u0083\7q\2\2\u0083\u0084\7q\2\2\u0084") + buf.write("\u0085\7n\2\2\u0085\36\3\2\2\2\u0086\u0087\7k\2\2\u0087") + buf.write("\u0088\7p\2\2\u0088\u0089\7v\2\2\u0089 \3\2\2\2\u008a") + buf.write("\u008b\7t\2\2\u008b\u008c\7g\2\2\u008c\u008d\7c\2\2\u008d") + buf.write("\u008e\7n\2\2\u008e\"\3\2\2\2\u008f\u0090\7u\2\2\u0090") + buf.write("\u0091\7v\2\2\u0091\u0092\7t\2\2\u0092\u0093\7k\2\2\u0093") + buf.write("\u0094\7p\2\2\u0094\u0095\7i\2\2\u0095$\3\2\2\2\u0096") + buf.write("\u0097\7x\2\2\u0097\u0098\7c\2\2\u0098\u0099\7t\2\2\u0099") + buf.write("&\3\2\2\2\u009a\u009b\7n\2\2\u009b\u009c\7k\2\2\u009c") + buf.write("\u009d\7u\2\2\u009d\u009e\7v\2\2\u009e(\3\2\2\2\u009f") + buf.write("\u00a0\7>\2\2\u00a0*\3\2\2\2\u00a1\u00a2\7@\2\2\u00a2") + buf.write(",\3\2\2\2\u00a3\u00a4\7o\2\2\u00a4\u00a5\7q\2\2\u00a5") + buf.write("\u00a6\7f\2\2\u00a6\u00a7\7g\2\2\u00a7\u00a8\7n\2\2\u00a8") + buf.write(".\3\2\2\2\u00a9\u00aa\7u\2\2\u00aa\u00ab\7v\2\2\u00ab") + buf.write("\u00ac\7t\2\2\u00ac\u00ad\7w\2\2\u00ad\u00ae\7e\2\2\u00ae") + buf.write("\u00af\7v\2\2\u00af\60\3\2\2\2\u00b0\u00b1\7g\2\2\u00b1") + buf.write("\u00b2\7p\2\2\u00b2\u00b3\7w\2\2\u00b3\u00b4\7o\2\2\u00b4") + buf.write("\62\3\2\2\2\u00b5\u00b6\7h\2\2\u00b6\u00b7\7n\2\2\u00b7") + buf.write("\u00b8\7c\2\2\u00b8\u00b9\7i\2\2\u00b9\64\3\2\2\2\u00ba") + buf.write("\u00bc\t\2\2\2\u00bb\u00ba\3\2\2\2\u00bb\u00bc\3\2\2\2") + buf.write("\u00bc\u00be\3\2\2\2\u00bd\u00bf\4\62;\2\u00be\u00bd\3") + buf.write("\2\2\2\u00bf\u00c0\3\2\2\2\u00c0\u00be\3\2\2\2\u00c0\u00c1") + buf.write("\3\2\2\2\u00c1\66\3\2\2\2\u00c2\u00c3\7\62\2\2\u00c3\u00c4") + buf.write("\7z\2\2\u00c4\u00c6\3\2\2\2\u00c5\u00c7\t\3\2\2\u00c6") + buf.write("\u00c5\3\2\2\2\u00c7\u00c8\3\2\2\2\u00c8\u00c6\3\2\2\2") + buf.write("\u00c8\u00c9\3\2\2\2\u00c98\3\2\2\2\u00ca\u00cb\7B\2\2") + buf.write("\u00cb\u00cf\t\4\2\2\u00cc\u00ce\t\5\2\2\u00cd\u00cc\3") + buf.write("\2\2\2\u00ce\u00d1\3\2\2\2\u00cf\u00cd\3\2\2\2\u00cf\u00d0") + buf.write("\3\2\2\2\u00d0:\3\2\2\2\u00d1\u00cf\3\2\2\2\u00d2\u00d6") + buf.write("\t\4\2\2\u00d3\u00d5\t\5\2\2\u00d4\u00d3\3\2\2\2\u00d5") + buf.write("\u00d8\3\2\2\2\u00d6\u00d4\3\2\2\2\u00d6\u00d7\3\2\2\2") + buf.write("\u00d7<\3\2\2\2\u00d8\u00d6\3\2\2\2\u00d9\u00da\t\6\2") + buf.write("\2\u00da\u00db\7\60\2\2\u00db\u00dc\t\6\2\2\u00dc>\3\2") + buf.write("\2\2\u00dd\u00de\7\61\2\2\u00de\u00df\7,\2\2\u00df\u00e0") + buf.write("\7#\2\2\u00e0\u00e4\3\2\2\2\u00e1\u00e3\13\2\2\2\u00e2") + buf.write("\u00e1\3\2\2\2\u00e3\u00e6\3\2\2\2\u00e4\u00e5\3\2\2\2") + buf.write("\u00e4\u00e2\3\2\2\2\u00e5\u00e7\3\2\2\2\u00e6\u00e4\3") + buf.write("\2\2\2\u00e7\u00e8\7,\2\2\u00e8\u00e9\7\61\2\2\u00e9@") + buf.write("\3\2\2\2\u00ea\u00ec\t\7\2\2\u00eb\u00ea\3\2\2\2\u00ec") + buf.write("\u00ed\3\2\2\2\u00ed\u00eb\3\2\2\2\u00ed\u00ee\3\2\2\2") + buf.write("\u00ee\u00ef\3\2\2\2\u00ef\u00f0\b!\2\2\u00f0B\3\2\2\2") + buf.write("\u00f1\u00f2\7\61\2\2\u00f2\u00f3\7\61\2\2\u00f3\u00f7") + buf.write("\3\2\2\2\u00f4\u00f6\n\b\2\2\u00f5\u00f4\3\2\2\2\u00f6") + buf.write("\u00f9\3\2\2\2\u00f7\u00f5\3\2\2\2\u00f7\u00f8\3\2\2\2") + buf.write("\u00f8\u00fa\3\2\2\2\u00f9\u00f7\3\2\2\2\u00fa\u00fb\b") + buf.write("\"\2\2\u00fbD\3\2\2\2\u00fc\u00fd\7\61\2\2\u00fd\u00fe") + buf.write("\7,\2\2\u00fe\u0102\3\2\2\2\u00ff\u0101\13\2\2\2\u0100") + buf.write("\u00ff\3\2\2\2\u0101\u0104\3\2\2\2\u0102\u0103\3\2\2\2") + buf.write("\u0102\u0100\3\2\2\2\u0103\u0105\3\2\2\2\u0104\u0102\3") + buf.write("\2\2\2\u0105\u0106\7,\2\2\u0106\u0107\7\61\2\2\u0107\u0108") + buf.write("\3\2\2\2\u0108\u0109\b#\2\2\u0109F\3\2\2\2\f\2\u00bb\u00c0") + buf.write("\u00c8\u00cf\u00d6\u00e4\u00ed\u00f7\u0102\3\b\2\2") return buf.getvalue() @@ -147,31 +151,32 @@ class TLexer(Lexer): T__24 = 25 INTCONSTANT = 26 HEXCONSTANT = 27 - IDENTIFIER = 28 - VERSION = 29 - DOCCOMMENT = 30 - WHITESPACE = 31 - COMMENT = 32 - MULTICOMM = 33 + TAGIDENTIFIER = 28 + IDENTIFIER = 29 + VERSION = 30 + DOCCOMMENT = 31 + WHITESPACE = 32 + COMMENT = 33 + MULTICOMM = 34 modeNames = [ "DEFAULT_MODE" ] literalNames = [ "<INVALID>", "'import'", "';'", "'module'", "'interface'", "'{'", "'}'", - "'event'", "'void'", "'('", "')'", "'readonly'", "','", "'bool'", - "'int'", "'real'", "'string'", "'var'", "'list'", "'<'", "'>'", - "'model'", "'struct'", "'enum'", "'flag'", "'='" ] + "'event'", "'void'", "'('", "')'", "'readonly'", "','", "'='", + "'bool'", "'int'", "'real'", "'string'", "'var'", "'list'", + "'<'", "'>'", "'model'", "'struct'", "'enum'", "'flag'" ] symbolicNames = [ "<INVALID>", - "INTCONSTANT", "HEXCONSTANT", "IDENTIFIER", "VERSION", "DOCCOMMENT", - "WHITESPACE", "COMMENT", "MULTICOMM" ] + "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", "INTCONSTANT", - "HEXCONSTANT", "IDENTIFIER", "VERSION", "DOCCOMMENT", - "WHITESPACE", "COMMENT", "MULTICOMM" ] + "HEXCONSTANT", "TAGIDENTIFIER", "IDENTIFIER", "VERSION", + "DOCCOMMENT", "WHITESPACE", "COMMENT", "MULTICOMM" ] grammarFileName = "T.g4" diff --git a/qface/idl/parser/TLexer.tokens b/qface/idl/parser/TLexer.tokens index 505f1e4..4241ad3 100644 --- a/qface/idl/parser/TLexer.tokens +++ b/qface/idl/parser/TLexer.tokens @@ -25,12 +25,13 @@ T__23=24 T__24=25 INTCONSTANT=26 HEXCONSTANT=27 -IDENTIFIER=28 -VERSION=29 -DOCCOMMENT=30 -WHITESPACE=31 -COMMENT=32 -MULTICOMM=33 +TAGIDENTIFIER=28 +IDENTIFIER=29 +VERSION=30 +DOCCOMMENT=31 +WHITESPACE=32 +COMMENT=33 +MULTICOMM=34 'import'=1 ';'=2 'module'=3 @@ -43,16 +44,16 @@ MULTICOMM=33 ')'=10 'readonly'=11 ','=12 -'bool'=13 -'int'=14 -'real'=15 -'string'=16 -'var'=17 -'list'=18 -'<'=19 -'>'=20 -'model'=21 -'struct'=22 -'enum'=23 -'flag'=24 -'='=25 +'='=13 +'bool'=14 +'int'=15 +'real'=16 +'string'=17 +'var'=18 +'list'=19 +'<'=20 +'>'=21 +'model'=22 +'struct'=23 +'enum'=24 +'flag'=25 diff --git a/qface/idl/parser/TListener.py b/qface/idl/parser/TListener.py index 10f5a3a..dbcafbd 100644 --- a/qface/idl/parser/TListener.py +++ b/qface/idl/parser/TListener.py @@ -98,6 +98,24 @@ class TListener(ParseTreeListener): pass + # Enter a parse tree produced by TParser#tagSymbol. + def enterTagSymbol(self, ctx:TParser.TagSymbolContext): + pass + + # Exit a parse tree produced by TParser#tagSymbol. + def exitTagSymbol(self, ctx:TParser.TagSymbolContext): + pass + + + # Enter a parse tree produced by TParser#tagAttributeSymbol. + def enterTagAttributeSymbol(self, ctx:TParser.TagAttributeSymbolContext): + pass + + # Exit a parse tree produced by TParser#tagAttributeSymbol. + def exitTagAttributeSymbol(self, ctx:TParser.TagAttributeSymbolContext): + pass + + # Enter a parse tree produced by TParser#typeSymbol. def enterTypeSymbol(self, ctx:TParser.TypeSymbolContext): pass diff --git a/qface/idl/parser/TParser.py b/qface/idl/parser/TParser.py index 228d366..5130a93 100644 --- a/qface/idl/parser/TParser.py +++ b/qface/idl/parser/TParser.py @@ -5,99 +5,137 @@ from io import StringIO def serializedATN(): with StringIO() as buf: - buf.write("\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3#") - buf.write("\u00dd\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\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3$") + buf.write("\u0120\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\3\2\3\2\7\2/\n\2\f\2\16") - buf.write("\2\62\13\2\3\3\3\3\7\3\66\n\3\f\3\16\39\13\3\3\4\3\4\3") - buf.write("\4\3\4\5\4?\n\4\3\5\5\5B\n\5\3\5\3\5\3\5\3\5\5\5H\n\5") - buf.write("\3\6\3\6\3\6\5\6M\n\6\3\7\5\7P\n\7\3\7\3\7\3\7\3\7\7\7") - buf.write("V\n\7\f\7\16\7Y\13\7\3\7\3\7\5\7]\n\7\3\b\3\b\5\ba\n\b") - buf.write("\3\t\5\td\n\t\3\t\5\tg\n\t\3\t\3\t\5\tk\n\t\3\t\3\t\3") - buf.write("\t\7\tp\n\t\f\t\16\ts\13\t\3\t\3\t\5\tw\n\t\3\n\5\nz\n") - buf.write("\n\3\n\5\n}\n\n\3\n\3\n\3\n\5\n\u0082\n\n\3\13\3\13\3") - buf.write("\13\5\13\u0087\n\13\3\f\3\f\3\f\3\f\5\f\u008d\n\f\3\r") - buf.write("\3\r\3\16\3\16\3\16\3\16\3\16\5\16\u0096\n\16\3\17\3\17") - buf.write("\3\17\3\17\3\17\3\20\3\20\3\20\3\20\3\20\3\21\5\21\u00a3") - buf.write("\n\21\3\21\3\21\3\21\3\21\7\21\u00a9\n\21\f\21\16\21\u00ac") - buf.write("\13\21\3\21\3\21\5\21\u00b0\n\21\3\22\5\22\u00b3\n\22") - buf.write("\3\22\3\22\3\22\5\22\u00b8\n\22\3\23\5\23\u00bb\n\23\3") - buf.write("\23\3\23\3\23\3\23\7\23\u00c1\n\23\f\23\16\23\u00c4\13") - buf.write("\23\3\23\3\23\5\23\u00c8\n\23\3\24\3\24\5\24\u00cc\n\24") - buf.write("\3\25\5\25\u00cf\n\25\3\25\3\25\3\25\5\25\u00d4\n\25\3") - buf.write("\25\5\25\u00d7\n\25\3\26\3\26\5\26\u00db\n\26\3\26\2\2") - buf.write("\27\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*\2\2") - buf.write("\u00ef\2,\3\2\2\2\4\63\3\2\2\2\6:\3\2\2\2\bA\3\2\2\2\n") - buf.write("L\3\2\2\2\fO\3\2\2\2\16`\3\2\2\2\20c\3\2\2\2\22y\3\2\2") - buf.write("\2\24\u0083\3\2\2\2\26\u008c\3\2\2\2\30\u008e\3\2\2\2") - buf.write("\32\u0095\3\2\2\2\34\u0097\3\2\2\2\36\u009c\3\2\2\2 \u00a2") - buf.write("\3\2\2\2\"\u00b2\3\2\2\2$\u00ba\3\2\2\2&\u00cb\3\2\2\2") - buf.write("(\u00ce\3\2\2\2*\u00da\3\2\2\2,\60\5\4\3\2-/\5\n\6\2.") - buf.write("-\3\2\2\2/\62\3\2\2\2\60.\3\2\2\2\60\61\3\2\2\2\61\3\3") - buf.write("\2\2\2\62\60\3\2\2\2\63\67\5\b\5\2\64\66\5\6\4\2\65\64") - buf.write("\3\2\2\2\669\3\2\2\2\67\65\3\2\2\2\678\3\2\2\28\5\3\2") - buf.write("\2\29\67\3\2\2\2:;\7\3\2\2;<\7\36\2\2<>\7\37\2\2=?\7\4") - buf.write("\2\2>=\3\2\2\2>?\3\2\2\2?\7\3\2\2\2@B\7 \2\2A@\3\2\2\2") - buf.write("AB\3\2\2\2BC\3\2\2\2CD\7\5\2\2DE\7\36\2\2EG\7\37\2\2F") - buf.write("H\7\4\2\2GF\3\2\2\2GH\3\2\2\2H\t\3\2\2\2IM\5\f\7\2JM\5") - buf.write(" \21\2KM\5$\23\2LI\3\2\2\2LJ\3\2\2\2LK\3\2\2\2M\13\3\2") - buf.write("\2\2NP\7 \2\2ON\3\2\2\2OP\3\2\2\2PQ\3\2\2\2QR\7\6\2\2") - buf.write("RS\7\36\2\2SW\7\7\2\2TV\5\16\b\2UT\3\2\2\2VY\3\2\2\2W") - buf.write("U\3\2\2\2WX\3\2\2\2XZ\3\2\2\2YW\3\2\2\2Z\\\7\b\2\2[]\7") - buf.write("\4\2\2\\[\3\2\2\2\\]\3\2\2\2]\r\3\2\2\2^a\5\20\t\2_a\5") - buf.write("\22\n\2`^\3\2\2\2`_\3\2\2\2a\17\3\2\2\2bd\7 \2\2cb\3\2") - buf.write("\2\2cd\3\2\2\2df\3\2\2\2eg\7\t\2\2fe\3\2\2\2fg\3\2\2\2") - buf.write("gj\3\2\2\2hk\5\26\f\2ik\7\n\2\2jh\3\2\2\2ji\3\2\2\2kl") - buf.write("\3\2\2\2lm\7\36\2\2mq\7\13\2\2np\5\24\13\2on\3\2\2\2p") - buf.write("s\3\2\2\2qo\3\2\2\2qr\3\2\2\2rt\3\2\2\2sq\3\2\2\2tv\7") - buf.write("\f\2\2uw\7\4\2\2vu\3\2\2\2vw\3\2\2\2w\21\3\2\2\2xz\7 ") - buf.write("\2\2yx\3\2\2\2yz\3\2\2\2z|\3\2\2\2{}\7\r\2\2|{\3\2\2\2") - buf.write("|}\3\2\2\2}~\3\2\2\2~\177\5\26\f\2\177\u0081\7\36\2\2") - buf.write("\u0080\u0082\7\4\2\2\u0081\u0080\3\2\2\2\u0081\u0082\3") - buf.write("\2\2\2\u0082\23\3\2\2\2\u0083\u0084\5\26\f\2\u0084\u0086") - buf.write("\7\36\2\2\u0085\u0087\7\16\2\2\u0086\u0085\3\2\2\2\u0086") - buf.write("\u0087\3\2\2\2\u0087\25\3\2\2\2\u0088\u008d\5\32\16\2") - buf.write("\u0089\u008d\5\30\r\2\u008a\u008d\5\34\17\2\u008b\u008d") - buf.write("\5\36\20\2\u008c\u0088\3\2\2\2\u008c\u0089\3\2\2\2\u008c") - buf.write("\u008a\3\2\2\2\u008c\u008b\3\2\2\2\u008d\27\3\2\2\2\u008e") - buf.write("\u008f\7\36\2\2\u008f\31\3\2\2\2\u0090\u0096\7\17\2\2") - buf.write("\u0091\u0096\7\20\2\2\u0092\u0096\7\21\2\2\u0093\u0096") - buf.write("\7\22\2\2\u0094\u0096\7\23\2\2\u0095\u0090\3\2\2\2\u0095") - buf.write("\u0091\3\2\2\2\u0095\u0092\3\2\2\2\u0095\u0093\3\2\2\2") - buf.write("\u0095\u0094\3\2\2\2\u0096\33\3\2\2\2\u0097\u0098\7\24") - buf.write("\2\2\u0098\u0099\7\25\2\2\u0099\u009a\5\26\f\2\u009a\u009b") - buf.write("\7\26\2\2\u009b\35\3\2\2\2\u009c\u009d\7\27\2\2\u009d") - buf.write("\u009e\7\25\2\2\u009e\u009f\5\26\f\2\u009f\u00a0\7\26") - buf.write("\2\2\u00a0\37\3\2\2\2\u00a1\u00a3\7 \2\2\u00a2\u00a1\3") - buf.write("\2\2\2\u00a2\u00a3\3\2\2\2\u00a3\u00a4\3\2\2\2\u00a4\u00a5") - buf.write("\7\30\2\2\u00a5\u00a6\7\36\2\2\u00a6\u00aa\7\7\2\2\u00a7") - buf.write("\u00a9\5\"\22\2\u00a8\u00a7\3\2\2\2\u00a9\u00ac\3\2\2") - buf.write("\2\u00aa\u00a8\3\2\2\2\u00aa\u00ab\3\2\2\2\u00ab\u00ad") - buf.write("\3\2\2\2\u00ac\u00aa\3\2\2\2\u00ad\u00af\7\b\2\2\u00ae") - buf.write("\u00b0\7\4\2\2\u00af\u00ae\3\2\2\2\u00af\u00b0\3\2\2\2") - buf.write("\u00b0!\3\2\2\2\u00b1\u00b3\7 \2\2\u00b2\u00b1\3\2\2\2") - buf.write("\u00b2\u00b3\3\2\2\2\u00b3\u00b4\3\2\2\2\u00b4\u00b5\5") - buf.write("\26\f\2\u00b5\u00b7\7\36\2\2\u00b6\u00b8\7\4\2\2\u00b7") - buf.write("\u00b6\3\2\2\2\u00b7\u00b8\3\2\2\2\u00b8#\3\2\2\2\u00b9") - buf.write("\u00bb\7 \2\2\u00ba\u00b9\3\2\2\2\u00ba\u00bb\3\2\2\2") - buf.write("\u00bb\u00bc\3\2\2\2\u00bc\u00bd\5&\24\2\u00bd\u00be\7") - buf.write("\36\2\2\u00be\u00c2\7\7\2\2\u00bf\u00c1\5(\25\2\u00c0") - buf.write("\u00bf\3\2\2\2\u00c1\u00c4\3\2\2\2\u00c2\u00c0\3\2\2\2") - buf.write("\u00c2\u00c3\3\2\2\2\u00c3\u00c5\3\2\2\2\u00c4\u00c2\3") - buf.write("\2\2\2\u00c5\u00c7\7\b\2\2\u00c6\u00c8\7\4\2\2\u00c7\u00c6") - buf.write("\3\2\2\2\u00c7\u00c8\3\2\2\2\u00c8%\3\2\2\2\u00c9\u00cc") - buf.write("\7\31\2\2\u00ca\u00cc\7\32\2\2\u00cb\u00c9\3\2\2\2\u00cb") - buf.write("\u00ca\3\2\2\2\u00cc\'\3\2\2\2\u00cd\u00cf\7 \2\2\u00ce") - buf.write("\u00cd\3\2\2\2\u00ce\u00cf\3\2\2\2\u00cf\u00d0\3\2\2\2") - buf.write("\u00d0\u00d3\7\36\2\2\u00d1\u00d2\7\33\2\2\u00d2\u00d4") - buf.write("\5*\26\2\u00d3\u00d1\3\2\2\2\u00d3\u00d4\3\2\2\2\u00d4") - buf.write("\u00d6\3\2\2\2\u00d5\u00d7\7\16\2\2\u00d6\u00d5\3\2\2") - buf.write("\2\u00d6\u00d7\3\2\2\2\u00d7)\3\2\2\2\u00d8\u00db\7\34") - buf.write("\2\2\u00d9\u00db\7\35\2\2\u00da\u00d8\3\2\2\2\u00da\u00d9") - buf.write("\3\2\2\2\u00db+\3\2\2\2$\60\67>AGLOW\\`cfjqvy|\u0081\u0086") - buf.write("\u008c\u0095\u00a2\u00aa\u00af\u00b2\u00b7\u00ba\u00c2") - buf.write("\u00c7\u00cb\u00ce\u00d3\u00d6\u00da") + buf.write("\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\3\2") + buf.write("\3\2\7\2\63\n\2\f\2\16\2\66\13\2\3\3\3\3\7\3:\n\3\f\3") + buf.write("\16\3=\13\3\3\4\3\4\3\4\3\4\5\4C\n\4\3\5\5\5F\n\5\3\5") + buf.write("\7\5I\n\5\f\5\16\5L\13\5\3\5\3\5\3\5\3\5\5\5R\n\5\3\6") + buf.write("\3\6\3\6\5\6W\n\6\3\7\5\7Z\n\7\3\7\7\7]\n\7\f\7\16\7`") + buf.write("\13\7\3\7\3\7\3\7\3\7\7\7f\n\7\f\7\16\7i\13\7\3\7\3\7") + buf.write("\5\7m\n\7\3\b\3\b\5\bq\n\b\3\t\5\tt\n\t\3\t\7\tw\n\t\f") + buf.write("\t\16\tz\13\t\3\t\5\t}\n\t\3\t\3\t\5\t\u0081\n\t\3\t\3") + buf.write("\t\3\t\7\t\u0086\n\t\f\t\16\t\u0089\13\t\3\t\3\t\5\t\u008d") + buf.write("\n\t\3\n\5\n\u0090\n\n\3\n\7\n\u0093\n\n\f\n\16\n\u0096") + buf.write("\13\n\3\n\5\n\u0099\n\n\3\n\3\n\3\n\5\n\u009e\n\n\3\13") + buf.write("\3\13\3\13\5\13\u00a3\n\13\3\f\3\f\3\f\7\f\u00a8\n\f\f") + buf.write("\f\16\f\u00ab\13\f\3\f\3\f\3\r\3\r\3\r\5\r\u00b2\n\r\3") + buf.write("\16\3\16\3\16\3\16\5\16\u00b8\n\16\3\17\3\17\3\20\3\20") + buf.write("\3\20\3\20\3\20\5\20\u00c1\n\20\3\21\3\21\3\21\3\21\3") + buf.write("\21\3\22\3\22\3\22\3\22\3\22\3\23\5\23\u00ce\n\23\3\23") + buf.write("\7\23\u00d1\n\23\f\23\16\23\u00d4\13\23\3\23\3\23\3\23") + buf.write("\3\23\7\23\u00da\n\23\f\23\16\23\u00dd\13\23\3\23\3\23") + buf.write("\5\23\u00e1\n\23\3\24\5\24\u00e4\n\24\3\24\7\24\u00e7") + buf.write("\n\24\f\24\16\24\u00ea\13\24\3\24\3\24\3\24\5\24\u00ef") + buf.write("\n\24\3\25\5\25\u00f2\n\25\3\25\7\25\u00f5\n\25\f\25\16") + buf.write("\25\u00f8\13\25\3\25\3\25\3\25\3\25\7\25\u00fe\n\25\f") + buf.write("\25\16\25\u0101\13\25\3\25\3\25\5\25\u0105\n\25\3\26\3") + buf.write("\26\5\26\u0109\n\26\3\27\5\27\u010c\n\27\3\27\7\27\u010f") + buf.write("\n\27\f\27\16\27\u0112\13\27\3\27\3\27\3\27\5\27\u0117") + buf.write("\n\27\3\27\5\27\u011a\n\27\3\30\3\30\5\30\u011e\n\30\3") + buf.write("\30\2\2\31\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$") + buf.write("&(*,.\2\2\u013a\2\60\3\2\2\2\4\67\3\2\2\2\6>\3\2\2\2\b") + buf.write("E\3\2\2\2\nV\3\2\2\2\fY\3\2\2\2\16p\3\2\2\2\20s\3\2\2") + buf.write("\2\22\u008f\3\2\2\2\24\u009f\3\2\2\2\26\u00a4\3\2\2\2") + buf.write("\30\u00ae\3\2\2\2\32\u00b7\3\2\2\2\34\u00b9\3\2\2\2\36") + buf.write("\u00c0\3\2\2\2 \u00c2\3\2\2\2\"\u00c7\3\2\2\2$\u00cd\3") + buf.write("\2\2\2&\u00e3\3\2\2\2(\u00f1\3\2\2\2*\u0108\3\2\2\2,\u010b") + buf.write("\3\2\2\2.\u011d\3\2\2\2\60\64\5\4\3\2\61\63\5\n\6\2\62") + buf.write("\61\3\2\2\2\63\66\3\2\2\2\64\62\3\2\2\2\64\65\3\2\2\2") + buf.write("\65\3\3\2\2\2\66\64\3\2\2\2\67;\5\b\5\28:\5\6\4\298\3") + buf.write("\2\2\2:=\3\2\2\2;9\3\2\2\2;<\3\2\2\2<\5\3\2\2\2=;\3\2") + buf.write("\2\2>?\7\3\2\2?@\7\37\2\2@B\7 \2\2AC\7\4\2\2BA\3\2\2\2") + buf.write("BC\3\2\2\2C\7\3\2\2\2DF\7!\2\2ED\3\2\2\2EF\3\2\2\2FJ\3") + buf.write("\2\2\2GI\5\26\f\2HG\3\2\2\2IL\3\2\2\2JH\3\2\2\2JK\3\2") + buf.write("\2\2KM\3\2\2\2LJ\3\2\2\2MN\7\5\2\2NO\7\37\2\2OQ\7 \2\2") + buf.write("PR\7\4\2\2QP\3\2\2\2QR\3\2\2\2R\t\3\2\2\2SW\5\f\7\2TW") + buf.write("\5$\23\2UW\5(\25\2VS\3\2\2\2VT\3\2\2\2VU\3\2\2\2W\13\3") + buf.write("\2\2\2XZ\7!\2\2YX\3\2\2\2YZ\3\2\2\2Z^\3\2\2\2[]\5\26\f") + buf.write("\2\\[\3\2\2\2]`\3\2\2\2^\\\3\2\2\2^_\3\2\2\2_a\3\2\2\2") + buf.write("`^\3\2\2\2ab\7\6\2\2bc\7\37\2\2cg\7\7\2\2df\5\16\b\2e") + buf.write("d\3\2\2\2fi\3\2\2\2ge\3\2\2\2gh\3\2\2\2hj\3\2\2\2ig\3") + buf.write("\2\2\2jl\7\b\2\2km\7\4\2\2lk\3\2\2\2lm\3\2\2\2m\r\3\2") + buf.write("\2\2nq\5\20\t\2oq\5\22\n\2pn\3\2\2\2po\3\2\2\2q\17\3\2") + buf.write("\2\2rt\7!\2\2sr\3\2\2\2st\3\2\2\2tx\3\2\2\2uw\5\26\f\2") + buf.write("vu\3\2\2\2wz\3\2\2\2xv\3\2\2\2xy\3\2\2\2y|\3\2\2\2zx\3") + buf.write("\2\2\2{}\7\t\2\2|{\3\2\2\2|}\3\2\2\2}\u0080\3\2\2\2~\u0081") + buf.write("\5\32\16\2\177\u0081\7\n\2\2\u0080~\3\2\2\2\u0080\177") + buf.write("\3\2\2\2\u0081\u0082\3\2\2\2\u0082\u0083\7\37\2\2\u0083") + buf.write("\u0087\7\13\2\2\u0084\u0086\5\24\13\2\u0085\u0084\3\2") + buf.write("\2\2\u0086\u0089\3\2\2\2\u0087\u0085\3\2\2\2\u0087\u0088") + buf.write("\3\2\2\2\u0088\u008a\3\2\2\2\u0089\u0087\3\2\2\2\u008a") + buf.write("\u008c\7\f\2\2\u008b\u008d\7\4\2\2\u008c\u008b\3\2\2\2") + buf.write("\u008c\u008d\3\2\2\2\u008d\21\3\2\2\2\u008e\u0090\7!\2") + buf.write("\2\u008f\u008e\3\2\2\2\u008f\u0090\3\2\2\2\u0090\u0094") + buf.write("\3\2\2\2\u0091\u0093\5\26\f\2\u0092\u0091\3\2\2\2\u0093") + buf.write("\u0096\3\2\2\2\u0094\u0092\3\2\2\2\u0094\u0095\3\2\2\2") + buf.write("\u0095\u0098\3\2\2\2\u0096\u0094\3\2\2\2\u0097\u0099\7") + buf.write("\r\2\2\u0098\u0097\3\2\2\2\u0098\u0099\3\2\2\2\u0099\u009a") + buf.write("\3\2\2\2\u009a\u009b\5\32\16\2\u009b\u009d\7\37\2\2\u009c") + buf.write("\u009e\7\4\2\2\u009d\u009c\3\2\2\2\u009d\u009e\3\2\2\2") + buf.write("\u009e\23\3\2\2\2\u009f\u00a0\5\32\16\2\u00a0\u00a2\7") + buf.write("\37\2\2\u00a1\u00a3\7\16\2\2\u00a2\u00a1\3\2\2\2\u00a2") + buf.write("\u00a3\3\2\2\2\u00a3\25\3\2\2\2\u00a4\u00a5\7\36\2\2\u00a5") + buf.write("\u00a9\7\13\2\2\u00a6\u00a8\5\30\r\2\u00a7\u00a6\3\2\2") + buf.write("\2\u00a8\u00ab\3\2\2\2\u00a9\u00a7\3\2\2\2\u00a9\u00aa") + buf.write("\3\2\2\2\u00aa\u00ac\3\2\2\2\u00ab\u00a9\3\2\2\2\u00ac") + buf.write("\u00ad\7\f\2\2\u00ad\27\3\2\2\2\u00ae\u00b1\7\37\2\2\u00af") + buf.write("\u00b0\7\17\2\2\u00b0\u00b2\7\37\2\2\u00b1\u00af\3\2\2") + buf.write("\2\u00b1\u00b2\3\2\2\2\u00b2\31\3\2\2\2\u00b3\u00b8\5") + buf.write("\36\20\2\u00b4\u00b8\5\34\17\2\u00b5\u00b8\5 \21\2\u00b6") + buf.write("\u00b8\5\"\22\2\u00b7\u00b3\3\2\2\2\u00b7\u00b4\3\2\2") + buf.write("\2\u00b7\u00b5\3\2\2\2\u00b7\u00b6\3\2\2\2\u00b8\33\3") + buf.write("\2\2\2\u00b9\u00ba\7\37\2\2\u00ba\35\3\2\2\2\u00bb\u00c1") + buf.write("\7\20\2\2\u00bc\u00c1\7\21\2\2\u00bd\u00c1\7\22\2\2\u00be") + buf.write("\u00c1\7\23\2\2\u00bf\u00c1\7\24\2\2\u00c0\u00bb\3\2\2") + buf.write("\2\u00c0\u00bc\3\2\2\2\u00c0\u00bd\3\2\2\2\u00c0\u00be") + buf.write("\3\2\2\2\u00c0\u00bf\3\2\2\2\u00c1\37\3\2\2\2\u00c2\u00c3") + buf.write("\7\25\2\2\u00c3\u00c4\7\26\2\2\u00c4\u00c5\5\32\16\2\u00c5") + buf.write("\u00c6\7\27\2\2\u00c6!\3\2\2\2\u00c7\u00c8\7\30\2\2\u00c8") + buf.write("\u00c9\7\26\2\2\u00c9\u00ca\5\32\16\2\u00ca\u00cb\7\27") + buf.write("\2\2\u00cb#\3\2\2\2\u00cc\u00ce\7!\2\2\u00cd\u00cc\3\2") + buf.write("\2\2\u00cd\u00ce\3\2\2\2\u00ce\u00d2\3\2\2\2\u00cf\u00d1") + buf.write("\5\26\f\2\u00d0\u00cf\3\2\2\2\u00d1\u00d4\3\2\2\2\u00d2") + buf.write("\u00d0\3\2\2\2\u00d2\u00d3\3\2\2\2\u00d3\u00d5\3\2\2\2") + buf.write("\u00d4\u00d2\3\2\2\2\u00d5\u00d6\7\31\2\2\u00d6\u00d7") + buf.write("\7\37\2\2\u00d7\u00db\7\7\2\2\u00d8\u00da\5&\24\2\u00d9") + buf.write("\u00d8\3\2\2\2\u00da\u00dd\3\2\2\2\u00db\u00d9\3\2\2\2") + buf.write("\u00db\u00dc\3\2\2\2\u00dc\u00de\3\2\2\2\u00dd\u00db\3") + buf.write("\2\2\2\u00de\u00e0\7\b\2\2\u00df\u00e1\7\4\2\2\u00e0\u00df") + buf.write("\3\2\2\2\u00e0\u00e1\3\2\2\2\u00e1%\3\2\2\2\u00e2\u00e4") + buf.write("\7!\2\2\u00e3\u00e2\3\2\2\2\u00e3\u00e4\3\2\2\2\u00e4") + buf.write("\u00e8\3\2\2\2\u00e5\u00e7\5\26\f\2\u00e6\u00e5\3\2\2") + buf.write("\2\u00e7\u00ea\3\2\2\2\u00e8\u00e6\3\2\2\2\u00e8\u00e9") + buf.write("\3\2\2\2\u00e9\u00eb\3\2\2\2\u00ea\u00e8\3\2\2\2\u00eb") + buf.write("\u00ec\5\32\16\2\u00ec\u00ee\7\37\2\2\u00ed\u00ef\7\4") + buf.write("\2\2\u00ee\u00ed\3\2\2\2\u00ee\u00ef\3\2\2\2\u00ef\'\3") + buf.write("\2\2\2\u00f0\u00f2\7!\2\2\u00f1\u00f0\3\2\2\2\u00f1\u00f2") + buf.write("\3\2\2\2\u00f2\u00f6\3\2\2\2\u00f3\u00f5\5\26\f\2\u00f4") + buf.write("\u00f3\3\2\2\2\u00f5\u00f8\3\2\2\2\u00f6\u00f4\3\2\2\2") + buf.write("\u00f6\u00f7\3\2\2\2\u00f7\u00f9\3\2\2\2\u00f8\u00f6\3") + buf.write("\2\2\2\u00f9\u00fa\5*\26\2\u00fa\u00fb\7\37\2\2\u00fb") + buf.write("\u00ff\7\7\2\2\u00fc\u00fe\5,\27\2\u00fd\u00fc\3\2\2\2") + buf.write("\u00fe\u0101\3\2\2\2\u00ff\u00fd\3\2\2\2\u00ff\u0100\3") + buf.write("\2\2\2\u0100\u0102\3\2\2\2\u0101\u00ff\3\2\2\2\u0102\u0104") + buf.write("\7\b\2\2\u0103\u0105\7\4\2\2\u0104\u0103\3\2\2\2\u0104") + buf.write("\u0105\3\2\2\2\u0105)\3\2\2\2\u0106\u0109\7\32\2\2\u0107") + buf.write("\u0109\7\33\2\2\u0108\u0106\3\2\2\2\u0108\u0107\3\2\2") + buf.write("\2\u0109+\3\2\2\2\u010a\u010c\7!\2\2\u010b\u010a\3\2\2") + buf.write("\2\u010b\u010c\3\2\2\2\u010c\u0110\3\2\2\2\u010d\u010f") + buf.write("\5\26\f\2\u010e\u010d\3\2\2\2\u010f\u0112\3\2\2\2\u0110") + buf.write("\u010e\3\2\2\2\u0110\u0111\3\2\2\2\u0111\u0113\3\2\2\2") + buf.write("\u0112\u0110\3\2\2\2\u0113\u0116\7\37\2\2\u0114\u0115") + buf.write("\7\17\2\2\u0115\u0117\5.\30\2\u0116\u0114\3\2\2\2\u0116") + buf.write("\u0117\3\2\2\2\u0117\u0119\3\2\2\2\u0118\u011a\7\16\2") + buf.write("\2\u0119\u0118\3\2\2\2\u0119\u011a\3\2\2\2\u011a-\3\2") + buf.write("\2\2\u011b\u011e\7\34\2\2\u011c\u011e\7\35\2\2\u011d\u011b") + buf.write("\3\2\2\2\u011d\u011c\3\2\2\2\u011e/\3\2\2\2.\64;BEJQV") + buf.write("Y^glpsx|\u0080\u0087\u008c\u008f\u0094\u0098\u009d\u00a2") + buf.write("\u00a9\u00b1\u00b7\u00c0\u00cd\u00d2\u00db\u00e0\u00e3") + buf.write("\u00e8\u00ee\u00f1\u00f6\u00ff\u0104\u0108\u010b\u0110") + buf.write("\u0116\u0119\u011d") return buf.getvalue() @@ -113,9 +151,9 @@ class TParser ( Parser ): literalNames = [ "<INVALID>", "'import'", "';'", "'module'", "'interface'", "'{'", "'}'", "'event'", "'void'", "'('", "')'", "'readonly'", - "','", "'bool'", "'int'", "'real'", "'string'", "'var'", - "'list'", "'<'", "'>'", "'model'", "'struct'", "'enum'", - "'flag'", "'='" ] + "','", "'='", "'bool'", "'int'", "'real'", "'string'", + "'var'", "'list'", "'<'", "'>'", "'model'", "'struct'", + "'enum'", "'flag'" ] symbolicNames = [ "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", @@ -124,8 +162,8 @@ class TParser ( Parser ): "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", "<INVALID>", "INTCONSTANT", "HEXCONSTANT", - "IDENTIFIER", "VERSION", "DOCCOMMENT", "WHITESPACE", - "COMMENT", "MULTICOMM" ] + "TAGIDENTIFIER", "IDENTIFIER", "VERSION", "DOCCOMMENT", + "WHITESPACE", "COMMENT", "MULTICOMM" ] RULE_documentSymbol = 0 RULE_headerSymbol = 1 @@ -137,24 +175,26 @@ class TParser ( Parser ): RULE_operationSymbol = 7 RULE_propertySymbol = 8 RULE_operationParameterSymbol = 9 - RULE_typeSymbol = 10 - RULE_complexTypeSymbol = 11 - RULE_primitiveTypeSymbol = 12 - RULE_listTypeSymbol = 13 - RULE_modelTypeSymbol = 14 - RULE_structSymbol = 15 - RULE_structFieldSymbol = 16 - RULE_enumSymbol = 17 - RULE_enumTypeSymbol = 18 - RULE_enumMemberSymbol = 19 - RULE_intSymbol = 20 + RULE_tagSymbol = 10 + RULE_tagAttributeSymbol = 11 + RULE_typeSymbol = 12 + RULE_complexTypeSymbol = 13 + RULE_primitiveTypeSymbol = 14 + RULE_listTypeSymbol = 15 + RULE_modelTypeSymbol = 16 + RULE_structSymbol = 17 + RULE_structFieldSymbol = 18 + RULE_enumSymbol = 19 + RULE_enumTypeSymbol = 20 + RULE_enumMemberSymbol = 21 + RULE_intSymbol = 22 ruleNames = [ "documentSymbol", "headerSymbol", "importSymbol", "moduleSymbol", "definitionSymbol", "interfaceSymbol", "interfaceMemberSymbol", "operationSymbol", "propertySymbol", "operationParameterSymbol", - "typeSymbol", "complexTypeSymbol", "primitiveTypeSymbol", - "listTypeSymbol", "modelTypeSymbol", "structSymbol", - "structFieldSymbol", "enumSymbol", "enumTypeSymbol", + "tagSymbol", "tagAttributeSymbol", "typeSymbol", "complexTypeSymbol", + "primitiveTypeSymbol", "listTypeSymbol", "modelTypeSymbol", + "structSymbol", "structFieldSymbol", "enumSymbol", "enumTypeSymbol", "enumMemberSymbol", "intSymbol" ] EOF = Token.EOF @@ -185,12 +225,13 @@ class TParser ( Parser ): T__24=25 INTCONSTANT=26 HEXCONSTANT=27 - IDENTIFIER=28 - VERSION=29 - DOCCOMMENT=30 - WHITESPACE=31 - COMMENT=32 - MULTICOMM=33 + TAGIDENTIFIER=28 + IDENTIFIER=29 + VERSION=30 + DOCCOMMENT=31 + WHITESPACE=32 + COMMENT=33 + MULTICOMM=34 def __init__(self, input:TokenStream): super().__init__(input) @@ -244,15 +285,15 @@ class TParser ( Parser ): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 42 - self.headerSymbol() self.state = 46 + self.headerSymbol() + self.state = 50 self._errHandler.sync(self) _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__3) | (1 << TParser.T__21) | (1 << TParser.T__22) | (1 << TParser.T__23) | (1 << TParser.DOCCOMMENT))) != 0): - self.state = 43 + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__3) | (1 << TParser.T__22) | (1 << TParser.T__23) | (1 << TParser.T__24) | (1 << TParser.TAGIDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0): + self.state = 47 self.definitionSymbol() - self.state = 48 + self.state = 52 self._errHandler.sync(self) _la = self._input.LA(1) @@ -308,15 +349,15 @@ class TParser ( Parser ): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 49 - self.moduleSymbol() self.state = 53 + self.moduleSymbol() + self.state = 57 self._errHandler.sync(self) _la = self._input.LA(1) while _la==TParser.T__0: - self.state = 50 + self.state = 54 self.importSymbol() - self.state = 55 + self.state = 59 self._errHandler.sync(self) _la = self._input.LA(1) @@ -369,16 +410,16 @@ class TParser ( Parser ): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 56 + self.state = 60 self.match(TParser.T__0) - self.state = 57 + self.state = 61 localctx.name = self.match(TParser.IDENTIFIER) - self.state = 58 + self.state = 62 localctx.version = self.match(TParser.VERSION) - self.state = 60 + self.state = 64 _la = self._input.LA(1) if _la==TParser.T__1: - self.state = 59 + self.state = 63 self.match(TParser.T__1) @@ -405,6 +446,13 @@ class TParser ( Parser ): def VERSION(self): return self.getToken(TParser.VERSION, 0) + def tagSymbol(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(TParser.TagSymbolContext) + else: + return self.getTypedRuleContext(TParser.TagSymbolContext,i) + + def DOCCOMMENT(self): return self.getToken(TParser.DOCCOMMENT, 0) @@ -435,23 +483,33 @@ class TParser ( Parser ): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 63 + self.state = 67 _la = self._input.LA(1) if _la==TParser.DOCCOMMENT: - self.state = 62 + self.state = 66 localctx.comment = self.match(TParser.DOCCOMMENT) - self.state = 65 + self.state = 72 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==TParser.TAGIDENTIFIER: + self.state = 69 + self.tagSymbol() + self.state = 74 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 75 self.match(TParser.T__2) - self.state = 66 + self.state = 76 localctx.name = self.match(TParser.IDENTIFIER) - self.state = 67 + self.state = 77 localctx.version = self.match(TParser.VERSION) - self.state = 69 + self.state = 79 _la = self._input.LA(1) if _la==TParser.T__1: - self.state = 68 + self.state = 78 self.match(TParser.T__1) @@ -506,24 +564,24 @@ class TParser ( Parser ): localctx = TParser.DefinitionSymbolContext(self, self._ctx, self.state) self.enterRule(localctx, 8, self.RULE_definitionSymbol) try: - self.state = 74 + self.state = 84 self._errHandler.sync(self); - la_ = self._interp.adaptivePredict(self._input,5,self._ctx) + la_ = self._interp.adaptivePredict(self._input,6,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 71 + self.state = 81 self.interfaceSymbol() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 72 + self.state = 82 self.structSymbol() pass elif la_ == 3: self.enterOuterAlt(localctx, 3) - self.state = 73 + self.state = 83 self.enumSymbol() pass @@ -547,6 +605,13 @@ class TParser ( Parser ): def IDENTIFIER(self): return self.getToken(TParser.IDENTIFIER, 0) + def tagSymbol(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(TParser.TagSymbolContext) + else: + return self.getTypedRuleContext(TParser.TagSymbolContext,i) + + def interfaceMemberSymbol(self, i:int=None): if i is None: return self.getTypedRuleContexts(TParser.InterfaceMemberSymbolContext) @@ -584,35 +649,45 @@ class TParser ( Parser ): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 77 + self.state = 87 _la = self._input.LA(1) if _la==TParser.DOCCOMMENT: - self.state = 76 + self.state = 86 localctx.comment = self.match(TParser.DOCCOMMENT) - self.state = 79 + self.state = 92 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==TParser.TAGIDENTIFIER: + self.state = 89 + self.tagSymbol() + self.state = 94 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 95 self.match(TParser.T__3) - self.state = 80 + self.state = 96 localctx.name = self.match(TParser.IDENTIFIER) - self.state = 81 + self.state = 97 self.match(TParser.T__4) - self.state = 85 + self.state = 101 self._errHandler.sync(self) _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__6) | (1 << TParser.T__7) | (1 << TParser.T__10) | (1 << TParser.T__12) | (1 << TParser.T__13) | (1 << TParser.T__14) | (1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__20) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0): - self.state = 82 + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__6) | (1 << TParser.T__7) | (1 << TParser.T__10) | (1 << TParser.T__13) | (1 << TParser.T__14) | (1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__18) | (1 << TParser.T__21) | (1 << TParser.TAGIDENTIFIER) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0): + self.state = 98 self.interfaceMemberSymbol() - self.state = 87 + self.state = 103 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 88 + self.state = 104 self.match(TParser.T__5) - self.state = 90 + self.state = 106 _la = self._input.LA(1) if _la==TParser.T__1: - self.state = 89 + self.state = 105 self.match(TParser.T__1) @@ -663,18 +738,18 @@ class TParser ( Parser ): localctx = TParser.InterfaceMemberSymbolContext(self, self._ctx, self.state) self.enterRule(localctx, 12, self.RULE_interfaceMemberSymbol) try: - self.state = 94 + self.state = 110 self._errHandler.sync(self); - la_ = self._interp.adaptivePredict(self._input,9,self._ctx) + la_ = self._interp.adaptivePredict(self._input,11,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 92 + self.state = 108 self.operationSymbol() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 93 + self.state = 109 self.propertySymbol() pass @@ -703,6 +778,13 @@ class TParser ( Parser ): return self.getTypedRuleContext(TParser.TypeSymbolContext,0) + def tagSymbol(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(TParser.TagSymbolContext) + else: + return self.getTypedRuleContext(TParser.TagSymbolContext,i) + + def operationParameterSymbol(self, i:int=None): if i is None: return self.getTypedRuleContexts(TParser.OperationParameterSymbolContext) @@ -740,53 +822,63 @@ class TParser ( Parser ): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 97 + self.state = 113 _la = self._input.LA(1) if _la==TParser.DOCCOMMENT: - self.state = 96 + self.state = 112 localctx.comment = self.match(TParser.DOCCOMMENT) - self.state = 100 + self.state = 118 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==TParser.TAGIDENTIFIER: + self.state = 115 + self.tagSymbol() + self.state = 120 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 122 _la = self._input.LA(1) if _la==TParser.T__6: - self.state = 99 + self.state = 121 localctx.isEvent = self.match(TParser.T__6) - self.state = 104 + self.state = 126 token = self._input.LA(1) - if token in [TParser.T__12, TParser.T__13, TParser.T__14, TParser.T__15, TParser.T__16, TParser.T__17, TParser.T__20, TParser.IDENTIFIER]: - self.state = 102 + if token in [TParser.T__13, TParser.T__14, TParser.T__15, TParser.T__16, TParser.T__17, TParser.T__18, TParser.T__21, TParser.IDENTIFIER]: + self.state = 124 self.typeSymbol() elif token in [TParser.T__7]: - self.state = 103 + self.state = 125 self.match(TParser.T__7) else: raise NoViableAltException(self) - self.state = 106 + self.state = 128 localctx.name = self.match(TParser.IDENTIFIER) - self.state = 107 + self.state = 129 self.match(TParser.T__8) - self.state = 111 + self.state = 133 self._errHandler.sync(self) _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__12) | (1 << TParser.T__13) | (1 << TParser.T__14) | (1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__20) | (1 << TParser.IDENTIFIER))) != 0): - self.state = 108 + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__13) | (1 << TParser.T__14) | (1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__18) | (1 << TParser.T__21) | (1 << TParser.IDENTIFIER))) != 0): + self.state = 130 self.operationParameterSymbol() - self.state = 113 + self.state = 135 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 114 + self.state = 136 self.match(TParser.T__9) - self.state = 116 + self.state = 138 _la = self._input.LA(1) if _la==TParser.T__1: - self.state = 115 + self.state = 137 self.match(TParser.T__1) @@ -814,6 +906,13 @@ class TParser ( Parser ): def IDENTIFIER(self): return self.getToken(TParser.IDENTIFIER, 0) + def tagSymbol(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(TParser.TagSymbolContext) + else: + return self.getTypedRuleContext(TParser.TagSymbolContext,i) + + def DOCCOMMENT(self): return self.getToken(TParser.DOCCOMMENT, 0) @@ -844,28 +943,38 @@ class TParser ( Parser ): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 119 + self.state = 141 _la = self._input.LA(1) if _la==TParser.DOCCOMMENT: - self.state = 118 + self.state = 140 localctx.comment = self.match(TParser.DOCCOMMENT) - self.state = 122 + self.state = 146 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==TParser.TAGIDENTIFIER: + self.state = 143 + self.tagSymbol() + self.state = 148 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 150 _la = self._input.LA(1) if _la==TParser.T__10: - self.state = 121 + self.state = 149 localctx.isReadOnly = self.match(TParser.T__10) - self.state = 124 + self.state = 152 self.typeSymbol() - self.state = 125 + self.state = 153 localctx.name = self.match(TParser.IDENTIFIER) - self.state = 127 + self.state = 155 _la = self._input.LA(1) if _la==TParser.T__1: - self.state = 126 + self.state = 154 self.match(TParser.T__1) @@ -918,14 +1027,14 @@ class TParser ( Parser ): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 129 + self.state = 157 self.typeSymbol() - self.state = 130 + self.state = 158 localctx.name = self.match(TParser.IDENTIFIER) - self.state = 132 + self.state = 160 _la = self._input.LA(1) if _la==TParser.T__11: - self.state = 131 + self.state = 159 self.match(TParser.T__11) @@ -937,6 +1046,134 @@ class TParser ( Parser ): self.exitRule() return localctx + class TagSymbolContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + self.name = None # Token + + def TAGIDENTIFIER(self): + return self.getToken(TParser.TAGIDENTIFIER, 0) + + def tagAttributeSymbol(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(TParser.TagAttributeSymbolContext) + else: + return self.getTypedRuleContext(TParser.TagAttributeSymbolContext,i) + + + def getRuleIndex(self): + return TParser.RULE_tagSymbol + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterTagSymbol" ): + listener.enterTagSymbol(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitTagSymbol" ): + listener.exitTagSymbol(self) + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitTagSymbol" ): + return visitor.visitTagSymbol(self) + else: + return visitor.visitChildren(self) + + + + + def tagSymbol(self): + + localctx = TParser.TagSymbolContext(self, self._ctx, self.state) + self.enterRule(localctx, 20, self.RULE_tagSymbol) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 162 + localctx.name = self.match(TParser.TAGIDENTIFIER) + self.state = 163 + self.match(TParser.T__8) + self.state = 167 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==TParser.IDENTIFIER: + self.state = 164 + self.tagAttributeSymbol() + self.state = 169 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 170 + self.match(TParser.T__9) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class TagAttributeSymbolContext(ParserRuleContext): + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + self.name = None # Token + self.value = None # Token + + def IDENTIFIER(self, i:int=None): + if i is None: + return self.getTokens(TParser.IDENTIFIER) + else: + return self.getToken(TParser.IDENTIFIER, i) + + def getRuleIndex(self): + return TParser.RULE_tagAttributeSymbol + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterTagAttributeSymbol" ): + listener.enterTagAttributeSymbol(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitTagAttributeSymbol" ): + listener.exitTagAttributeSymbol(self) + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitTagAttributeSymbol" ): + return visitor.visitTagAttributeSymbol(self) + else: + return visitor.visitChildren(self) + + + + + def tagAttributeSymbol(self): + + localctx = TParser.TagAttributeSymbolContext(self, self._ctx, self.state) + self.enterRule(localctx, 22, self.RULE_tagAttributeSymbol) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 172 + localctx.name = self.match(TParser.IDENTIFIER) + self.state = 175 + _la = self._input.LA(1) + if _la==TParser.T__12: + self.state = 173 + self.match(TParser.T__12) + self.state = 174 + localctx.value = self.match(TParser.IDENTIFIER) + + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + class TypeSymbolContext(ParserRuleContext): def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): @@ -982,28 +1219,28 @@ class TParser ( Parser ): def typeSymbol(self): localctx = TParser.TypeSymbolContext(self, self._ctx, self.state) - self.enterRule(localctx, 20, self.RULE_typeSymbol) + self.enterRule(localctx, 24, self.RULE_typeSymbol) try: - self.state = 138 + self.state = 181 token = self._input.LA(1) - if token in [TParser.T__12, TParser.T__13, TParser.T__14, TParser.T__15, TParser.T__16]: + if token in [TParser.T__13, TParser.T__14, TParser.T__15, TParser.T__16, TParser.T__17]: self.enterOuterAlt(localctx, 1) - self.state = 134 + self.state = 177 self.primitiveTypeSymbol() elif token in [TParser.IDENTIFIER]: self.enterOuterAlt(localctx, 2) - self.state = 135 + self.state = 178 self.complexTypeSymbol() - elif token in [TParser.T__17]: + elif token in [TParser.T__18]: self.enterOuterAlt(localctx, 3) - self.state = 136 + self.state = 179 self.listTypeSymbol() - elif token in [TParser.T__20]: + elif token in [TParser.T__21]: self.enterOuterAlt(localctx, 4) - self.state = 137 + self.state = 180 self.modelTypeSymbol() else: @@ -1050,10 +1287,10 @@ class TParser ( Parser ): def complexTypeSymbol(self): localctx = TParser.ComplexTypeSymbolContext(self, self._ctx, self.state) - self.enterRule(localctx, 22, self.RULE_complexTypeSymbol) + self.enterRule(localctx, 26, self.RULE_complexTypeSymbol) try: self.enterOuterAlt(localctx, 1) - self.state = 140 + self.state = 183 localctx.name = self.match(TParser.IDENTIFIER) except RecognitionException as re: localctx.exception = re @@ -1094,35 +1331,35 @@ class TParser ( Parser ): def primitiveTypeSymbol(self): localctx = TParser.PrimitiveTypeSymbolContext(self, self._ctx, self.state) - self.enterRule(localctx, 24, self.RULE_primitiveTypeSymbol) + self.enterRule(localctx, 28, self.RULE_primitiveTypeSymbol) try: - self.state = 147 + self.state = 190 token = self._input.LA(1) - if token in [TParser.T__12]: + if token in [TParser.T__13]: self.enterOuterAlt(localctx, 1) - self.state = 142 - localctx.name = self.match(TParser.T__12) - - elif token in [TParser.T__13]: - self.enterOuterAlt(localctx, 2) - self.state = 143 + self.state = 185 localctx.name = self.match(TParser.T__13) elif token in [TParser.T__14]: - self.enterOuterAlt(localctx, 3) - self.state = 144 + self.enterOuterAlt(localctx, 2) + self.state = 186 localctx.name = self.match(TParser.T__14) elif token in [TParser.T__15]: - self.enterOuterAlt(localctx, 4) - self.state = 145 + self.enterOuterAlt(localctx, 3) + self.state = 187 localctx.name = self.match(TParser.T__15) elif token in [TParser.T__16]: - self.enterOuterAlt(localctx, 5) - self.state = 146 + self.enterOuterAlt(localctx, 4) + self.state = 188 localctx.name = self.match(TParser.T__16) + elif token in [TParser.T__17]: + self.enterOuterAlt(localctx, 5) + self.state = 189 + localctx.name = self.match(TParser.T__17) + else: raise NoViableAltException(self) @@ -1168,17 +1405,17 @@ class TParser ( Parser ): def listTypeSymbol(self): localctx = TParser.ListTypeSymbolContext(self, self._ctx, self.state) - self.enterRule(localctx, 26, self.RULE_listTypeSymbol) + self.enterRule(localctx, 30, self.RULE_listTypeSymbol) try: self.enterOuterAlt(localctx, 1) - self.state = 149 - self.match(TParser.T__17) - self.state = 150 + self.state = 192 self.match(TParser.T__18) - self.state = 151 - localctx.valueType = self.typeSymbol() - self.state = 152 + self.state = 193 self.match(TParser.T__19) + self.state = 194 + localctx.valueType = self.typeSymbol() + self.state = 195 + self.match(TParser.T__20) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -1221,17 +1458,17 @@ class TParser ( Parser ): def modelTypeSymbol(self): localctx = TParser.ModelTypeSymbolContext(self, self._ctx, self.state) - self.enterRule(localctx, 28, self.RULE_modelTypeSymbol) + self.enterRule(localctx, 32, self.RULE_modelTypeSymbol) try: self.enterOuterAlt(localctx, 1) - self.state = 154 - self.match(TParser.T__20) - self.state = 155 - self.match(TParser.T__18) - self.state = 156 - localctx.valueType = self.typeSymbol() - self.state = 157 + self.state = 197 + self.match(TParser.T__21) + self.state = 198 self.match(TParser.T__19) + self.state = 199 + localctx.valueType = self.typeSymbol() + self.state = 200 + self.match(TParser.T__20) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -1251,6 +1488,13 @@ class TParser ( Parser ): def IDENTIFIER(self): return self.getToken(TParser.IDENTIFIER, 0) + def tagSymbol(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(TParser.TagSymbolContext) + else: + return self.getTypedRuleContext(TParser.TagSymbolContext,i) + + def structFieldSymbol(self, i:int=None): if i is None: return self.getTypedRuleContexts(TParser.StructFieldSymbolContext) @@ -1284,39 +1528,49 @@ class TParser ( Parser ): def structSymbol(self): localctx = TParser.StructSymbolContext(self, self._ctx, self.state) - self.enterRule(localctx, 30, self.RULE_structSymbol) + self.enterRule(localctx, 34, self.RULE_structSymbol) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 160 + self.state = 203 _la = self._input.LA(1) if _la==TParser.DOCCOMMENT: - self.state = 159 + self.state = 202 localctx.comment = self.match(TParser.DOCCOMMENT) - self.state = 162 - self.match(TParser.T__21) - self.state = 163 + self.state = 208 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==TParser.TAGIDENTIFIER: + self.state = 205 + self.tagSymbol() + self.state = 210 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 211 + self.match(TParser.T__22) + self.state = 212 localctx.name = self.match(TParser.IDENTIFIER) - self.state = 164 + self.state = 213 self.match(TParser.T__4) - self.state = 168 + self.state = 217 self._errHandler.sync(self) _la = self._input.LA(1) - while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__12) | (1 << TParser.T__13) | (1 << TParser.T__14) | (1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__20) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0): - self.state = 165 + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.T__13) | (1 << TParser.T__14) | (1 << TParser.T__15) | (1 << TParser.T__16) | (1 << TParser.T__17) | (1 << TParser.T__18) | (1 << TParser.T__21) | (1 << TParser.TAGIDENTIFIER) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0): + self.state = 214 self.structFieldSymbol() - self.state = 170 + self.state = 219 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 171 + self.state = 220 self.match(TParser.T__5) - self.state = 173 + self.state = 222 _la = self._input.LA(1) if _la==TParser.T__1: - self.state = 172 + self.state = 221 self.match(TParser.T__1) @@ -1343,6 +1597,13 @@ class TParser ( Parser ): def IDENTIFIER(self): return self.getToken(TParser.IDENTIFIER, 0) + def tagSymbol(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(TParser.TagSymbolContext) + else: + return self.getTypedRuleContext(TParser.TagSymbolContext,i) + + def DOCCOMMENT(self): return self.getToken(TParser.DOCCOMMENT, 0) @@ -1369,25 +1630,35 @@ class TParser ( Parser ): def structFieldSymbol(self): localctx = TParser.StructFieldSymbolContext(self, self._ctx, self.state) - self.enterRule(localctx, 32, self.RULE_structFieldSymbol) + self.enterRule(localctx, 36, self.RULE_structFieldSymbol) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 176 + self.state = 225 _la = self._input.LA(1) if _la==TParser.DOCCOMMENT: - self.state = 175 + self.state = 224 localctx.comment = self.match(TParser.DOCCOMMENT) - self.state = 178 + self.state = 230 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==TParser.TAGIDENTIFIER: + self.state = 227 + self.tagSymbol() + self.state = 232 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 233 self.typeSymbol() - self.state = 179 + self.state = 234 localctx.name = self.match(TParser.IDENTIFIER) - self.state = 181 + self.state = 236 _la = self._input.LA(1) if _la==TParser.T__1: - self.state = 180 + self.state = 235 self.match(TParser.T__1) @@ -1414,6 +1685,13 @@ class TParser ( Parser ): def IDENTIFIER(self): return self.getToken(TParser.IDENTIFIER, 0) + def tagSymbol(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(TParser.TagSymbolContext) + else: + return self.getTypedRuleContext(TParser.TagSymbolContext,i) + + def enumMemberSymbol(self, i:int=None): if i is None: return self.getTypedRuleContexts(TParser.EnumMemberSymbolContext) @@ -1447,39 +1725,49 @@ class TParser ( Parser ): def enumSymbol(self): localctx = TParser.EnumSymbolContext(self, self._ctx, self.state) - self.enterRule(localctx, 34, self.RULE_enumSymbol) + self.enterRule(localctx, 38, self.RULE_enumSymbol) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 184 + self.state = 239 _la = self._input.LA(1) if _la==TParser.DOCCOMMENT: - self.state = 183 + self.state = 238 localctx.comment = self.match(TParser.DOCCOMMENT) - self.state = 186 + self.state = 244 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==TParser.TAGIDENTIFIER: + self.state = 241 + self.tagSymbol() + self.state = 246 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 247 self.enumTypeSymbol() - self.state = 187 + self.state = 248 localctx.name = self.match(TParser.IDENTIFIER) - self.state = 188 + self.state = 249 self.match(TParser.T__4) - self.state = 192 + self.state = 253 self._errHandler.sync(self) _la = self._input.LA(1) - while _la==TParser.IDENTIFIER or _la==TParser.DOCCOMMENT: - self.state = 189 + while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << TParser.TAGIDENTIFIER) | (1 << TParser.IDENTIFIER) | (1 << TParser.DOCCOMMENT))) != 0): + self.state = 250 self.enumMemberSymbol() - self.state = 194 + self.state = 255 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 195 + self.state = 256 self.match(TParser.T__5) - self.state = 197 + self.state = 258 _la = self._input.LA(1) if _la==TParser.T__1: - self.state = 196 + self.state = 257 self.match(TParser.T__1) @@ -1523,19 +1811,19 @@ class TParser ( Parser ): def enumTypeSymbol(self): localctx = TParser.EnumTypeSymbolContext(self, self._ctx, self.state) - self.enterRule(localctx, 36, self.RULE_enumTypeSymbol) + self.enterRule(localctx, 40, self.RULE_enumTypeSymbol) try: - self.state = 201 + self.state = 262 token = self._input.LA(1) - if token in [TParser.T__22]: + if token in [TParser.T__23]: self.enterOuterAlt(localctx, 1) - self.state = 199 - localctx.isEnum = self.match(TParser.T__22) + self.state = 260 + localctx.isEnum = self.match(TParser.T__23) - elif token in [TParser.T__23]: + elif token in [TParser.T__24]: self.enterOuterAlt(localctx, 2) - self.state = 200 - localctx.isFlag = self.match(TParser.T__23) + self.state = 261 + localctx.isFlag = self.match(TParser.T__24) else: raise NoViableAltException(self) @@ -1559,6 +1847,13 @@ class TParser ( Parser ): def IDENTIFIER(self): return self.getToken(TParser.IDENTIFIER, 0) + def tagSymbol(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(TParser.TagSymbolContext) + else: + return self.getTypedRuleContext(TParser.TagSymbolContext,i) + + def intSymbol(self): return self.getTypedRuleContext(TParser.IntSymbolContext,0) @@ -1589,32 +1884,42 @@ class TParser ( Parser ): def enumMemberSymbol(self): localctx = TParser.EnumMemberSymbolContext(self, self._ctx, self.state) - self.enterRule(localctx, 38, self.RULE_enumMemberSymbol) + self.enterRule(localctx, 42, self.RULE_enumMemberSymbol) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 204 + self.state = 265 _la = self._input.LA(1) if _la==TParser.DOCCOMMENT: - self.state = 203 + self.state = 264 localctx.comment = self.match(TParser.DOCCOMMENT) - self.state = 206 + self.state = 270 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la==TParser.TAGIDENTIFIER: + self.state = 267 + self.tagSymbol() + self.state = 272 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 273 localctx.name = self.match(TParser.IDENTIFIER) - self.state = 209 + self.state = 276 _la = self._input.LA(1) - if _la==TParser.T__24: - self.state = 207 - self.match(TParser.T__24) - self.state = 208 + if _la==TParser.T__12: + self.state = 274 + self.match(TParser.T__12) + self.state = 275 self.intSymbol() - self.state = 212 + self.state = 279 _la = self._input.LA(1) if _la==TParser.T__11: - self.state = 211 + self.state = 278 self.match(TParser.T__11) @@ -1662,18 +1967,18 @@ class TParser ( Parser ): def intSymbol(self): localctx = TParser.IntSymbolContext(self, self._ctx, self.state) - self.enterRule(localctx, 40, self.RULE_intSymbol) + self.enterRule(localctx, 44, self.RULE_intSymbol) try: - self.state = 216 + self.state = 283 token = self._input.LA(1) if token in [TParser.INTCONSTANT]: self.enterOuterAlt(localctx, 1) - self.state = 214 + self.state = 281 localctx.value = self.match(TParser.INTCONSTANT) elif token in [TParser.HEXCONSTANT]: self.enterOuterAlt(localctx, 2) - self.state = 215 + self.state = 282 localctx.value = self.match(TParser.HEXCONSTANT) else: diff --git a/qface/idl/parser/TVisitor.py b/qface/idl/parser/TVisitor.py index dee7f69..adafdea 100644 --- a/qface/idl/parser/TVisitor.py +++ b/qface/idl/parser/TVisitor.py @@ -59,6 +59,16 @@ class TVisitor(ParseTreeVisitor): return self.visitChildren(ctx) + # Visit a parse tree produced by TParser#tagSymbol. + def visitTagSymbol(self, ctx:TParser.TagSymbolContext): + return self.visitChildren(ctx) + + + # Visit a parse tree produced by TParser#tagAttributeSymbol. + def visitTagAttributeSymbol(self, ctx:TParser.TagAttributeSymbolContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by TParser#typeSymbol. def visitTypeSymbol(self, ctx:TParser.TypeSymbolContext): return self.visitChildren(ctx) @@ -16,13 +16,20 @@ except (IOError, ImportError): long_description = f.read() +__title__ = '' +__version__ = '' +__summary__ = '' +__uri__ = '' +__author__ = '' +exec(open('./qface/__about__.py').read()) + setup( - name='qface', - version='1.0.0a5', - description='QFace - A Generator Framework', + name=__title__, + version=__version__, + description=__summary__, long_description=long_description, - url='https://github.com/Pelagicore/qface', - author='JRyannel', + url=__uri__, + author=__author__, license='GPLV3', classifiers=[ 'Development Status :: 3 - Alpha', diff --git a/tests/in/com.pelagicore.ivi.climate.qdl b/tests/in/com.pelagicore.ivi.climate.qface index 6414bb5..6414bb5 100644 --- a/tests/in/com.pelagicore.ivi.climate.qdl +++ b/tests/in/com.pelagicore.ivi.climate.qface diff --git a/tests/in/com.pelagicore.ivi.tuner.qdl b/tests/in/com.pelagicore.ivi.tuner.qface index d6b742b..36fab03 100644 --- a/tests/in/com.pelagicore.ivi.tuner.qdl +++ b/tests/in/com.pelagicore.ivi.tuner.qface @@ -1,6 +1,8 @@ module com.pelagicore.ivi.tuner 1.0; /*! Service Tuner */ +@service() +@interface() interface Tuner { /*! property currentStation */ readonly Station currentStation; @@ -30,6 +32,7 @@ enum State { } /*! enum Waveband */ +@default(value=FM) enum Waveband { /*! value Waveband.FM */ FM=0, diff --git a/tests/in/com.pelagicore.one.qdl b/tests/in/com.pelagicore.one.qface index 9203d29..9203d29 100644 --- a/tests/in/com.pelagicore.one.qdl +++ b/tests/in/com.pelagicore.one.qface diff --git a/tests/in/com.pelagicore.test.qdl b/tests/in/com.pelagicore.test.qface index 77687ef..07ecf1f 100644 --- a/tests/in/com.pelagicore.test.qdl +++ b/tests/in/com.pelagicore.test.qface @@ -2,6 +2,7 @@ module com.pelagicore.test 1.0; import common 1.0; +@service(singleton=True) interface ContactService { State state; int intValue; diff --git a/tests/templates/module.txt b/tests/templates/module.txt new file mode 100644 index 0000000..d2ea91c --- /dev/null +++ b/tests/templates/module.txt @@ -0,0 +1 @@ +{{module}}
\ No newline at end of file diff --git a/tests/test_climate.py b/tests/test_climate.py index 287b36a..b7adec6 100644 --- a/tests/test_climate.py +++ b/tests/test_climate.py @@ -13,7 +13,7 @@ log.debug('input path folder: {0}'.format(inputPath.absolute())) def load_system(): - path = inputPath / 'com.pelagicore.ivi.climate.qdl' + path = inputPath / 'com.pelagicore.ivi.climate.qface' return FileSystem.parse_document(path) @@ -21,4 +21,3 @@ def test_interface(): system = load_system() interface = system.lookup('com.pelagicore.ivi.climate.ClimateControl') assert interface.name == 'ClimateControl' - diff --git a/tests/test_generator.py b/tests/test_generator.py index 83041b9..823c7fa 100644 --- a/tests/test_generator.py +++ b/tests/test_generator.py @@ -1,7 +1,7 @@ from qface.generator import FileSystem, Generator import logging import logging.config -from pathlib import Path +from path import Path # logging.config.fileConfig('logging.ini') logging.basicConfig() @@ -9,11 +9,11 @@ logging.basicConfig() log = logging.getLogger(__name__) inputPath = Path('tests/in') -log.debug('input path folder: {0}'.format(inputPath.absolute())) +log.debug('input path folder: {0}'.format(inputPath.abspath())) def loadSystem(): - path = inputPath / 'com.pelagicore.ivi.tuner.qdl' + path = inputPath / 'com.pelagicore.ivi.tuner.qface' return FileSystem.parse_document(path) @@ -40,20 +40,36 @@ def test_gen_interface(): def test_parse_document(): - system = FileSystem.parse(inputPath / 'com.pelagicore.ivi.tuner.qdl') + system = FileSystem.parse(inputPath / 'com.pelagicore.ivi.tuner.qface') assert system.lookup('com.pelagicore.ivi.tuner') def test_parse_document_list(): - input = [inputPath / 'com.pelagicore.ivi.tuner.qdl', inputPath / 'com.pelagicore.ivi.climate.qdl'] - system = FileSystem.parse(input) + src = [inputPath / 'com.pelagicore.ivi.tuner.qface', + inputPath / 'com.pelagicore.ivi.climate.qface'] + system = FileSystem.parse(src) assert system.lookup('com.pelagicore.ivi.tuner') assert system.lookup('com.pelagicore.ivi.climate') def test_parse_document_mixed(): - input = [inputPath, inputPath / 'com.pelagicore.ivi.climate.qdl'] - system = FileSystem.parse(input) + src = [inputPath, inputPath / 'com.pelagicore.ivi.climate.qface'] + system = FileSystem.parse(src) assert system.lookup('com.pelagicore.ivi.tuner') assert system.lookup('com.pelagicore.ivi.climate') assert system.lookup('com.pelagicore.one') + + +def test_destination_prefix(): + system = FileSystem.parse(inputPath) + out = Path('tests/out') + out.rmtree_p() + out.makedirs_p() + generator = Generator(searchpath='tests/templates') + for module in system.modules: + dst_template = '{{out}}/{{module|lower}}.txt' + ctx = {'out': out.abspath(), 'module': module} + generator.write(dst_template, 'module.txt', ctx) + path = generator.apply(dst_template, ctx) + assert Path(path).exists() + out.rmtree_p() diff --git a/tests/test_lookup.py b/tests/test_lookup.py index d775dea..7ff7aa5 100644 --- a/tests/test_lookup.py +++ b/tests/test_lookup.py @@ -1,9 +1,9 @@ -from qface.idl.domain import System -from qface.generator import FileSystem import logging import logging.config from pathlib import Path +from qface.generator import FileSystem + # logging.config.fileConfig('logging.ini') logging.basicConfig() @@ -13,13 +13,13 @@ inputPath = Path('tests/in') log.debug('input path folder: {0}'.format(inputPath.absolute())) -def loadTuner(): - path = inputPath / 'com.pelagicore.ivi.tuner.qdl' +def load_tuner(): + path = inputPath / 'com.pelagicore.ivi.tuner.qface' return FileSystem.parse_document(path) def test_lookup(): - system = loadTuner() + system = load_tuner() # lookup module module = system.lookup('com.pelagicore.ivi.tuner') assert module is module.lookup('com.pelagicore.ivi.tuner') @@ -34,4 +34,3 @@ def test_lookup(): # lookup enum enum = system.lookup('com.pelagicore.ivi.tuner.Waveband') assert enum is module.lookup('Waveband') - diff --git a/tests/test_parser.py b/tests/test_parser.py index 7d05f6d..3b36cd1 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -1,9 +1,9 @@ -from qface.idl.domain import System -from qface.generator import FileSystem import logging import logging.config from pathlib import Path +from qface.generator import FileSystem + # logging.config.fileConfig('logging.ini') logging.basicConfig() @@ -13,30 +13,31 @@ inputPath = Path('tests/in') log.debug('input path folder: {0}'.format(inputPath.absolute())) -def loadTuner(): - path = inputPath / 'com.pelagicore.ivi.tuner.qdl' +def load_tuner(): + path = inputPath / 'com.pelagicore.ivi.tuner.qface' return FileSystem.parse_document(path) -def loadTest(): - path = inputPath / 'com.pelagicore.test.qdl' +def load_test(): + path = inputPath / 'com.pelagicore.test.qface' return FileSystem.parse_document(path) def test_parse(): log.debug('test parse') system = FileSystem.parse(inputPath) + assert system def test_module(): - system = loadTuner() + system = load_tuner() assert len(system.modules) == 1 module = system.lookup('com.pelagicore.ivi.tuner') assert module in system.modules def test_interface(): - system = loadTuner() + system = load_tuner() module = system.lookup('com.pelagicore.ivi.tuner') interface = system.lookup('com.pelagicore.ivi.tuner.Tuner') assert interface in module.interfaces @@ -44,7 +45,7 @@ def test_interface(): def test_property(): - system = loadTuner() + system = load_tuner() interface = system.lookup('com.pelagicore.ivi.tuner.Tuner') module = system.lookup('com.pelagicore.ivi.tuner') property = interface._propertyMap['currentStation'] @@ -56,7 +57,7 @@ def test_property(): def test_struct(): - system = loadTuner() + system = load_tuner() module = system.lookup('com.pelagicore.ivi.tuner') symbol = system.lookup('com.pelagicore.ivi.tuner.Station') assert symbol.name == 'Station' @@ -66,7 +67,7 @@ def test_struct(): def test_enum(): - system = loadTuner() + system = load_tuner() definition = system.lookup('com.pelagicore.ivi.tuner.Waveband') module = system.lookup('com.pelagicore.ivi.tuner') symbol = system.lookup('com.pelagicore.ivi.tuner.Waveband') @@ -79,15 +80,16 @@ def test_enum(): def test_enum_counter(): - system = loadTest() + system = load_test() enum = system.lookup('com.pelagicore.test.State') assert enum # import ipdb; ipdb.set_trace() assert enum._memberMap['Null'].value is 0 assert enum._memberMap['Failure'].value is 3 + def test_flag_counter(): - system = loadTest() + system = load_test() flag = system.lookup('com.pelagicore.test.Phase') assert flag # import ipdb; ipdb.set_trace() @@ -95,14 +97,15 @@ def test_flag_counter(): assert flag._memberMap['PhaseTwo'].value is 2 assert flag._memberMap['PhaseThree'].value is 4 + def test_flag(): - system = loadTuner() + system = load_tuner() symbol = system.lookup('com.pelagicore.ivi.tuner.Features') assert symbol.is_flag def test_list(): - system = loadTuner() + system = load_tuner() interface = system.lookup('com.pelagicore.ivi.tuner.Tuner') property = interface._propertyMap['primitiveList'] assert property.type.name == 'list' @@ -118,7 +121,7 @@ def test_list(): def test_model(): - system = loadTuner() + system = load_tuner() interface = system.lookup('com.pelagicore.ivi.tuner.Tuner') property = interface._propertyMap['primitiveModel'] assert property.type.name == 'model' @@ -131,7 +134,3 @@ def test_model(): assert property.type.is_model is True assert property.type.nested.is_complex assert property.type.nested.name == 'Station' - - - - diff --git a/tests/test_qtcpp_helper.py b/tests/test_qtcpp_helper.py new file mode 100644 index 0000000..d86dfd1 --- /dev/null +++ b/tests/test_qtcpp_helper.py @@ -0,0 +1,202 @@ +import logging +import logging.config +from pathlib import Path + +from qface.helper import qtcpp +from qface.generator import FileSystem + + +from antlr4 import InputStream + +logging.basicConfig() + +log = logging.getLogger(__name__) + + +src = Path('tests/in') + +document = """ +// org.example.qface +module org.example 1.0 + +interface Test { + void echo(string message); + Message message; + Status status; + list<int> list001; + list<Message> list002; + model<int> model001; + model<Message> model002; + +} + +struct Message { + string body +} + +enum Status { + ON, + OFF +} +""" + + +def parse_document(): + stream = InputStream(document) + return FileSystem._parse_stream(stream) + + +def test_return_type(): + system = parse_document() + interface = system.lookup('org.example.Test') + assert interface + operation = interface._operationMap['echo'] + assert operation + parameter = operation._parameterMap['message'] + + types = { + 'bool': 'bool', + 'int': 'int', + 'real': 'qreal', + 'string': 'QString', + 'var': 'QVariant' + } + + for key, value in types.items(): + parameter.type.name = key + answer = qtcpp.Filters.returnType(parameter) + assert answer == value + + # check for struct + prop = interface._propertyMap['message'] + answer = qtcpp.Filters.returnType(prop) + assert answer == 'QmlMessage' + # check for enum + prop = interface._propertyMap['status'] + answer = qtcpp.Filters.returnType(prop) + assert answer == 'QmlExampleModule::Status' + + # check for list of primitive + prop = interface._propertyMap['list001'] + answer = qtcpp.Filters.returnType(prop) + assert answer == 'QVariantList' + + # check for list of structs + prop = interface._propertyMap['list002'] + answer = qtcpp.Filters.returnType(prop) + assert answer == 'QVariantList' + + # check for model of primitive + prop = interface._propertyMap['model001'] + answer = qtcpp.Filters.returnType(prop) + assert answer == 'QmlVariantModel *' + + # check for model of structs + prop = interface._propertyMap['model002'] + answer = qtcpp.Filters.returnType(prop) + assert answer == 'QmlMessageModel *' + + +def test_default_value(): + system = parse_document() + interface = system.lookup('org.example.Test') + assert interface + operation = interface._operationMap['echo'] + assert operation + parameter = operation._parameterMap['message'] + + types = { + 'bool': 'false', + 'int': '0', + 'real': '0.0', + 'string': 'QString()', + 'var': 'QVariant()' + } + + for key, value in types.items(): + parameter.type.name = key + answer = qtcpp.Filters.defaultValue(parameter) + assert answer == value + + # check for struct + prop = interface._propertyMap['message'] + answer = qtcpp.Filters.defaultValue(prop) + assert answer == 'QmlMessage()' + # check for enum + prop = interface._propertyMap['status'] + answer = qtcpp.Filters.defaultValue(prop) + assert answer == 'Status::ON' + + # check for list of primitive + prop = interface._propertyMap['list001'] + answer = qtcpp.Filters.defaultValue(prop) + assert answer == 'QVariantList()' + + # check for list of structs + prop = interface._propertyMap['list002'] + answer = qtcpp.Filters.defaultValue(prop) + assert answer == 'QVariantList()' + + # check for model of primitive + prop = interface._propertyMap['model001'] + answer = qtcpp.Filters.defaultValue(prop) + assert answer == 'new QmlVariantModel(this)' + + # check for model of structs + prop = interface._propertyMap['model002'] + answer = qtcpp.Filters.defaultValue(prop) + assert answer == 'new QmlMessageModel(this)' + + +def test_parameter_type(): + system = parse_document() + interface = system.lookup('org.example.Test') + assert interface + operation = interface._operationMap['echo'] + assert operation + parameter = operation._parameterMap['message'] + name = parameter.name + + types = { + 'bool': 'bool {0}'.format(name), + 'int': 'int {0}'.format(name), + 'real': 'qreal {0}'.format(name), + 'string': 'const QString &{0}'.format(name), + 'var': 'const QVariant &{0}'.format(name) + } + + for key, value in types.items(): + parameter.type.name = key + answer = qtcpp.Filters.parameterType(parameter) + assert answer == value + + # check for struct + prop = interface._propertyMap['message'] + answer = qtcpp.Filters.parameterType(prop) + assert answer == 'const QmlMessage &{0}'.format(prop.name) + # check for enum + prop = interface._propertyMap['status'] + answer = qtcpp.Filters.parameterType(prop) + assert answer == 'QmlExampleModule::Status {0}'.format(prop.name) + + # check for list of primitive + prop = interface._propertyMap['list001'] + answer = qtcpp.Filters.parameterType(prop) + assert answer == 'const QVariantList &{0}'.format(prop.name) + + # check for list of structs + prop = interface._propertyMap['list002'] + answer = qtcpp.Filters.parameterType(prop) + assert answer == 'const QVariantList &{0}'.format(prop.name) + + # check for model of primitive + prop = interface._propertyMap['model001'] + answer = qtcpp.Filters.parameterType(prop) + assert answer == 'QmlVariantModel *{0}'.format(prop.name) + + # check for model of structs + prop = interface._propertyMap['model002'] + answer = qtcpp.Filters.parameterType(prop) + assert answer == 'QmlMessageModel *{0}'.format(prop.name) + + diff --git a/tests/test_tags.py b/tests/test_tags.py new file mode 100644 index 0000000..5ff56a0 --- /dev/null +++ b/tests/test_tags.py @@ -0,0 +1,39 @@ +from qface.generator import FileSystem +import logging +import logging.config +from pathlib import Path + +# logging.config.fileConfig('logging.ini') +logging.basicConfig() + +log = logging.getLogger(__name__) + +inputPath = Path('tests/in') +log.debug('input path folder: {0}'.format(inputPath.absolute())) + + +def loadTuner(): + path = inputPath / 'com.pelagicore.ivi.tuner.qface' + return FileSystem.parse_document(path) + + +def test_tag(): + system = loadTuner() + # lookup module + module = system.lookup('com.pelagicore.ivi.tuner') + assert module is module.lookup('com.pelagicore.ivi.tuner') + # lookup service + service = system.lookup('com.pelagicore.ivi.tuner.Tuner') + assert service is module.lookup('Tuner') + assert 'service' in service.tags + assert 'interface' in service.tags + + # lookup struct + struct = system.lookup('com.pelagicore.ivi.tuner.Station') + assert struct is module.lookup('Station') + + # lookup enum + enum = system.lookup('com.pelagicore.ivi.tuner.Waveband') + assert enum is module.lookup('Waveband') + assert 'default' in enum.tags + assert enum.attribute('default', 'value') == 'FM' diff --git a/tests/test_validation.py b/tests/test_validation.py index 98fa949..a420783 100644 --- a/tests/test_validation.py +++ b/tests/test_validation.py @@ -1,9 +1,9 @@ -from qface.idl.domain import System -from qface.generator import FileSystem import logging import logging.config from pathlib import Path +from qface.generator import FileSystem + # logging.config.fileConfig('logging.ini') logging.basicConfig() @@ -13,13 +13,13 @@ inputPath = Path('tests/in') log.debug('input path folder: {0}'.format(inputPath.absolute())) -def loadOne(): - path = inputPath / 'com.pelagicore.one.qdl' +def load_one(): + path = inputPath / 'com.pelagicore.one.qface' return FileSystem.parse_document(path) def test_resolve(): - system = loadOne() + system = load_one() module = system.lookup('com.pelagicore.one') assert module service = module.lookup('OneService') @@ -41,7 +41,7 @@ def test_resolve(): def test_resolve_nested(): - system = loadOne() + system = load_one() module = system.lookup('com.pelagicore.one') assert module struct = module.lookup('com.pelagicore.one.StringStruct') @@ -53,12 +53,10 @@ def test_resolve_nested(): service = module.lookup('com.pelagicore.one.OneService') assert service - listProperty = service._propertyMap['messageList'] - assert listProperty - assert listProperty.type.nested.reference is struct - - modelProperty = service._propertyMap['messageModel'] - assert modelProperty - assert modelProperty.type.nested.reference is struct - + list_property = service._propertyMap['messageList'] + assert list_property + assert list_property.type.nested.reference is struct + model_property = service._propertyMap['messageModel'] + assert model_property + assert model_property.type.nested.reference is struct |