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)), ])
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)), ])
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'), ])
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), ])
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)
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)
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)
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))])
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)))
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)
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'), ])
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)))
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'), ])
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)'), ])
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), ])
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), ])
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), ])
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)
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)
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)
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)
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'), ])
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)])
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)
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'), ])
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)), ])
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'), ])
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))])
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)