summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MANIFEST.in17
-rw-r--r--qface/__about__.py2
-rw-r--r--qface/filters.py28
-rw-r--r--qface/generator.py55
-rw-r--r--qface/helper/doc.py4
-rw-r--r--qface/helper/qtcpp.py2
-rw-r--r--qface/idl/domain.py2
-rw-r--r--qface/idl/listener.py1
-rw-r--r--qface/templates/__init__.py0
-rw-r--r--qface/templates/qface/__init__.py0
-rw-r--r--setup.py3
-rw-r--r--tests/in/com.pelagicore.ivi.tuner.qface2
-rw-r--r--tests/in/org.example.echo.qface2
-rw-r--r--tests/in/org.example.failing.qface5
-rw-r--r--tests/test_comments.py6
-rw-r--r--tests/test_parser.py22
-rw-r--r--tests/test_qtcpp_helper.py14
17 files changed, 135 insertions, 30 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index 10543f7..064b9f8 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,5 +1,12 @@
-include LICENSE.GPLV3
-include qface/builtin/qtcpp/templates/*
-include qface/builtin/qtcpp/log.yaml
-include qface/builtin/qtqml/templates/*
-include qface/builtin/qtqml/log.yaml
+include LICENSE
+include README.md
+
+graft qface/templates
+
+global-exclude *.so
+global-exclude *.pyc
+global-exclude *~
+global-exclude \#*
+global-exclude .git*
+global-exclude .DS_Store
+
diff --git a/qface/__about__.py b/qface/__about__.py
index a9d62f6..0d6a726 100644
--- a/qface/__about__.py
+++ b/qface/__about__.py
@@ -9,7 +9,7 @@ except NameError:
__title__ = "qface"
__summary__ = "A generator framework based on a common modern IDL"
__url__ = "https://pelagicore.github.io/qface/"
-__version__ = "1.5"
+__version__ = "1.6"
__author__ = "JRyannel"
__author_email__ = "qface-generator@googlegroups.com"
__copyright__ = "2017 Pelagicore"
diff --git a/qface/filters.py b/qface/filters.py
index af9fc1f..c5ecab8 100644
--- a/qface/filters.py
+++ b/qface/filters.py
@@ -2,25 +2,29 @@ import json
import hashlib
-def jsonify(obj):
+def jsonify(symbol):
+ """ returns json format for symbol """
try:
# all symbols have a toJson method, try it
- return json.dumps(obj.toJson(), indent=' ')
+ return json.dumps(symbol.toJson(), indent=' ')
except AttributeError:
pass
- return json.dumps(obj, indent=' ')
+ return json.dumps(symbol, indent=' ')
-def upper_first(s):
- s = str(s)
- return s[0].upper() + s[1:]
+def upper_first(symbol):
+ """ uppercase first letter """
+ name = str(symbol)
+ return name[0].upper() + name[1:]
-def hash(s, hash_type='sha1'):
- h = hashlib.new(hash_type)
- h.update(str(s).encode('utf-8'))
- return h.hexdigest()
+def hash(symbol, hash_type='sha1'):
+ """ create a hash code from symbol """
+ code = hashlib.new(hash_type)
+ code.update(str(symbol).encode('utf-8'))
+ return code.hexdigest()
-def path(s):
- return str(s).replace('.', '/')
+def path(symbol):
+ """ replaces '.' with '/' """
+ return str(symbol).replace('.', '/')
diff --git a/qface/generator.py b/qface/generator.py
index 997ace8..c2e018b 100644
--- a/qface/generator.py
+++ b/qface/generator.py
@@ -1,3 +1,4 @@
+
# Copyright (c) Pelagicore AB 2016
from jinja2 import Environment, Template
@@ -5,12 +6,13 @@ from jinja2 import FileSystemLoader, PackageLoader, ChoiceLoader
from jinja2 import TemplateSyntaxError, TemplateNotFound, TemplateError
from path import Path
from antlr4 import FileStream, CommonTokenStream, ParseTreeWalker
-from antlr4.error import DiagnosticErrorListener
+from antlr4.error import DiagnosticErrorListener, ErrorListener
import shelve
import logging
import hashlib
import yaml
import click
+import sys
from .idl.parser.TLexer import TLexer
from .idl.parser.TParser import TParser
@@ -43,8 +45,30 @@ def lower_first_filter(s):
return s[0].lower() + s[1:]
+class ReportingErrorListener(ErrorListener.ErrorListener):
+ def __init__(self, document):
+ self.document = document
+
+ def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
+ msg = '{0}:{1}:{2} {2}'.format(self.document, line, column, msg)
+ click.secho(msg, fg='red')
+ raise ValueError(msg)
+
+ def reportAmbiguity(self, recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs):
+ click.secho('ambiguity', fg='red')
+
+ def reportAttemptingFullContext(self, recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs):
+ click.secho('reportAttemptingFullContext', fg='red')
+
+ def reportContextSensitivity(self, recognizer, dfa, startIndex, stopIndex, prediction, configs):
+ click.secho('reportContextSensitivity', fg='red')
+
+
class Generator(object):
"""Manages the templates and applies your context data"""
+ strict = False
+ """ enables strict code generation """
+
def __init__(self, search_path: str):
loader = ChoiceLoader([
FileSystemLoader(search_path),
@@ -86,18 +110,24 @@ class Generator(object):
"""Using a template file name it renders a template
into a file given a context
"""
+ error = False
try:
self._write(file_path, template, context, preserve)
except TemplateSyntaxError as exc:
# import pdb; pdb.set_trace()
message = '{0}:{1} error: {2}'.format(exc.filename, exc.lineno, exc.message)
click.secho(message, fg='red')
+ error = True
except TemplateNotFound as exc:
message = '{0} error: Template not found'.format(exc.name)
click.secho(message, fg='red')
+ error = True
except TemplateError as exc:
message = 'error: {0}'.format(exc.message)
click.secho(message, fg='red')
+ error = True
+ if error and Generator.strict:
+ sys.exit(-1)
def _write(self, file_path: Path, template: str, context: dict, preserve: bool = False):
path = self.destination / Path(self.apply(file_path, context))
@@ -125,9 +155,26 @@ class Generator(object):
class FileSystem(object):
"""QFace helper functions to work with the file system"""
+ strict = False
+ """ enables strict parsing """
@staticmethod
def parse_document(document: Path, system: System = None):
+ error = False
+ try:
+ return FileSystem._parse_document(document, system)
+ except FileNotFoundError as e:
+ click.secho('{0}: file not found'.format(document), fg='red')
+ error = True
+ except ValueError as e:
+ click.secho('Error parsing document {0}'.format(document))
+ error = True
+ if error and FileSystem.strict:
+ sys.exit(-1)
+
+
+ @staticmethod
+ def _parse_document(document: Path, system: System = None):
"""Parses a document and returns the resulting domain system
:param path: document path to parse
@@ -135,19 +182,19 @@ class FileSystem(object):
"""
logger.debug('parse document: {0}'.format(document))
stream = FileStream(str(document), encoding='utf-8')
- system = FileSystem._parse_stream(stream, system)
+ system = FileSystem._parse_stream(stream, system, document)
FileSystem.merge_annotations(system, document.stripext() + '.yaml')
return system
@staticmethod
- def _parse_stream(stream, system: System = None):
+ def _parse_stream(stream, system: System = None, document=None):
logger.debug('parse stream')
system = system or System()
lexer = TLexer(stream)
stream = CommonTokenStream(lexer)
parser = TParser(stream)
- parser.addErrorListener(DiagnosticErrorListener.DiagnosticErrorListener())
+ parser.addErrorListener(ReportingErrorListener(document))
tree = parser.documentSymbol()
walker = ParseTreeWalker()
walker.walk(DomainListener(system), tree)
diff --git a/qface/helper/doc.py b/qface/helper/doc.py
index 0935e67..9695136 100644
--- a/qface/helper/doc.py
+++ b/qface/helper/doc.py
@@ -21,7 +21,7 @@ class DocObject:
The documentation object passed into the template engine
"""
def __init__(self):
- self.brief = str()
+ self.brief = []
self.description = []
self.see = []
self.deprecated = False
@@ -78,4 +78,6 @@ def parse_doc(s):
doc.add_tag(tag, value)
elif tag: # append to previous matched tag
doc.add_tag(tag, line)
+ else: # append any loose lines to description
+ doc.add_tag('description', line)
return doc
diff --git a/qface/helper/qtcpp.py b/qface/helper/qtcpp.py
index 4a7178d..db959b4 100644
--- a/qface/helper/qtcpp.py
+++ b/qface/helper/qtcpp.py
@@ -39,6 +39,8 @@ class Filters(object):
module_name = upper_first(t.reference.module.module_name)
value = next(iter(t.reference.members))
return '{0}{1}Module::{2}'.format(prefix, module_name, value)
+ elif t.is_flag:
+ return '0'
elif symbol.type.is_list:
nested = Filters.returnType(symbol.type.nested)
return 'QVariantList()'.format(nested)
diff --git a/qface/idl/domain.py b/qface/idl/domain.py
index b8c611f..a2e3972 100644
--- a/qface/idl/domain.py
+++ b/qface/idl/domain.py
@@ -125,6 +125,7 @@ class Symbol(NamedElement):
self._contentMap = ChainMap()
self.type = TypeSymbol('', self)
+ self.kind = self.__class__.__name__.lower()
""" the associated type information """
@property
@@ -431,6 +432,7 @@ class Operation(Symbol):
def toJson(self):
o = super().toJson()
o['parameters'] = [s.toJson() for s in self.parameters]
+ o['type'] = self.type.toJson()
return o
diff --git a/qface/idl/listener.py b/qface/idl/listener.py
index 3704444..3a36837 100644
--- a/qface/idl/listener.py
+++ b/qface/idl/listener.py
@@ -214,6 +214,7 @@ class DomainListener(TListener):
if ctx.intSymbol():
value = int(ctx.intSymbol().value.text, 0)
self.field.value = value
+ self.parse_annotations(ctx, self.field)
contextMap[ctx] = self.field
if self.enum.is_flag:
self.enumCounter <<= 1
diff --git a/qface/templates/__init__.py b/qface/templates/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/qface/templates/__init__.py
+++ /dev/null
diff --git a/qface/templates/qface/__init__.py b/qface/templates/qface/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/qface/templates/qface/__init__.py
+++ /dev/null
diff --git a/setup.py b/setup.py
index e37e3e6..567f9e2 100644
--- a/setup.py
+++ b/setup.py
@@ -43,9 +43,6 @@ setup(
keywords='qt code generator framework',
packages=find_packages(),
include_package_data=True,
- package_data={
- '': ['*[!*.pyc]']
- },
install_requires=[
'jinja2',
'path.py',
diff --git a/tests/in/com.pelagicore.ivi.tuner.qface b/tests/in/com.pelagicore.ivi.tuner.qface
index e8f53ae..725d4d5 100644
--- a/tests/in/com.pelagicore.ivi.tuner.qface
+++ b/tests/in/com.pelagicore.ivi.tuner.qface
@@ -2,7 +2,7 @@ module com.pelagicore.ivi.tuner 1.0;
interface BaseTuner {
- property int baseValue;
+ int baseValue;
}
diff --git a/tests/in/org.example.echo.qface b/tests/in/org.example.echo.qface
index 04a93ce..087f14f 100644
--- a/tests/in/org.example.echo.qface
+++ b/tests/in/org.example.echo.qface
@@ -10,6 +10,8 @@ module org.example.echo 1.0
* @see org.example
* @see http://qt.io
* @anything hello
+ *
+ * continued description
*/
interface Echo {
/**
diff --git a/tests/in/org.example.failing.qface b/tests/in/org.example.failing.qface
new file mode 100644
index 0000000..0fe3888
--- /dev/null
+++ b/tests/in/org.example.failing.qface
@@ -0,0 +1,5 @@
+module org.example 1.0
+
+interfase xx Failed {
+
+} \ No newline at end of file
diff --git a/tests/test_comments.py b/tests/test_comments.py
index 008dd0d..d2f18b6 100644
--- a/tests/test_comments.py
+++ b/tests/test_comments.py
@@ -35,8 +35,8 @@ def test_comment():
interface = system.lookup('org.example.echo.Echo')
assert interface
o = doc.parse_doc(interface.comment)
- assert o.brief == 'the brief'
- assert o.description == ['the description', 'continues {@link http://qt.io}']
+ assert o.brief == ['the brief']
+ assert o.description == ['the description', 'continues {@link http://qt.io}', 'continued description']
assert o.deprecated is True
assert o.see == ['org.example.echo.Echo', 'org.example', 'http://qt.io']
@@ -50,4 +50,4 @@ def test_qdoc_translate():
assert interface
doc.translate = qdoc_translate
o = doc.parse_doc(interface.comment)
- assert o.description == ['the description', 'continues \\link{http://qt.io}']
+ assert o.description == ['the description', 'continues \\link{http://qt.io}', 'continued description']
diff --git a/tests/test_parser.py b/tests/test_parser.py
index b2844fc..6adfe04 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -1,5 +1,6 @@
import logging
import logging.config
+import pytest
from path import Path
from qface.generator import FileSystem
@@ -190,3 +191,24 @@ def test_interface_property():
assert prop.type.is_interface
assert prop.type.reference is extension
+
+def test_symbol_kind():
+ system = load_tuner()
+ tuner = system.lookup('com.pelagicore.ivi.tuner.Tuner')
+ assert tuner.kind == 'interface'
+ property = system.lookup('com.pelagicore.ivi.tuner.Tuner#primitiveModel')
+ assert property.kind == 'property'
+
+
+def test_parser_exceptions():
+ path = inputPath / 'org.example.failing.qface'
+ system = FileSystem.parse_document(path)
+
+ try:
+ system = FileSystem.parse_document('not-exists')
+ except SystemExit as e:
+ pass
+ else:
+ pytest.fail('should not ome here')
+
+
diff --git a/tests/test_qtcpp_helper.py b/tests/test_qtcpp_helper.py
index a59e0d9..acc034f 100644
--- a/tests/test_qtcpp_helper.py
+++ b/tests/test_qtcpp_helper.py
@@ -23,6 +23,7 @@ interface Test {
void echo(string message);
Message message;
Status status;
+ ApplicationState state;
list<int> list001;
list<Message> list002;
model<int> model001;
@@ -38,6 +39,14 @@ enum Status {
ON,
OFF
}
+
+flag ApplicationState {
+ Suspended,
+ Hidden,
+ Inactive,
+ Active,
+}
+
"""
@@ -127,6 +136,11 @@ def test_default_value():
answer = qtcpp.Filters.defaultValue(prop)
assert answer == 'ExampleModule::ON'
+ # check for flag
+ prop = interface._propertyMap['state']
+ answer = qtcpp.Filters.defaultValue(prop)
+ assert answer == '0'
+
# check for list of primitive
prop = interface._propertyMap['list001']
answer = qtcpp.Filters.defaultValue(prop)