Esempio n. 1
0
    def type_internal_name(self, type):
        """
        Python specific helper, to get the internal name of a type that is
        wrapped.

        :param CompiledType type: The type for which we want to get the
            internal name.
        :rtype: str
        """
        def ctype_type(name):
            return "ctypes.{}".format(name)

        def wrapped_type(name):
            return "_{}".format(name)

        return dispatch_on_type(type, [
            (T.BoolType, lambda _: ctype_type('c_uint8')),
            (T.LongType, lambda _: ctype_type('c_int')),
            (T.EnvRebindingsType, lambda _: 'EnvRebindings._c_type'),
            (T.TokenType, lambda _: 'Token'),
            (T.SymbolType, lambda _: wrapped_type('text')),
            (T.AnalysisUnitType, lambda _: 'AnalysisUnit._c_type'),
            (T.AnalysisUnitKind, lambda _: ctype_type('c_uint')),
            (ct.ASTNodeType, lambda _: '_ASTNodeExtension.c_type'),
            (ct.ArrayType,
             lambda cls: '{}._c_type'.format(self.array_wrapper(cls))),
            (ct.EntityType,
             lambda _: '{}._c_type'.format(ct.T.entity.name.camel)),
            (ct.StructType, lambda _: '{}._c_type'.format(type.name.camel)),
        ])
Esempio n. 2
0
    def c_value_type(self, type, from_module=None):
        """
        Return the name of the type to use in the C API for ``type``. This
        is the type of a c value.

        :param CompiledType type: The type for which we want to get the C type
            name.
        :param CompiledType from_module: Module from which we want to access
            the name.
        :rtype: str
        """
        if not type.is_entity_type and from_module == type:
            return "c_type"

        return dispatch_on_type(type, [
            (T.Bool, lambda _: 'bool'),
            (T.Int, lambda _: 'int'),
            (T.Character, lambda _: 'string'),
            (T.Token,
             lambda t: '{}.token structure'.format(self.module_name(t))),
            (T.Symbol, lambda t: '{}.t structure'.format(self.module_name(t))),
            (ct.EnumType, lambda t: self.type_public_name(t)),
            (ct.ASTNodeType, lambda _: 'BareNode.t'),
            (ct.EntityType,
             lambda t: '{}.t structure'.format(self.struct_name(t))),
            (T.AnalysisUnit, lambda t: '{}.t'.format(self.struct_name(t))),
            (ct.ArrayType,
             lambda t: '{}.t structure ptr'.format(self.struct_name(t))),
            (ct.StructType,
             lambda t: '{}.t structure'.format(self.struct_name(t))),
            (T.BigInt, lambda _: 'unit ptr'),
            (T.EnvRebindings, lambda t: self.type_public_name(t)),
        ])
Esempio n. 3
0
    def type_public_name(self, type, from_module=None):
        """
        Return the public API name for a given CompiledType instance.

        :param CompiledType type: The type for which we want to get the name.
        :param CompiledType from_module: Module from which we want to access
            the name.
        :rtype: str
        """
        if from_module == type:
            return "t"

        return dispatch_on_type(type, [
            (T.Bool, lambda _: 'bool'),
            (T.Int, lambda _: 'int'),
            (T.Character, lambda _: 'string'),
            (T.Token, lambda t: '{}.t'.format(self.module_name(t))),
            (T.Symbol, lambda _: 'string'),
            (ct.EnumType, lambda t: '{}.t'.format(self.module_name(t))),
            (ct.ASTNodeType, lambda t: self.type_public_name(t.entity)),
            (ct.EntityType, lambda t: "{}.t".format(self.module_name(t))),
            (T.AnalysisUnit, lambda t: "{}.t".format(t.api_name)),
            (ct.ArrayType, lambda t: 'string' if t.is_string_type else
             '{} list'.format(self.type_public_name(type.element_type))),
            (ct.StructType, lambda _: "{}.t".format(type.api_name.camel)),
            (T.BigInt, lambda t: '{}.t'.format(self.module_name(t))),
            (T.EnvRebindings, lambda _: 'Rebindings.t'),
        ])
Esempio n. 4
0
    def is_struct(self, type, from_module=None):
        """
        Return true if the given type is defined as a ctypes structure without
        a view.

        :param CompiledType type: Type we want to test.
        :param ct.ASTNodeType from_module: The field is assumed to be accessed
            within this module.
        :rtype: str
        """
        if not type.is_entity_type and from_module == type:
            return "c_type"

        return dispatch_on_type(type, [
            (T.Bool, lambda _: False),
            (T.Int, lambda _: False),
            (T.Character, lambda _: False),
            (T.Token, lambda _: True),
            (T.Symbol, lambda _: False),
            (ct.EnumType, lambda _: False),
            (ct.ASTNodeType, lambda _: False),
            (ct.EntityType, lambda _: True),
            (T.AnalysisUnit, lambda _: True),
            (ct.ArrayType, lambda _: True),
            (ct.StructType, lambda _: True),
            (T.BigInt, lambda _: False),
            (T.EnvRebindings, lambda _: False),
        ])
