summaryrefslogtreecommitdiff
path: root/grc/core/blocks
diff options
context:
space:
mode:
authorTerry May <terrydmay@gmail.com>2019-09-09 19:45:41 -0400
committerMartin Braun <martin@gnuradio.org>2020-02-18 22:04:15 -0800
commit64ee803068269fe3b9563fd415c420fb513a1c9b (patch)
treed27e9b5560b5bb4377f964e39772cd1395a7bff0 /grc/core/blocks
parent012870af22ae873b3b998691de8e81752179d266 (diff)
grc: Fix C++ code generation
- Added support for C++ std::map<> from python dict - Fixed default initialization of parameters in main() - Added missing include for realtime scheduling - Added default CMake option for std=c++11 as this is required for gnuradio >= 3.8 - Fixed mako template to add initialization to parameter declarations in main() - Fixed C++ constructor initialization list generation - Fixed parameter type determination when an lvalue is used in an rvalue expression - Improved determining type of C++ variables - Added C++ support for gr_complex parameters - Fixed C++ generation of nested container types - Added C++ support for virtual source/sink - Moved cmake CMAKE_CXX_STANDARD 11 option from options.yml to CMakeLists.txt.mako - Fixed qtqui_sink to allow multiple instances - Revised virtual connection processing in cpp_top_block.py Reviewed-By: HÃ¥kon Vagsether <hauk142@gmail.com>
Diffstat (limited to 'grc/core/blocks')
-rw-r--r--grc/core/blocks/_build.py2
-rw-r--r--grc/core/blocks/block.py130
-rw-r--r--grc/core/blocks/virtual.py8
3 files changed, 98 insertions, 42 deletions
diff --git a/grc/core/blocks/_build.py b/grc/core/blocks/_build.py
index f8406f9d6b..151fa3274f 100644
--- a/grc/core/blocks/_build.py
+++ b/grc/core/blocks/_build.py
@@ -53,7 +53,7 @@ def build(id, label='', category='', flags='', documentation='',
cpp_templates = cpp_templates or {}
cls.cpp_templates = MakoTemplates(
- includes=cpp_templates.get('includes', ''),
+ includes=cpp_templates.get('includes', []),
make=cpp_templates.get('make', ''),
callbacks=cpp_templates.get('callbacks', []),
var_make=cpp_templates.get('var_make', ''),
diff --git a/grc/core/blocks/block.py b/grc/core/blocks/block.py
index e51b730cdd..fe16f710cc 100644
--- a/grc/core/blocks/block.py
+++ b/grc/core/blocks/block.py
@@ -77,7 +77,7 @@ class Block(Element):
self.states = {'state': True, 'bus_source': False, 'bus_sink': False, 'bus_structure': None}
- if 'cpp' in self.flags:
+ if 'cpp' in self.flags and not (self.is_virtual_source() or self.is_virtual_sink()):
self.orig_cpp_templates = self.cpp_templates # The original template, in case we have to edit it when transpiling to C++
self.current_bus_structure = {'source': None, 'sink': None}
@@ -400,7 +400,7 @@ class Block(Element):
return [make_callback(c) for c in self.cpp_templates.render('callbacks')]
- def decide_type(self):
+ def format_expr(self, py_type):
"""
Evaluate the value of the variable block and decide its type.
@@ -410,60 +410,112 @@ class Block(Element):
value = self.params['value'].value
self.cpp_templates = copy.copy(self.orig_cpp_templates)
- def get_type(element):
+ # Determine the lvalue type
+ def get_type(element, _vtype):
+ evaluated = None
try:
evaluated = ast.literal_eval(element)
+ if _vtype == None:
+ _vtype = type(evaluated)
+ except ValueError or SyntaxError as excp:
+ if _vtype == None:
+ print(excp)
+
+ if _vtype in [int, float, bool, list, dict, str, complex]:
+ if _vtype == (int or long):
+ return 'int'
+
+ if _vtype == float:
+ return 'double'
+
+ if _vtype == bool:
+ return 'bool'
+
+ if _vtype == complex:
+ return 'gr_complex'
+
+ if _vtype == list:
+ try:
+ # For container types we must also determine the type of the template parameter(s)
+ return 'std::vector<' + get_type(str(evaluated[0]), type(evaluated[0])) + '>'
+
+ except IndexError: # empty list
+ return 'std::vector<std::string>'
+
+ if _vtype == dict:
+ try:
+ # For container types we must also determine the type of the template parameter(s)
+ key = list(evaluated)[0]
+ val = list(evaluated.values())[0]
+ return 'std::map<' + get_type(str(key), type(key)) + ', ' + get_type(str(val), type(val)) +'>'
+
+ except IndexError: # empty dict
+ return 'std::map<std::string, std::string>'
- except ValueError or SyntaxError:
- if re.match(r'^(numpy|np|scipy|sp)\.pi$', value):
- return 'pi'
else:
return 'std::string'
- else:
- _vtype = type(evaluated)
- if _vtype in [int, float, bool, list]:
- if _vtype == (int or long):
- return 'int'
-
- if _vtype == float:
- return 'double'
+ # Get the lvalue type
+ self.vtype = get_type(value, py_type)
+
+ # The r-value for these types must be transformed to create legal C++ syntax.
+ if self.vtype in ['bool', 'gr_complex'] or 'std::map' in self.vtype or 'std::vector' in self.vtype:
+ evaluated = ast.literal_eval(value)
+ self.cpp_templates['var_make'] = self.cpp_templates['var_make'].replace('${value}', self.get_cpp_value(evaluated))
- if _vtype == bool:
- return 'bool'
+ if 'string' in self.vtype:
+ self.cpp_templates['includes'].append('#include <string>')
- if _vtype == list:
- try:
- first_element_type = type(evaluated[0])
- if first_element_type != str:
- list_type = get_type(str(evaluated[0]))
- else:
- list_type = get_type(evaluated[0])
- except IndexError: # empty list
- return 'std::vector<std::string>'
+ def get_cpp_value(self, pyval):
- else:
- return 'std::vector<' + list_type + '>'
+ if type(pyval) == int or type(pyval) == float:
+ val_str = str(pyval)
- else:
- return 'std::string'
+ # Check for PI and replace with C++ constant
+ pi_re = r'^(math|numpy|np|scipy|sp)\.pi$'
+ if re.match(pi_re, str(pyval)):
+ val_str = re.sub(pi_re, 'boost::math::constants::pi<double>()', val_str)
+ self.cpp_templates['includes'].append('#include <boost/math/constants/constants.hpp>')
+
+ return str(pyval)
- self.vtype = get_type(value)
- if self.vtype == 'bool':
- self.cpp_templates['var_make'] = self.cpp_templates['var_make'].replace('${value}', (value[0].lower() + value[1:]))
+ elif type(pyval) == bool:
+ return str(pyval)[0].lower() + str(pyval)[1:]
- elif self.vtype == 'pi':
- self.vtype = 'double'
- self.cpp_templates['var_make'] = self.cpp_templates['var_make'].replace('${value}', 'boost::math::constants::pi<double>()')
- self.cpp_templates['includes'].append('#include <boost/math/constants/constants.hpp>')
+ elif type(pyval) == complex:
+ self.cpp_templates['includes'].append('#include <gnuradio/gr_complex.h>')
+ evaluated = ast.literal_eval(str(pyval).strip())
+ return '{' + str(evaluated.real) + ', ' + str(evaluated.imag) + '}'
- elif 'std::vector' in self.vtype:
+ elif type(pyval) == list:
self.cpp_templates['includes'].append('#include <vector>')
- self.cpp_templates['var_make'] = self.cpp_templates['var_make'].replace('${value}', '{' + value[1:-1] + '}')
+ val_str = '{'
+ for element in pyval:
+ val_str += self.get_cpp_value(element) + ', '
- if 'string' in self.vtype:
+ if len(val_str) > 1:
+ # truncate to trim superfluous ', ' from the end
+ val_str = val_str[0:-2]
+
+ return val_str + '}'
+
+ elif type(pyval) == dict:
+ self.cpp_templates['includes'].append('#include <map>')
+ val_str = '{'
+ for key in pyval:
+ val_str += '{' + self.get_cpp_value(key) + ', ' + self.get_cpp_value(pyval[key]) + '}, '
+
+ if len(val_str) > 1:
+ # truncate to trim superfluous ', ' from the end
+ val_str = val_str[0:-2]
+
+ return val_str + '}'
+
+ if type(self.vtype) == str:
self.cpp_templates['includes'].append('#include <string>')
+ return '"' + pyval + '"'
+
def is_virtual_sink(self):
return self.key == 'virtual_sink'
diff --git a/grc/core/blocks/virtual.py b/grc/core/blocks/virtual.py
index a742419d27..598e8371d5 100644
--- a/grc/core/blocks/virtual.py
+++ b/grc/core/blocks/virtual.py
@@ -18,10 +18,12 @@ class VirtualSink(Block):
key = 'virtual_sink'
label = 'Virtual Sink'
+ flags = Block.flags
+ flags.set('cpp')
parameters_data = build_params(
params_raw=[dict(label='Stream ID', id='stream_id', dtype='stream_id')],
- have_inputs=False, have_outputs=False, flags=Block.flags, block_id=key
+ have_inputs=False, have_outputs=False, flags=flags, block_id=key
)
inputs_data = [dict(domain='stream', dtype='', direction='sink', id="0")]
@@ -40,10 +42,12 @@ class VirtualSource(Block):
key = 'virtual_source'
label = 'Virtual Source'
+ flags = Block.flags
+ flags.set('cpp')
parameters_data = build_params(
params_raw=[dict(label='Stream ID', id='stream_id', dtype='stream_id')],
- have_inputs=False, have_outputs=False, flags=Block.flags, block_id=key
+ have_inputs=False, have_outputs=False, flags=flags, block_id=key
)
outputs_data = [dict(domain='stream', dtype='', direction='source', id="0")]