diff options
author | Terry May <terrydmay@gmail.com> | 2019-09-09 19:45:41 -0400 |
---|---|---|
committer | Martin Braun <martin@gnuradio.org> | 2020-02-18 22:04:15 -0800 |
commit | 64ee803068269fe3b9563fd415c420fb513a1c9b (patch) | |
tree | d27e9b5560b5bb4377f964e39772cd1395a7bff0 /grc/core/blocks | |
parent | 012870af22ae873b3b998691de8e81752179d266 (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.py | 2 | ||||
-rw-r--r-- | grc/core/blocks/block.py | 130 | ||||
-rw-r--r-- | grc/core/blocks/virtual.py | 8 |
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")] |