Esempio n. 5
0
    def unwrap_value(self, value, type):
        """
        Given an expression for a high-level value and the associated type,
        return an other expression that yields the corresponding low-level
        value.

        :param str value: Expression yielding a high-level value.
        :param ct.CompiledType type: Type corresponding to the "value"
            expression.
        :rtype: str
        """
        return dispatch_on_type(
            type, [
                (T.AnalysisUnitType, lambda _: 'AnalysisUnit._unwrap({})'),
                (T.AnalysisUnitKind, lambda _: '_unwrap_unit_kind({})'),
                (ct.ASTNodeType, lambda _: '_ASTNodeExtension.unwrap({})'),
                (ct.EntityType, lambda _: '{}._unwrap({{}})'.format(
                    ct.T.root_node.kwless_raw_name.camel)),
                (T.BoolType, lambda _: 'bool({})'),
                (T.LongType, lambda _: 'int({})'),
                (ct.ArrayType,
                 lambda cls: '{}._unwrap({{}})'.format(self.array_wrapper(cls))
                 ),
                (ct.StructType,
                 lambda _: '{}._unwrap({{}})'.format(type.name.camel)),
                (T.SymbolType, lambda _: '_text._unwrap({})'),
                (T.EnvRebindingsType, lambda _: 'EnvRebindings._unwrap({})'),
            ],
            exception=TypeError(
                'Unhandled field type in the python binding'
                ' (unwrapping): {}'.format(type))).format(value)
Esempio n. 6
0
    def unwrap_value(self, value, type):
        """
        Given an expression for a high-level value and the associated type,
        return an other expression that yields the corresponding low-level
        value.

        :param str value: Expression yielding a high-level value.
        :param ct.CompiledType type: Type parameter. Type corresponding to the
            "value" expression.
        :rtype: str
        """
        return dispatch_on_type(type, [
            (ct.AnalysisUnitType, lambda _: '{}._c_value'),
            (ct.AnalysisUnitKind, lambda _: '_unwrap_unit_kind({})'),
            (ct.ASTNode, lambda _: '_unwrap_astnode({})'),
            (ct.BoolType, lambda _: 'bool({})'),
            (ct.LongType, lambda _: 'int({})'),
            (ct.EnumType, lambda _: '_unwrap_enum({{}}, str_to_{}, {})'.format(
                type.c_type(self.c_api_settings).name,
                type.name().camel
            )),
            (ct.Symbol, lambda _: '_text.unwrap({})'),
            (ct.LexicalEnvType, lambda _: '{}.unwrap()'),
        ], exception=TypeError(
            'Unhandled field type in the python binding '
            '(unwrapping): {}'.format(type)
        )).format(value)
Esempio n. 7
0
    def unwrap_value(self, value, type):
        """
        Given an expression for a high-level value and the associated type,
        return an other expression that yields the corresponding low-level
        value.

        :param str value: Expression yielding a high-level value.
        :param ct.CompiledType type: Type parameter. Type corresponding to the
            "value" expression.
        :rtype: str
        """
        return dispatch_on_type(type, [
            (ct.ASTNode, lambda _: '_unwrap_astnode({})'),
            (ct.BoolType, lambda _: 'bool({})'),
            (ct.LongType, lambda _: 'int({})'),
            (ct.EnumType, lambda _: '_unwrap_enum({{}}, str_to_{}, {})'.format(
                type.c_type(self.c_api_settings).name,
                type.name().camel
            )),
            (ct.Symbol, lambda _: '_text.unwrap({})'),
            (ct.LexicalEnvType, lambda _: '{}.unwrap()'),
        ], exception=TypeError(
            'Unhandled field type in the python binding '
            '(unwrapping): {}'.format(type)
        )).format(value)
Esempio n. 8
0
    def finalize_function(self, type):
        """
        Return the name of the finalization function if a value of the given
        type must be finalized. A value needs a finalization if it is
        completly converted to an OCaml value. This function is used
        when calling a C API function, where, we allocated a C value when
        unwrapping an OCaml value. Thus, we need to finalize it after the call
        to the C API function.

        :param CompiledType type: The type for which we want to get the
            finalization function name.
        :rtype: str
        """
        def dec_ref(type):
            if type.is_refcounted:
                return '{}.dec_ref'.format(self.struct_name(type))
            else:
                return None

        return dispatch_on_type(
            type,
            [(T.BigInt, lambda t: '{}.decref'.format(self.struct_name(t))),
             (ct.ASTNodeType, lambda _: None), (ct.EntityType, lambda _: None),
             (T.AnalysisUnit, lambda _: None),
             (ct.CompiledType, lambda t: dec_ref(t))])
