aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuergen Bocklage-Ryannel <juergen.bocklage-ryannel@pelagicore.com>2017-01-17 12:29:27 +0100
committerJuergen Bocklage-Ryannel <juergen.bocklage-ryannel@pelagicore.com>2017-01-17 12:29:27 +0100
commit92dc0631922f8b2faaf1c1772d0f8534b884f326 (patch)
tree29420e952530a825739a1f884e93e20836aee7cc
parent0d747ca6d9647f212a0d853987faed46e66408b7 (diff)
parent978c6058064f9f0384c913b94ed8266563e572a7 (diff)
Merge branch 'release/1.0b1'1.0b1
-rw-r--r--README.md7
-rw-r--r--builtin/qtcpp/log.yaml (renamed from examples/qtcpp/generator/log.yaml)2
-rwxr-xr-xbuiltin/qtcpp/qtcpp.py69
-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.cpp102
-rw-r--r--builtin/qtcpp/templates/variantmodel.h38
-rw-r--r--builtin/qtqml/log.yaml18
-rw-r--r--builtin/qtqml/qtqml.py62
-rw-r--r--builtin/qtqml/templates/AbstractInterface.qml20
-rw-r--r--builtin/qtqml/templates/Interface.qml11
-rw-r--r--builtin/qtqml/templates/InterfaceProvider.qml23
-rw-r--r--builtin/qtqml/templates/Module.qml24
-rw-r--r--builtin/qtqml/templates/module.js18
-rw-r--r--builtin/qtqml/templates/private_qmldir5
-rw-r--r--builtin/qtqml/templates/public_qmldir4
-rwxr-xr-xcli.py2
-rw-r--r--docs/api.rst8
-rw-r--r--docs/builtin.rst60
-rw-r--r--docs/extending.rst2
-rw-r--r--docs/index.rst9
-rw-r--r--docs/qtcpp.rst125
-rw-r--r--docs/qtqml.rst27
-rw-r--r--examples/csv/README.md8
-rwxr-xr-xexamples/csv/csv.py26
-rw-r--r--examples/csv/templates/modules.csv (renamed from generator/csv/templates/modules.csv)0
-rw-r--r--examples/echo/README.md30
-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.pro7
-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-xexamples/qtcpp/generator/qtcpp.py95
-rw-r--r--examples/qtcpp/qtcpp.pro2
-rw-r--r--examples/qtcpp/src/src.pro2
-rwxr-xr-xgenerator/csv/csv.py22
-rw-r--r--qface/__about__.py13
-rw-r--r--qface/generator.py41
-rw-r--r--qface/helper/__init__.py (renamed from examples/qtcpp/src/plugins/.gitkeep)0
-rw-r--r--qface/helper/qtcpp.py107
-rw-r--r--qface/helper/qtqml.py52
-rw-r--r--qface/idl/domain.py36
-rw-r--r--qface/idl/listener.py24
-rw-r--r--qface/idl/parser/T.g426
-rw-r--r--qface/idl/parser/T.tokens39
-rw-r--r--qface/idl/parser/TLexer.py233
-rw-r--r--qface/idl/parser/TLexer.tokens39
-rw-r--r--qface/idl/parser/TListener.py18
-rw-r--r--qface/idl/parser/TParser.py875
-rw-r--r--qface/idl/parser/TVisitor.py10
-rw-r--r--setup.py17
-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.txt1
-rw-r--r--tests/test_climate.py3
-rw-r--r--tests/test_generator.py32
-rw-r--r--tests/test_lookup.py11
-rw-r--r--tests/test_parser.py39
-rw-r--r--tests/test_qtcpp_helper.py202
-rw-r--r--tests/test_tags.py39
-rw-r--r--tests/test_validation.py26
76 files changed, 2084 insertions, 741 deletions
diff --git a/README.md b/README.md
index f2524ba..b73e2ce 100644
--- a/README.md
+++ b/README.md
@@ -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 %}
diff --git a/cli.py b/cli.py
index c70ecf3..0c4a9d1 100755
--- a/cli.py
+++ b/cli.py
@@ -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)
diff --git a/setup.py b/setup.py
index 8acbf20..eb98ff1 100644
--- a/setup.py
+++ b/setup.py
@@ -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