Skip to content

New language bindings generation

CppBind allows users to add a new supported language if they already have code and type converter snippets (look here for more detailed information about snippets usage). CppBind deduces the list of supported languages from the rules section info defined inside project config files. Thus, to add a new language to that list, users need to make their own code snippets, type converter snippets and define them under the rules section. To add a new language, the user doesn't need to change the CppBind source code; it can be done by project config files.

Here are the examples for snippets and config files for virtual my_lang language:

# after this macros `class_start_comment`, `class_end_comment`, `method_comment` and `register_method_arg` are available in this file
var_macros: &var_macros
  !concat
  - !include shareable_macros/code_snippets_macros.yaml&method_macros
  - !include shareable_macros/code_snippets_macros.yaml&class_macros.class_start
  - !include shareable_macros/code_snippets_macros.yaml&class_macros.class_end

# code snippets for file
file:
  my_lang:
    file_path: |
      {{"my_lang" + pat_sep + [vars.file]|map('replace', '.', pat_sep)|path_join}}.my_lang
    scopes:
      - body
    content: |
      {%- do my_lang.validate_default_helper_module() -%}
      {{body}}{{cppbind_helper.NEW_LINE}}

# code snippets for class
class:
  my_lang:
    body:
      scopes:
        - body
      content:
        !concat
        - *var_macros
        - |
          {{class_start_comment(vars.name)}}
          public class {{vars.name}}  {

            // body of function
            {{body|string|indent}}
          }
          {{class_end_comment(vars.name)}}

# code snippets for function
method:
  my_lang:
    # example of snippet call which doesn't have source and target defined
    body:
      !concat
      - *var_macros
      - |
        {%- set comma = joiner(', ') -%}
        {{method_comment(vars.name)}}
        public function ({%- for arg in cxx.args -%}{{comma()}}{{arg.name}}: {{get_type_converter(arg.type).my_lang.target_type_name}}{%- endfor -%}) {

          {%- set args_list = [] -%}
          {%- for arg in cxx.args %}
          {%-   set arg_converter = get_type_converter(arg.type) %}
          {#    calling shareable macro which modifies macro arguments in order to use it later -#}
                {{register_method_arg(args_list, arg)}}
          {%-   if arg_converter.my_section is defined %}
              {{arg_converter.my_section.snippet(arg.name)}}
          {%- endif %}

            {{arg_converter.my_lang_to_c.snippet(arg.name)}}
          {%- endfor %}
          // arg names -> {{args_list}}

        }
# type converter section for 'int'
int:
  # type info specifications
  types:
    c: int
    my_lang: myLangInt
  # converters section
  converters:
    # a section example without source and target definitions
    my_section: |
      // Calling a section without source and target attributes
    # a section example with source and target specifications
    my_lang_to_c:
      source: my_lang
      target: c
      snippet:
        !concat
        - !include shareable_macros/types_converter_macros.yaml&converter_comment_macro
        -  |

          // Calling converter for int type from my_lang to c
          {{put_type_comment(name)}}
          assign {{target_name}} = int({{name}})

# type converter section for custom object
$Object:
  types:
    my_lang: myLangPointer
    c: void*
  converters:
    my_lang_to_c:
      !concat
      - !include shareable_macros/types_converter_macros.yaml&converter_comment_macro
      - |

        // Calling converter for object type from my_lang to c
        {{put_type_comment(name)}}
        assign {{target_name}} = Pointer({{name}}.self)

# for mac
std::__1::map:
  std::map

# type converter section for std::map
std::map:
  types:
    my_lang: "myLangDict<{{get_type_converter(template_args[0]).my_lang.target_type_name}}, {{get_type_converter(template_args[1]).my_lang.target_type_name}}>"
    c: CppBindCDataMap
  converters:
    my_lang_to_c:
      !concat
      - !include shareable_macros/types_converter_macros.yaml&converter_comment_macro
      - |
        {%- set arg0_converter = get_type_converter(template_args[0]).my_lang_to_c -%}
        {%- set arg1_converter = get_type_converter(template_args[1]).my_lang_to_c -%}
        // Calling converter for std::map
        {{put_type_comment(name)}}
        var {{target_name}} = {{target_type_name}}()
        {{target_name}}.keys = Pointer(_key_{{target_name}})
        {{target_name}}.values = Pointer(_val_{{target_name}})
        {{target_name}}.size = myLangInt({{name}}.count)
        var _i_{{name}} = 0
        for (key_{{name}}, val_{{name}}) in {{name}} {
            {{arg0_converter.snippet('key_{}'.format(name))|indent}}
            {{arg1_converter.snippet('val_{}'.format(name))|indent}}
            _key_{{target_name}}[_i_{{name}}] = {{arg0_converter.converted_name('key_{}'.format(name))}}
            _val_{{target_name}}[_i_{{name}}] = {{arg1_converter.converted_name('val_{}'.format(name))}}
            _i_{{name}} += 1
        }

The above-described snippet files have minimum content to generate dummy bindings for class and function.

rules:
    my_lang.code_snippets:
        !join
        - !include my_lang_snippets/code_snippets.yaml
        - !include my_lang_snippets/custom_section_snippets.yaml

    my_lang.type_converters:
        !include my_lang_snippets/types.yaml

vars:
    src_glob:
        - cxx/example.hpp
    mac.clang_args:
        - --sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk

var_def:
    !include my_lang_snippets/my_lang_var_def.yaml

Here we included code snippets, type converter snippets, variable definitions, and defined some variables for the root node.

After these preparations, the tool is ready to be run for a new my_lang language. If the user wants to generate meaningful bindings with the correct target language syntax, they need to define accurate code snippets for class, function, and other cxx entities, and also must define type converter snippets for all the types that the user wants to use.


Last update: December 1, 2022