Esempio n. 9
0
    def wrap_requires_context(self, type):
        """
        Returns true if the given type need the context to be wrapped in an
        OCaml value.

        :param ct.CompiledType type: Type for which we want to know if the
            context is needed.
        :rtype: bool
        """

        return dispatch_on_type(type, [
            (T.AnalysisUnit, lambda _: True),
            (ct.EnumType, lambda _: False),
            (ct.ASTNodeType, lambda _: False),
            (ct.EntityType, lambda _: True),
            (T.Token, lambda _: False),
            (T.Symbol, lambda t: False),
            (T.Bool, lambda _: False),
            (T.Int, lambda _: False),
            (T.Character, lambda _: False),
            (ct.ArrayType,
             lambda t: self.wrap_requires_context(t.element_type)),
            (ct.StructType, lambda t: any(
                self.wrap_requires_context(field.type)
                for field in t.get_fields())),
            (T.BigInt, lambda _: False),
            (T.EnvRebindings, lambda _: False),
        ],
                                exception=TypeError(
                                    'Unhandled field type in the OCaml binding'
                                    ' (wrapping): {}'.format(type)))
Esempio n. 10
0
    def wrap_value(self, value, type, from_field_access=False):
        """
        Given an expression for a low-level value and the associated type,
        return an other expression that yields the corresponding high-level
        value.

        :param str value: Expression yielding a low-level value.
        :param ct.CompiledType type: Type parameter. Type corresponding to
            the "value" expression.
        :param bool from_field_access: True if "value" is a record field
            access (False by default). This is a special case because of the
            way ctypes works.
        :rtype: str
        """
        value_suffix = '' if from_field_access else '.value'
        return dispatch_on_type(type, [
            (ct.ASTNode, lambda _: '_wrap_astnode({})'),
            (ct.SourceLocationRangeType, lambda _: '_wrap_sloc_range({})'),
            (ct.Token, lambda _: '{}'),
            (ct.Symbol, lambda _: '{}.wrap()'),
            (ct.BoolType, lambda _: 'bool({{}}{})'.format(value_suffix)),
            (ct.LongType, lambda _: '{{}}{}'.format(value_suffix)),
            (ct.EnumType, lambda _: '{}_to_str[{{}}{}]'.format(
                type.c_type(self.c_api_settings).name,
                value_suffix,
            )),
            (ct.ArrayType, lambda cls: '{}({{}})'.format(type.name().camel)),
            (ct.Struct, lambda _: '{}'),
            (ct.LexicalEnvType, lambda _: 'LexicalEnv.wrap({})'),
        ], exception=TypeError(
            'Unhandled field type in the python binding'
            '(wrapping): {}'.format(type)
        )).format(value)
Esempio n. 11
0
    def c_type(self, type):
        """
        Return the name of the type to use in the C API for ``type``.

        :param CompiledType type: The type for which we want to get the C type
            name.
        :rtype: str
        """
        def ctype_type(name):
            return 'ctypes.{}'.format(name)

        return dispatch_on_type(type, [
            (T.Bool, lambda _: ctype_type('c_uint8')),
            (T.Int, lambda _: ctype_type('c_int')),
            (T.Character, lambda _: ctype_type('c_uint32')),
            (T.EnvRebindings, lambda _: '_EnvRebindings_c_type'),
            (T.Token, lambda _: 'Token'),
            (T.Symbol, lambda _: '_symbol_type'),
            (T.AnalysisUnit, lambda _: 'AnalysisUnit._c_type'),
            (ct.EnumType, lambda _: ctype_type('c_int')),
            (ct.ASTNodeType, lambda _: '{}._node_c_type'.format(
                self.type_public_name(ct.T.root_node))),
            (ct.ArrayType, lambda cls:
                '{}.c_type'.format(self.array_wrapper(cls))),
            (T.entity_info, lambda _: '_EntityInfo_c_type'),
            (T.env_md, lambda _: '_Metadata_c_type'),
            (ct.EntityType, lambda _: '_Entity_c_type'),
            (ct.StructType, lambda _:
                '{}._c_type'.format(self.type_public_name(type))),
            (T.BigInt, lambda _: '_big_integer.c_type'),
        ])
Esempio n. 12
0
    def has_ctype_view(self, type):
        """
        Given a type, return true if it has a ctype view. Having a ctype view
        means that wrap and unwrap operations are not needed explicitely.

        :param ct.CompiledType type: The type to check.
        :rtype: bool
        """

        return dispatch_on_type(type, [
            (T.AnalysisUnit, lambda _: False),
            (ct.EnumType, lambda _: True),
            (ct.ASTNodeType, lambda _: True),
            (ct.EntityType, lambda _: False),
            (T.Token, lambda _: True),
            (T.Symbol, lambda _: False),
            (T.Bool, lambda _: True),
            (T.Int, lambda _: True),
            (T.Character, lambda _: True),
            (ct.ArrayType, lambda _: False),
            (ct.StructType, lambda _: False),
            (T.BigInt, lambda _: False),
            (T.EnvRebindings, lambda _: True),
        ],
                                exception=TypeError(
                                    'Unhandled field type in the OCaml binding'
                                    ' (has_ctype_view): {}'.format(type)))
