Type System API¶
The type system manages mappings between IR types and target language types, ensuring consistent type translation across all generators.
Overview¶
The type system provides:
- Type Registry: Central repository for type mappings
- Built-in Types: Standard primitive type mappings
- Custom Types: User-defined type mappings
- Type Validation: Ensure types are supported
- Caching: O(1) lookup performance
Type Registry¶
polyglot_ffi.type_system.registry.TypeRegistry
¶
Registry for type mappings between IR types and target language types.
Example usage
registry = TypeRegistry() registry.register_primitive("string", { "ocaml": "string", "python": "str", "c": "char*" })
python_type = registry.get_mapping("string", "python") # Returns "str"
Source code in src/polyglot_ffi/type_system/registry.py
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | |
Functions¶
register_primitive(ir_type_name, mappings)
¶
Register a primitive type mapping.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ir_type_name
|
str
|
Name of the IR type (e.g., "string", "int") |
required |
mappings
|
Dict[str, str]
|
Dictionary of language -> type_name mappings |
required |
Source code in src/polyglot_ffi/type_system/registry.py
register_converter(ir_type_name, target_lang, converter)
¶
Register a custom type converter function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ir_type_name
|
str
|
Name of the IR type |
required |
target_lang
|
str
|
Target language |
required |
converter
|
Callable[[IRType], str]
|
Function that takes IRType and returns type string |
required |
Source code in src/polyglot_ffi/type_system/registry.py
get_mapping(ir_type, target_lang)
¶
Get the type mapping for a target language.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ir_type
|
IRType
|
The IR type to map |
required |
target_lang
|
str
|
Target language (e.g., "python", "c", "rust") |
required |
Returns:
| Type | Description |
|---|---|
str
|
Type string in the target language |
Raises:
| Type | Description |
|---|---|
TypeMappingError
|
If no mapping exists |
Source code in src/polyglot_ffi/type_system/registry.py
validate(ir_type, target_lang)
¶
Check if a type can be mapped to the target language.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ir_type
|
IRType
|
The IR type to validate |
required |
target_lang
|
str
|
Target language |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if mapping exists, False otherwise |
Source code in src/polyglot_ffi/type_system/registry.py
Getting the Registry¶
from polyglot_ffi.type_system.registry import get_default_registry
# Get the global registry (lazy-initialized)
registry = get_default_registry()
Basic Usage¶
from polyglot_ffi.ir.types import STRING, INT, ir_option
from polyglot_ffi.type_system.registry import get_default_registry
registry = get_default_registry()
# Map primitive types
registry.get_mapping(STRING, "python") # "str"
registry.get_mapping(INT, "python") # "int"
registry.get_mapping(STRING, "rust") # "String"
registry.get_mapping(INT, "c") # "int64_t"
# Map complex types
opt_string = ir_option(STRING)
registry.get_mapping(opt_string, "python") # "Optional[str]"
registry.get_mapping(opt_string, "rust") # "Option<String>"
Built-in Type Mappings¶
The registry comes pre-loaded with standard type mappings:
String Types¶
| IR Type | Python | Rust | OCaml | C |
|---|---|---|---|---|
string |
str |
String |
string |
char* |
Integer Types¶
| IR Type | Python | Rust | OCaml | C |
|---|---|---|---|---|
int |
int |
i64 |
int |
int64_t |
Float Types¶
| IR Type | Python | Rust | OCaml | C |
|---|---|---|---|---|
float |
float |
f64 |
float |
double |
Boolean Types¶
| IR Type | Python | Rust | OCaml | C |
|---|---|---|---|---|
bool |
bool |
bool |
bool |
int |
Unit Types¶
| IR Type | Python | Rust | OCaml | C |
|---|---|---|---|---|
unit |
None |
() |
unit |
void |
Complex Type Mappings¶
Option Types¶
from polyglot_ffi.ir.types import STRING, ir_option
opt_string = ir_option(STRING)
registry.get_mapping(opt_string, "python") # "Optional[str]"
registry.get_mapping(opt_string, "rust") # "Option<String>"
registry.get_mapping(opt_string, "ocaml") # "string option"
List Types¶
from polyglot_ffi.ir.types import INT, ir_list
int_list = ir_list(INT)
registry.get_mapping(int_list, "python") # "List[int]"
registry.get_mapping(int_list, "rust") # "Vec<i64>"
registry.get_mapping(int_list, "ocaml") # "int list"
Tuple Types¶
from polyglot_ffi.ir.types import STRING, INT, ir_tuple
pair = ir_tuple(STRING, INT)
registry.get_mapping(pair, "python") # "Tuple[str, int]"
registry.get_mapping(pair, "rust") # "(String, i64)"
registry.get_mapping(pair, "ocaml") # "(string * int)"
Nested Types¶
The type system handles arbitrarily nested types:
from polyglot_ffi.ir.types import STRING, INT, ir_option, ir_list, ir_tuple
# option[list[tuple[str, int]]]
complex = ir_option(ir_list(ir_tuple(STRING, INT)))
registry.get_mapping(complex, "python")
# "Optional[List[Tuple[str, int]]]"
registry.get_mapping(complex, "rust")
# "Option<Vec<(String, i64)>>"
Custom Type Mappings¶
Registering Primitive Types¶
from polyglot_ffi.type_system.registry import TypeRegistry
registry = TypeRegistry()
# Register a custom primitive type
registry.register_primitive("bytes", {
"ocaml": "bytes",
"python": "bytes",
"rust": "Vec<u8>",
"c": "uint8_t*"
})
# Use it
from polyglot_ffi.ir.types import ir_primitive
bytes_type = ir_primitive("bytes")
registry.get_mapping(bytes_type, "python") # "bytes"
Registering Type Converters¶
For complex custom types, register a converter function:
from polyglot_ffi.ir.types import IRType
def convert_timestamp(ir_type: IRType) -> str:
"""Convert timestamp type to Python."""
return "datetime.datetime"
registry.register_converter("timestamp", "python", convert_timestamp)
# Use it
timestamp = ir_primitive("timestamp")
registry.get_mapping(timestamp, "python") # "datetime.datetime"
Custom Types in Configuration¶
Users can define custom types in polyglot.toml:
[types.binary_data]
ocaml = "bytes"
python = "bytes"
rust = "Vec<u8>"
c = "uint8_t*"
[types.timestamp]
ocaml = "float"
python = "datetime.datetime"
rust = "SystemTime"
c = "time_t"
Type Validation¶
Check if a type mapping exists before using it:
from polyglot_ffi.ir.types import STRING, ir_primitive
registry = get_default_registry()
# Validate known type
is_valid = registry.validate(STRING, "python") # True
# Validate unknown type
unknown = ir_primitive("unknown_type")
is_valid = registry.validate(unknown, "python") # False
Error Handling¶
The registry raises TypeMappingError for invalid mappings:
from polyglot_ffi.type_system.registry import TypeMappingError
from polyglot_ffi.ir.types import ir_primitive
try:
unknown = ir_primitive("unknown_type")
registry.get_mapping(unknown, "python")
except TypeMappingError as e:
print(f"Type mapping error: {e}")
# "Unknown primitive type 'unknown_type'"
Performance¶
The type registry is optimized for speed:
- O(1) primitive lookups: Direct dictionary access
- Caching: Computed mappings cached automatically
- Pre-compilation: No runtime regex compilation
Typical performance: - Primitive lookup: ~0.0003ms - Option lookup: ~0.0007ms (with cache hit) - Complex nested type: ~0.0019ms (with cache hit)
Cache Behavior¶
The registry automatically caches computed type mappings:
# First call: computes and caches
result1 = registry.get_mapping(ir_option(STRING), "python")
# Second call: returns cached result (faster)
result2 = registry.get_mapping(ir_option(STRING), "python")
# Cache is cleared when registry is modified
registry.register_primitive("newtype", {...})
# Cache cleared automatically
Usage in Generators¶
Generators use the registry to produce consistent type mappings:
from polyglot_ffi.ir.types import IRFunction, IRParameter
from polyglot_ffi.type_system.registry import get_default_registry
def generate_python_signature(func: IRFunction) -> str:
"""Generate Python function signature."""
registry = get_default_registry()
# Map parameter types
params = []
for param in func.parameters:
py_type = registry.get_mapping(param.type, "python")
params.append(f"{param.name}: {py_type}")
# Map return type
return_type = registry.get_mapping(func.return_type, "python")
# Build signature
params_str = ", ".join(params)
return f"def {func.name}({params_str}) -> {return_type}:"
Complete Example¶
from polyglot_ffi.ir.types import (
STRING, INT, BOOL, ir_option, ir_list, ir_tuple, ir_primitive
)
from polyglot_ffi.type_system.registry import (
TypeRegistry, get_default_registry
)
# Get default registry with built-in types
registry = get_default_registry()
# Test primitive mappings
print("Primitives:")
for lang in ["python", "rust", "ocaml", "c"]:
print(f" {lang}: string -> {registry.get_mapping(STRING, lang)}")
# Test complex types
print("\nComplex types:")
opt_int = ir_option(INT)
print(f" option[int] -> {registry.get_mapping(opt_int, 'python')}")
list_str = ir_list(STRING)
print(f" list[str] -> {registry.get_mapping(list_str, 'rust')}")
pair = ir_tuple(STRING, INT)
print(f" tuple[str,int] -> {registry.get_mapping(pair, 'python')}")
# Test nested types
nested = ir_option(ir_list(ir_tuple(STRING, INT)))
print(f"\nNested type:")
print(f" Python: {registry.get_mapping(nested, 'python')}")
print(f" Rust: {registry.get_mapping(nested, 'rust')}")
# Register custom type
registry.register_primitive("uuid", {
"python": "uuid.UUID",
"rust": "Uuid",
"ocaml": "string",
"c": "char*"
})
uuid_type = ir_primitive("uuid")
print(f"\nCustom type:")
print(f" uuid -> {registry.get_mapping(uuid_type, 'python')}")
# Validate types
print(f"\nValidation:")
print(f" STRING valid? {registry.validate(STRING, 'python')}")
print(f" unknown valid? {registry.validate(ir_primitive('unknown'), 'python')}")
See Also¶
- IR Types - Type definitions
- Generators - Using type mappings
- Configuration - Custom type config