Esempio n. 13
0
    def type_public_name(self, type: CompiledType) -> str:
        """
        Python specific helper. Return the public API name for a given
        CompiledType instance.

        :param type: The type for which we want to get the name.
        """
        return dispatch_on_type(type, [
            (T.Bool, lambda _: 'bool'),
            (T.Int, lambda _: 'int'),
            (T.Character, lambda _: 'str'),
            (T.String, lambda _: 'str'),
            (T.Token, lambda _: 'Token'),
            (T.Symbol, lambda _: 'str'),
            (ct.EnumType, lambda _: 'str'),
            (ct.ASTNodeType, lambda t: self.type_public_name(t.entity)),
            (ct.EntityType, lambda t: t.astnode.kwless_raw_name.camel),
            (T.AnalysisUnit, lambda t: t.api_name),
            (T.String, lambda _: 'str'),
            (ct.ArrayType, lambda _:
             ('List[{}]'.format(self.type_public_name(type.element_type)))),
            (ct.IteratorType, lambda _: type.api_name.camel),
            (ct.StructType, lambda _: type.api_name.camel),
            (T.BigInt, lambda _: 'int'),
        ])
Esempio n. 14
0
    def c_type(self, type, from_module=None):
        """
        Return the name of the OCaml ctypes value defining the type to use in
        the C API for ``type``. For ctypes, types passed to the foreign
        function that import a c function are values. This returns the
        associated value for the given type.

        :param CompiledType type: The type for which we want to get the C type
            name.
        :param CompiledType from_module: Module from which we want to access
            the name.
        :rtype: str
        """
        if not type.is_entity_type and from_module == type:
            return "c_type"

        return dispatch_on_type(type, [
            (T.Bool, lambda _: 'bool'),
            (T.Int, lambda _: 'int'),
            (T.Character, lambda t: '{}.c_type'.format(self.module_name(t))),
            (T.Token, lambda t: '{}.c_type'.format(self.module_name(t))),
            (T.Symbol, lambda t: '{}.c_type'.format(self.module_name(t))),
            (ct.EnumType, lambda t: '{}.c_type'.format(self.module_name(t))),
            (ct.ASTNodeType, lambda _: '(ptr void)'),
            (ct.EntityType, lambda t: '{}.c_type'.format(self.struct_name(t))),
            (T.AnalysisUnit,
             lambda t: '{}.c_type'.format(self.struct_name(t))),
            (ct.ArrayType, lambda t: '{}.c_type'.format(self.struct_name(t))),
            (ct.StructType, lambda t: "{}.c_type".format(self.struct_name(t))),
            (T.BigInt, lambda t: '{}.c_type'.format(self.module_name(t))),
            (T.EnvRebindings, lambda _: '(ptr void)'),
        ])
Esempio n. 15
0
    def type_internal_name(self, type):
        """
        Python specific helper, to get the internal name of a type that is
        wrapped.

        :param CompiledType type: Type parameter. The type for which we want to
            get the internal name.
        :rtype: str
        """
        def ctype_type(name):
            return "ctypes.{}".format(name)

        def wrapped_type(name):
            return "_{}".format(name)

        return dispatch_on_type(type, [
            (ct.BoolType, lambda _: ctype_type('c_uint8')),
            (ct.LongType, lambda _: ctype_type('c_long')),
            (ct.LexicalEnvType, lambda _: wrapped_type('lexical_env')),
            (ct.EnvRebindingsType, lambda _: wrapped_type('env_rebindings')),
            (ct.SourceLocationRangeType, lambda _: wrapped_type('SlocRange')),
            (ct.Token, lambda _: 'Token'),
            (ct.Symbol, lambda _: wrapped_type('text')),
            (ct.AnalysisUnitType, lambda _: wrapped_type('analysis_unit')),
            (ct.AnalysisUnitKind, lambda _: ctype_type('c_uint')),
            (ct.ASTNode, lambda _: wrapped_type('node')),
            (ct.EnumType, lambda _: ctype_type('c_uint')),
            (ct.ArrayType, lambda cls: wrapped_type(cls.name().camel)),
            (ct.Struct, lambda _: type.name().camel),
        ])
Esempio n. 16
0
    def type_internal_name(self, type):
        """
        Python specific helper, to get the internal name of a type that is
        wrapped.

        :param CompiledType type: Type parameter. The type for which we want to
            get the internal name.
        :rtype: str
        """
        def ctype_type(name):
            return "ctypes.{}".format(name)

        def wrapped_type(name):
            return "_{}".format(name)

        return dispatch_on_type(type, [
            (ct.BoolType, lambda _: ctype_type('c_uint8')),
            (ct.LongType, lambda _: ctype_type('c_long')),
            (ct.LexicalEnvType, lambda _: wrapped_type('lexical_env')),
            (ct.SourceLocationRangeType, lambda _: wrapped_type('SlocRange')),
            (ct.Token, lambda _: 'Token'),
            (ct.Symbol, lambda _: wrapped_type('text')),
            (ct.ASTNode, lambda _: wrapped_type('node')),
            (ct.EnumType, lambda _: ctype_type('c_uint')),
            (ct.ArrayType, lambda cls: wrapped_type(cls.name().camel)),
            (ct.Struct, lambda _: type.name().camel),
        ])
Esempio n. 17
0
    def node_name(self, type: Union[ct.EntityType, ct.ASTNodeType]) -> str:
        """
        Returns the OCaml name for an ASTNodeType or an EntityType.

        :param type: Type we want to get the name.
        """
        return dispatch_on_type(type, [
            (ct.ASTNodeType, lambda t: self.node_name(t.entity)),
            (ct.EntityType, lambda t: t.astnode.kwless_raw_name.camel),
        ])
Esempio n. 18
0
    def unwrap_value(self,
                     value: str,
                     type: CompiledType,
                     context: str) -> str:
        """
        Given an expression for a high-level value and the associated type,
        return an other expression that yields the corresponding low-level
        value.

        Note that because of the way we handle resource (de)allocation, for
        some types, this does *not* yield a value that can be passed to C
        functions: for instance, arrays will yield an instance of a _BaseArray
        subclass. In order to get the C value, use the ``extract_c_value``
        method:

        >>> py_value_expr = ...
        >>> c_holder_expr = pyapi.unwrap_value(py_value_expr, my_type, context)
        >>> c_value_expr = pyapi.extract_c_value(c_holder_expr, my_type)

        :param value: Expression yielding a high-level value.
        :param type: Type corresponding to the "value" expression.
        :param context: Expression to return a C value for the context.  This
            is required to unwrap some types of value.
        """
        context_arg = (', {}'.format(context)
                       if type.conversion_requires_context else '')
        return dispatch_on_type(type, [
            (T.AnalysisUnit, lambda _: 'AnalysisUnit._unwrap({value})'),
            (ct.EnumType, lambda _:
                '{}._unwrap({{value}})'.format(
                    cast(ct.EnumType, type).py_helper
                )),
            (ct.ASTNodeType, lambda _: '{value}._node_c_value'),
            (ct.EntityType, lambda _: '{}._unwrap({{value}})'.format(
                self.type_public_name(ct.T.root_node))),
            (T.Bool, lambda _: 'bool({value})'),
            (T.Int, lambda _: 'int({value})'),
            (T.Character, lambda _: 'ord({value})'),
            (ct.ArrayType, lambda cls:
                '{}.unwrap({{value}}{{context}})'
                .format(self.array_wrapper(cls))),
            (ct.StructType, lambda _:
                '{}._unwrap({{value}}{{context}})'
                .format(self.type_public_name(type))),
            (T.Token, lambda _: '{value}'),
            (T.Symbol, lambda _: '_symbol_type.unwrap({value}{context})'),
            (T.BigInt, lambda _: '_big_integer.unwrap({value})'),
        ], exception=TypeError(
            'Unhandled field type in the python binding'
            ' (unwrapping): {}'.format(type)
        )).format(value=value, context=context_arg)
Esempio n. 19
0
    def wrap_value(self, value, type, from_field_access=False, inc_ref=False):
        """
        Given an expression for a low-level value and the associated type,
        return an other expression that yields the corresponding high-level
        value.

        :param str value: Expression yielding a low-level value.
        :param ct.CompiledType type: Type parameter. Type corresponding to
            the "value" expression.
        :param bool from_field_access: True if "value" is a record field
            access (False by default). This is a special case because of the
            way ctypes works.
        :param bool inc_ref: If True, this conversion also creates a new
            ownership share for "value".
        :rtype: str
        """

        # TODO: handle all types
        assert (not inc_ref
                or not type.is_refcounted()
                or issubclass(type, ct.ArrayType)), (
            'Incrementing ref-count of {} in the Python API is not handled'
            ' yet'.format(type.name())
        )

        value_suffix = '' if from_field_access else '.value'
        return dispatch_on_type(type, [
            (ct.AnalysisUnitType, lambda _: 'AnalysisUnit({})'),
            (ct.AnalysisUnitKind, lambda _: 'unit_kind_to_str[{}]'),
            (ct.ASTNode, lambda _: '_wrap_astnode({})'),
            (ct.SourceLocationRangeType, lambda _: '_wrap_sloc_range({})'),
            (ct.Token, lambda _: '{}'),
            (ct.Symbol, lambda _: '{}.wrap()'),
            (ct.BoolType, lambda _: 'bool({{}}{})'.format(value_suffix)),
            (ct.LongType, lambda _: '{{}}{}'.format(value_suffix)),
            (ct.EnumType, lambda _: '{}_to_str[{{}}{}]'.format(
                type.c_type(self.c_api_settings).name,
                value_suffix,
            )),
            (ct.ArrayType, lambda cls: '{}({{}}, inc_ref={})'.format(
                type.name().camel,
                inc_ref
            )),
            (ct.Struct, lambda _: '{}'),
            (ct.LexicalEnvType, lambda _: 'LexicalEnv.wrap({})'),
            (ct.EnvRebindingsType, lambda _: 'EnvRebindings.wrap({})'),
        ], exception=TypeError(
            'Unhandled field type in the python binding'
            '(wrapping): {}'.format(type)
        )).format(value)
 def wrap_value(self, value, type):
     return dispatch_on_type(type, [
         (ct.ASTNode, lambda _: '_wrap_astnode({})'),
         (ct.SourceLocationRangeType, lambda _: '_wrap_sloc_range({})'),
         (ct.Token, lambda _: 'Token({})'),
         (ct.BoolType, lambda _: 'bool({}.value)'),
         (ct.LongType, lambda _: '{}.value'),
         (ct.EnumType, lambda _: '{}_to_str[{{}}.value]'.format(
             type.c_type(self.c_api_settings).name)),
         (ct.ArrayType, lambda cls: '{}({{}})'.format(type.name().camel)),
         (ct.Struct, lambda _: '{}'),
     ], exception_msg='Unhandled field type'
                      ' in the python binding: {}'.format(type)
     ).format(value)
Esempio n. 21
0
    def wrap_value(self, value, type, from_field_access=False, inc_ref=False):
        """
        Given an expression for a low-level value and the associated type,
        return an other expression that yields the corresponding high-level
        value.

        :param str value: Expression yielding a low-level value.
        :param ct.CompiledType type: Type corresponding to the "value"
            expression.
        :param bool from_field_access: True if "value" is a record field or
            array item access (False by default). This is a special case
            because of the way ctypes works.
        :param bool inc_ref: If True, this conversion also creates a new
            ownership share for "value".
        :rtype: str
        """

        # TODO: handle all types
        assert (not inc_ref or not type.is_refcounted or isinstance(
            type, (ct.ArrayType, ct.StructType))), (
                'Incrementing ref-count of {} in the Python API is not handled'
                ' yet'.format(type.name))

        value_suffix = '' if from_field_access else '.value'
        return dispatch_on_type(
            type, [
                (T.AnalysisUnitType, lambda _: 'AnalysisUnit._wrap({})'),
                (T.AnalysisUnitKind, lambda _: '_unit_kind_to_str[{}]'),
                (ct.ASTNodeType,
                 lambda _: '_ASTNodeExtension.get_or_create({})'),
                (ct.EntityType, lambda _: '{}._wrap({{}})'.format(
                    ct.T.root_node.kwless_raw_name.camel)),
                (T.TokenType, lambda _: '{}'),
                (T.SymbolType, lambda _: '{}._wrap()'),
                (T.BoolType, lambda _: 'bool({{}}{})'.format(value_suffix)),
                (T.LongType, lambda _: '{{}}{}'.format(value_suffix)),
                (ct.EnumType, lambda _: '{}_to_str[{{}}{}]'.format(
                    type.c_type(self.c_api_settings).name,
                    value_suffix,
                )),
                (ct.ArrayType, lambda cls: '{}({{}}, inc_ref={})'.
                 format(self.array_wrapper(type), inc_ref)),
                (ct.StructType, lambda _: '{}._wrap({{}}, inc_ref={})'.
                 format(type.name.camel, inc_ref)),
                (T.EnvRebindingsType, lambda _: 'EnvRebindings._wrap({})'),
            ],
            exception=TypeError('Unhandled field type in the python binding'
                                ' (wrapping): {}'.format(type))).format(value)
Esempio n. 22
0
def print_field(context, file, struct, field):
    prefixes = []
    if field.is_private:
        prefixes.append('<span class="private">private</span>')
    prefixes.append('<span class="kw">{}</span>'.format(
        dispatch_on_type(type(field), (
            (compiled_types.AbstractField, lambda _: 'field'),
            (expressions.PropertyDef, lambda _: 'property')
        )),
    ))

    is_inherited = field.struct != struct

    inherit_note = (
        ' [inherited from {}]'.format(field_ref(field))
        if is_inherited else ''
    )

    div_classes = ['node_wrapper']
    if is_inherited:
        div_classes.append('field_inherited')
    if field.is_private:
        div_classes.append('field_private')

    print('<div class="{}">'.format(' '.join(div_classes)), file=file)
    print(
        '<dt>{prefixes}'
        ' <span class="def" id="{node}-{field}">{field}</span>'
        ' : {type}{inherit_note}</dt>'.format(
            prefixes=' '.join(prefixes),
            node=struct.dsl_name,
            field=field.name.lower,
            type=(
                astnode_ref(field.type)
                if field.type in context.astnode_types else
                field.type.dsl_name
            ),
            inherit_note=inherit_note
        ),
        file=file
    )
    # Don't repeat the documentation for inheritted fields
    if field.struct == struct:
        print('<dd>{}</dd>'.format(format_doc(field)), file=file)

    print('</div>', file=file)
Esempio n. 23
0
    def module_name(self, type: ct.CompiledType) -> str:
        """
        Returns the OCaml module containing the definition for the given type.

        :param type: Type we want to get the module name.
        """

        return dispatch_on_type(type, [
            (ct.EnumType, lambda enum: enum.api_name.camel),
            (T.Token, lambda _: 'Token'),
            (T.Symbol, lambda _: 'Symbol'),
            (T.Character, lambda _: 'Character'),
            (T.String, lambda _: 'StringType'),
            (ct.ArrayType, lambda t: t.api_name.camel),
            (ct.IteratorType, lambda t: t.api_name.camel),
            (ct.StructType, lambda t: t.api_name.camel),
            (T.BigInt, lambda t: 'BigInteger'),
        ])
Esempio n. 24
0
    def is_empty_type(self, type: TypeOrPlaceholder) -> bool:
        """
        Test if the given type is an empty type. An empty type is a structure
        that does not contain any field, or the fields are also
        empty structs. An empty type can also be an ASTNodeType that does not
        contain any concrete subclasses. We Want to check this because we
        cannot write empty sum types or empty structures in OCaml.

        :param type: The type we want to check if it is empty.
        """
        return dispatch_on_type(
            type,
            [(ct.ASTNodeType, lambda t: len(t.concrete_subclasses) == 0),
             (ct.EntityType, lambda t: self.is_empty_type(t.astnode)),
             (ct.ArrayType, lambda t: self.is_empty_type(t.element_type)),
             (ct.StructType, lambda t: all(
                 self.is_empty_type(field.type) for field in t.get_fields())),
             (ct.CompiledType, lambda _: False)])
Esempio n. 25
0
    def wrap_value(self,
                   value: str,
                   type: CompiledType,
                   from_field_access: bool = False) -> str:
        """
        Given an expression for a low-level value and the associated type,
        return an other expression that yields the corresponding high-level
        value.

        :param value: Expression yielding a low-level value.
        :param type: Type corresponding to the "value" expression.
        :param from_field_access: True if "value" is a record field or array
            item access (False by default). This is a special case because of
            the way ctypes works.
        """
        value_suffix = '' if from_field_access else '.value'
        return dispatch_on_type(
            type, [
                (T.AnalysisUnit, lambda _: 'AnalysisUnit._wrap({})'),
                (ct.EnumType, lambda _: '{}._wrap({{}})'.format(
                    cast(ct.EnumType, type).py_helper)),
                (ct.ASTNodeType, lambda _: '{}._wrap_bare_node({{}})'.format(
                    self.type_public_name(ct.T.root_node))),
                (ct.EntityType, lambda _: '{}._wrap({{}})'.
                 format(self.type_public_name(ct.T.root_node))),
                (T.Token, lambda _: '{}'),
                (T.Symbol, lambda _: '_symbol_type.wrap({})'),
                (T.Bool, lambda _: 'bool({{}}{})'.format(value_suffix)),
                (T.Int, lambda _: '{{}}{}'.format(value_suffix)),
                (T.Character, lambda _: '_py2to3.unicode_character({{}}{})'.
                 format(value_suffix)),
                (ct.ArrayType, lambda _: '{}.wrap({{}}, {})'.
                 format(self.array_wrapper(cast(ArrayType, type)),
                        from_field_access)),
                (ct.IteratorType, lambda _: '{}._wrap({{}})'
                 .format(self.iterator_wrapper(cast(IteratorType, type)))),
                (ct.StructType,
                 lambda _: '{}._wrap({{}})'.format(self.type_public_name(type))
                 ),
                (T.BigInt, lambda _: '_big_integer.wrap({})'),
            ],
            exception=TypeError('Unhandled field type in the python binding'
                                ' (wrapping): {}'.format(type))).format(value)
Esempio n. 26
0
    def module_name(self, type: ct.CompiledType) -> str:
        """
        Returns the OCaml module containing the definition for the given type.

        :param type: Type we want to get the module name.
        """

        return dispatch_on_type(type, [
            (ct.EnumType, lambda enum: enum.api_name.camel),
            (T.Token, lambda _: 'Token'),
            (T.Symbol, lambda _: 'Symbol'),
            (T.Character, lambda _: 'Character'),
            (ct.ASTNodeType, lambda t: self.module_name(t.entity)),
            (ct.EntityType, lambda t: '{}Type'.format(self.node_name(t))),
            (T.AnalysisUnit, lambda t: t.api_name.camel),
            (ct.ArrayType, lambda t: t.api_name.camel),
            (ct.StructType, lambda t: t.api_name.camel),
            (T.BigInt, lambda t: 'BigInteger'),
        ])
Esempio n. 27
0
    def struct_name(self, type: ct.CompiledType) -> str:
        """
        Returns the OCaml module containing the low-level structure for the
        given type.

        :param type: Type we want to get the module name.
        """

        return dispatch_on_type(type, [
            (ct.EnumType, lambda t: self.module_name(t)),
            (T.Token, lambda t: self.module_name(t)),
            (T.Symbol, lambda t: self.module_name(t)),
            (ct.ASTNodeType, lambda t: self.module_name(t.entity)),
            (ct.EntityType, lambda _: 'EntityStruct'),
            (T.AnalysisUnit, lambda t: '{}Struct'.format(self.module_name(t))),
            (ct.ArrayType, lambda t: '{}Struct'.format(self.array_wrapper(t))),
            (ct.StructType, lambda t: '{}Struct'.format(self.module_name(t))),
            (T.BigInt, lambda t: self.module_name(t)),
        ])
Esempio n. 28
0
    def type_public_name(self,
                         type: ct.CompiledType,
                         from_module: Optional[ct.CompiledType] = None) -> str:
        """
        Return the public API name for a given CompiledType instance.

        :param type: The type for which we want to get the name.
        :param from_module: Module from which we want to access the name.
        """
        def from_module_name(type: ct.CompiledType) -> str:
            if from_module == type:
                return "t"
            else:
                return "{}.t".format(self.module_name(type))

        def entity_type_name(type: ct.EntityType) -> str:
            name = type.astnode.kwless_raw_name.lower

            # Add _node to the name if it is an existing ocaml keyword
            return name + "_node" if name in ocaml_keywords else name

        return dispatch_on_type(type, [
            (T.Bool, lambda _: 'bool'),
            (T.Int, lambda _: 'int'),
            (T.Token, lambda t: from_module_name(t)),
            (T.Symbol, lambda _: 'string'),
            (ct.EnumType, lambda t: from_module_name(t)),
            (ct.ASTNodeType, lambda t: self.type_public_name(t.entity)),
            (ct.EntityType, lambda t: entity_type_name(t)),
            (T.AnalysisUnit, lambda t: t.api_name.lower),
            (T.entity_info, lambda t: t.api_name.lower),
            (T.env_md, lambda t: t.api_name.lower),
            (T.Character, lambda _: 'string'),
            (T.String, lambda _: 'string'),
            (ct.ArrayType, lambda t: '{} list'.format(
                self.type_public_name(type.element_type))),
            (ct.IteratorType, lambda t: 'unit'),
            (ct.StructType, lambda t: from_module_name(t)),
            (T.BigInt, lambda t: from_module_name(t)),
            (T.EnvRebindings, lambda _: 'Rebindings.t'),
        ])
Esempio n. 29
0
    def convert_function_name(
            self,
            type: ct.CompiledType,
            convert: str,
            convert_ast_node: Callable[[ct.ASTNodeType], str],
            from_module: Optional[ct.ASTNodeType] = None) -> str:
        """
        Return the wrap/unwrap function name used to wrap/unwrap the given
        type. The wrap or unwrap is selected with the given convert string.
        Call the given convert function on an ASTNodeType.

        :param type: The type for which we want the conversion function.
        :param convert: Conversion function name, either wrap, or unwrap.
        :param convert_ast_node: Function called to get the name of the
            conversion function to use for an ASTNodeType.
        :param from_module: The module from which we want to get the name of
            the conversion function. This is useful because if the module is
            the same as the type, then we don't want to prefix it with the
            module name.
        """
        def from_module_name(type: ct.CompiledType) -> str:
            if from_module == type:
                return convert
            else:
                return "{}.{}".format(self.module_name(type), convert)

        def plain_name(type: ct.CompiledType) -> str:
            return "{}_{}".format(convert, type.api_name.lower)

        return dispatch_on_type(
            type, [(ct.ASTNodeType, lambda t: convert_ast_node(t)),
                   (ct.EntityType, lambda t: self.convert_function_name(
                       t.astnode, convert, convert_ast_node, from_module)),
                   (T.AnalysisUnit, lambda t: plain_name(t)),
                   (T.entity_info, lambda t: plain_name(t)),
                   (T.env_md, lambda t: plain_name(t)),
                   (ct.CompiledType, lambda t: from_module_name(t))])
Esempio n. 30
0
    def unwrap_value(self, value, type, context):
        """
        Given an expression for a low-level value and the associated type,
        return an other expression that yields the corresponding high-level
        value.

        :param str value: Expression yielding a low-level value.
        :param ct.CompiledType type: Type corresponding to the "value"
            expression.
        :rtype: str
        """
        def from_module(typ):
            context_arg = ('{} '.format(context)
                           if type.conversion_requires_context else '')

            return "{}.unwrap {}({{}})".format(self.module_name(typ),
                                               context_arg)

        return dispatch_on_type(
            type, [
                (T.AnalysisUnit, lambda t: from_module(t)),
                (ct.EnumType, lambda t: from_module(t)),
                (ct.ASTNodeType, lambda _: '{}'),
                (ct.EntityType, lambda _: from_module(T.root_node)),
                (T.Token, lambda _: '{}'),
                (T.Symbol, lambda t: from_module(t)),
                (T.Bool, lambda _: '{}'),
                (T.Int, lambda _: '{}'),
                (T.Character, lambda _: '{}'),
                (ct.ArrayType, lambda t: from_module(t)),
                (ct.StructType, lambda t: from_module(t)),
                (T.BigInt, lambda _: '{}'),
                (T.EnvRebindings, lambda _: '{}'),
            ],
            exception=TypeError('Unhandled field type in the python binding'
                                ' (wrapping): {}'.format(type))).format(value)