Package not found. Please check the package name and try again.

pytecode 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,630 @@
1
+ """Serialize a ClassFile tree into JVM ``.class`` file bytes (JVMS §4)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from . import attributes, constant_pool, instructions
6
+ from .bytes_utils import BytesWriter
7
+ from .info import ClassFile, FieldInfo, MethodInfo
8
+
9
+ __all__ = ["ClassWriter"]
10
+
11
+
12
+ class ClassWriter:
13
+ """Serializer that converts a ``ClassFile`` tree into JVM ``.class`` bytes.
14
+
15
+ This writer walks every section of the ``ClassFile`` structure — constant
16
+ pool, fields, methods, and attributes — and emits the binary encoding
17
+ defined by the JVM class-file format (JVMS §4).
18
+ """
19
+
20
+ @staticmethod
21
+ def write(classfile: ClassFile) -> bytes:
22
+ """Serialize a ``ClassFile`` into raw ``.class`` file bytes.
23
+
24
+ Encodes all sections of the class file (magic number, version,
25
+ constant pool, access flags, fields, methods, and attributes) into
26
+ the binary format specified by JVMS §4.1.
27
+
28
+ Args:
29
+ classfile: The parsed class-file structure to serialize.
30
+
31
+ Returns:
32
+ The complete ``.class`` binary content.
33
+ """
34
+ writer = BytesWriter()
35
+ _write_classfile(writer, classfile)
36
+ return writer.to_bytes()
37
+
38
+
39
+ def _write_classfile(writer: BytesWriter, classfile: ClassFile) -> None:
40
+ writer.write_u4(classfile.magic)
41
+ writer.write_u2(classfile.minor_version)
42
+ writer.write_u2(classfile.major_version)
43
+
44
+ pool = classfile.constant_pool
45
+ writer.write_u2(len(pool))
46
+ for entry in _iter_constant_pool_entries(pool):
47
+ _write_constant_pool_entry(writer, entry)
48
+
49
+ writer.write_u2(int(classfile.access_flags))
50
+ writer.write_u2(classfile.this_class)
51
+ writer.write_u2(classfile.super_class)
52
+
53
+ writer.write_u2(len(classfile.interfaces))
54
+ for interface_index in classfile.interfaces:
55
+ writer.write_u2(interface_index)
56
+
57
+ writer.write_u2(len(classfile.fields))
58
+ for field in classfile.fields:
59
+ _write_field_info(writer, field)
60
+
61
+ writer.write_u2(len(classfile.methods))
62
+ for method in classfile.methods:
63
+ _write_method_info(writer, method)
64
+
65
+ _write_attributes(writer, classfile.attributes)
66
+
67
+
68
+ def _iter_constant_pool_entries(
69
+ pool: list[constant_pool.ConstantPoolInfo | None],
70
+ ) -> list[constant_pool.ConstantPoolInfo]:
71
+ if not pool:
72
+ raise ValueError("constant pool must include slot 0")
73
+ if pool[0] is not None:
74
+ raise ValueError("constant pool slot 0 must be None")
75
+
76
+ entries: list[constant_pool.ConstantPoolInfo] = []
77
+ expect_gap = False
78
+ for index in range(1, len(pool)):
79
+ entry = pool[index]
80
+ if expect_gap:
81
+ if entry is not None:
82
+ raise ValueError(f"constant pool slot {index} must be empty after a Long/Double entry")
83
+ expect_gap = False
84
+ continue
85
+
86
+ if entry is None:
87
+ raise ValueError(f"constant pool slot {index} is unexpectedly empty")
88
+
89
+ entries.append(entry)
90
+ expect_gap = isinstance(entry, (constant_pool.LongInfo, constant_pool.DoubleInfo))
91
+
92
+ if expect_gap:
93
+ raise ValueError("constant pool is missing the trailing gap slot for a Long/Double entry")
94
+
95
+ return entries
96
+
97
+
98
+ def _write_constant_pool_entry(writer: BytesWriter, entry: constant_pool.ConstantPoolInfo) -> None:
99
+ writer.write_u1(entry.tag)
100
+
101
+ if isinstance(entry, constant_pool.ClassInfo):
102
+ writer.write_u2(entry.name_index)
103
+ elif isinstance(entry, constant_pool.StringInfo):
104
+ writer.write_u2(entry.string_index)
105
+ elif isinstance(entry, constant_pool.MethodTypeInfo):
106
+ writer.write_u2(entry.descriptor_index)
107
+ elif isinstance(entry, constant_pool.ModuleInfo):
108
+ writer.write_u2(entry.name_index)
109
+ elif isinstance(entry, constant_pool.PackageInfo):
110
+ writer.write_u2(entry.name_index)
111
+ elif isinstance(entry, constant_pool.FieldrefInfo):
112
+ writer.write_u2(entry.class_index)
113
+ writer.write_u2(entry.name_and_type_index)
114
+ elif isinstance(entry, constant_pool.MethodrefInfo):
115
+ writer.write_u2(entry.class_index)
116
+ writer.write_u2(entry.name_and_type_index)
117
+ elif isinstance(entry, constant_pool.InterfaceMethodrefInfo):
118
+ writer.write_u2(entry.class_index)
119
+ writer.write_u2(entry.name_and_type_index)
120
+ elif isinstance(entry, constant_pool.NameAndTypeInfo):
121
+ writer.write_u2(entry.name_index)
122
+ writer.write_u2(entry.descriptor_index)
123
+ elif isinstance(entry, constant_pool.DynamicInfo):
124
+ writer.write_u2(entry.bootstrap_method_attr_index)
125
+ writer.write_u2(entry.name_and_type_index)
126
+ elif isinstance(entry, constant_pool.InvokeDynamicInfo):
127
+ writer.write_u2(entry.bootstrap_method_attr_index)
128
+ writer.write_u2(entry.name_and_type_index)
129
+ elif isinstance(entry, constant_pool.IntegerInfo):
130
+ writer.write_u4(entry.value_bytes)
131
+ elif isinstance(entry, constant_pool.FloatInfo):
132
+ writer.write_u4(entry.value_bytes)
133
+ elif isinstance(entry, constant_pool.LongInfo):
134
+ writer.write_u4(entry.high_bytes)
135
+ writer.write_u4(entry.low_bytes)
136
+ elif isinstance(entry, constant_pool.DoubleInfo):
137
+ writer.write_u4(entry.high_bytes)
138
+ writer.write_u4(entry.low_bytes)
139
+ elif isinstance(entry, constant_pool.Utf8Info):
140
+ writer.write_u2(len(entry.str_bytes))
141
+ writer.write_bytes(entry.str_bytes)
142
+ elif isinstance(entry, constant_pool.MethodHandleInfo):
143
+ writer.write_u1(entry.reference_kind)
144
+ writer.write_u2(entry.reference_index)
145
+ else:
146
+ raise ValueError(f"Unsupported constant-pool entry type: {type(entry).__name__}")
147
+
148
+
149
+ def _write_field_info(writer: BytesWriter, field: FieldInfo) -> None:
150
+ writer.write_u2(int(field.access_flags))
151
+ writer.write_u2(field.name_index)
152
+ writer.write_u2(field.descriptor_index)
153
+ _write_attributes(writer, field.attributes)
154
+
155
+
156
+ def _write_method_info(writer: BytesWriter, method: MethodInfo) -> None:
157
+ writer.write_u2(int(method.access_flags))
158
+ writer.write_u2(method.name_index)
159
+ writer.write_u2(method.descriptor_index)
160
+ _write_attributes(writer, method.attributes)
161
+
162
+
163
+ def _write_attributes(writer: BytesWriter, attrs: list[attributes.AttributeInfo]) -> None:
164
+ writer.write_u2(len(attrs))
165
+ for attr in attrs:
166
+ _write_attribute(writer, attr)
167
+
168
+
169
+ def _write_attribute(writer: BytesWriter, attr: attributes.AttributeInfo) -> None:
170
+ payload_writer = BytesWriter()
171
+ _write_attribute_payload(payload_writer, attr)
172
+ payload = payload_writer.to_bytes()
173
+
174
+ writer.write_u2(attr.attribute_name_index)
175
+ writer.write_u4(len(payload))
176
+ writer.write_bytes(payload)
177
+
178
+
179
+ def _write_attribute_payload(writer: BytesWriter, attr: attributes.AttributeInfo) -> None:
180
+ if isinstance(attr, (attributes.SyntheticAttr, attributes.DeprecatedAttr)):
181
+ return
182
+
183
+ if isinstance(attr, attributes.ConstantValueAttr):
184
+ writer.write_u2(attr.constantvalue_index)
185
+ return
186
+
187
+ if isinstance(attr, attributes.SignatureAttr):
188
+ writer.write_u2(attr.signature_index)
189
+ return
190
+
191
+ if isinstance(attr, attributes.SourceFileAttr):
192
+ writer.write_u2(attr.sourcefile_index)
193
+ return
194
+
195
+ if isinstance(attr, attributes.ModuleMainClassAttr):
196
+ writer.write_u2(attr.main_class_index)
197
+ return
198
+
199
+ if isinstance(attr, attributes.NestHostAttr):
200
+ writer.write_u2(attr.host_class_index)
201
+ return
202
+
203
+ if isinstance(attr, attributes.CodeAttr):
204
+ code_writer = BytesWriter()
205
+ for insn in attr.code:
206
+ _write_instruction(code_writer, insn)
207
+ code_bytes = code_writer.to_bytes()
208
+
209
+ writer.write_u2(attr.max_stacks)
210
+ writer.write_u2(attr.max_locals)
211
+ writer.write_u4(len(code_bytes))
212
+ writer.write_bytes(code_bytes)
213
+ writer.write_u2(len(attr.exception_table))
214
+ for exception in attr.exception_table:
215
+ writer.write_u2(exception.start_pc)
216
+ writer.write_u2(exception.end_pc)
217
+ writer.write_u2(exception.handler_pc)
218
+ writer.write_u2(exception.catch_type)
219
+ _write_attributes(writer, attr.attributes)
220
+ return
221
+
222
+ if isinstance(attr, attributes.StackMapTableAttr):
223
+ writer.write_u2(len(attr.entries))
224
+ for entry in attr.entries:
225
+ _write_stack_map_frame_info(writer, entry)
226
+ return
227
+
228
+ if isinstance(attr, attributes.ExceptionsAttr):
229
+ writer.write_u2(len(attr.exception_index_table))
230
+ for exception_index in attr.exception_index_table:
231
+ writer.write_u2(exception_index)
232
+ return
233
+
234
+ if isinstance(attr, attributes.InnerClassesAttr):
235
+ writer.write_u2(len(attr.classes))
236
+ for entry in attr.classes:
237
+ writer.write_u2(entry.inner_class_info_index)
238
+ writer.write_u2(entry.outer_class_info_index)
239
+ writer.write_u2(entry.inner_name_index)
240
+ writer.write_u2(int(entry.inner_class_access_flags))
241
+ return
242
+
243
+ if isinstance(attr, attributes.EnclosingMethodAttr):
244
+ writer.write_u2(attr.class_index)
245
+ writer.write_u2(attr.method_index)
246
+ return
247
+
248
+ if isinstance(attr, attributes.SourceDebugExtensionAttr):
249
+ writer.write_bytes(attr.debug_extension.encode("utf-8"))
250
+ return
251
+
252
+ if isinstance(attr, attributes.LineNumberTableAttr):
253
+ writer.write_u2(len(attr.line_number_table))
254
+ for entry in attr.line_number_table:
255
+ writer.write_u2(entry.start_pc)
256
+ writer.write_u2(entry.line_number)
257
+ return
258
+
259
+ if isinstance(attr, attributes.LocalVariableTableAttr):
260
+ writer.write_u2(len(attr.local_variable_table))
261
+ for entry in attr.local_variable_table:
262
+ writer.write_u2(entry.start_pc)
263
+ writer.write_u2(entry.length)
264
+ writer.write_u2(entry.name_index)
265
+ writer.write_u2(entry.descriptor_index)
266
+ writer.write_u2(entry.index)
267
+ return
268
+
269
+ if isinstance(attr, attributes.LocalVariableTypeTableAttr):
270
+ writer.write_u2(len(attr.local_variable_type_table))
271
+ for entry in attr.local_variable_type_table:
272
+ writer.write_u2(entry.start_pc)
273
+ writer.write_u2(entry.length)
274
+ writer.write_u2(entry.name_index)
275
+ writer.write_u2(entry.signature_index)
276
+ writer.write_u2(entry.index)
277
+ return
278
+
279
+ if isinstance(
280
+ attr,
281
+ (
282
+ attributes.RuntimeVisibleAnnotationsAttr,
283
+ attributes.RuntimeInvisibleAnnotationsAttr,
284
+ ),
285
+ ):
286
+ writer.write_u2(len(attr.annotations))
287
+ for annotation in attr.annotations:
288
+ _write_annotation_info(writer, annotation)
289
+ return
290
+
291
+ if isinstance(
292
+ attr,
293
+ (
294
+ attributes.RuntimeVisibleParameterAnnotationsAttr,
295
+ attributes.RuntimeInvisibleParameterAnnotationsAttr,
296
+ ),
297
+ ):
298
+ writer.write_u1(len(attr.parameter_annotations))
299
+ for parameter in attr.parameter_annotations:
300
+ writer.write_u2(len(parameter.annotations))
301
+ for annotation in parameter.annotations:
302
+ _write_annotation_info(writer, annotation)
303
+ return
304
+
305
+ if isinstance(
306
+ attr,
307
+ (
308
+ attributes.RuntimeVisibleTypeAnnotationsAttr,
309
+ attributes.RuntimeInvisibleTypeAnnotationsAttr,
310
+ ),
311
+ ):
312
+ writer.write_u2(len(attr.annotations))
313
+ for annotation in attr.annotations:
314
+ _write_type_annotation_info(writer, annotation)
315
+ return
316
+
317
+ if isinstance(attr, attributes.AnnotationDefaultAttr):
318
+ _write_element_value_info(writer, attr.default_value)
319
+ return
320
+
321
+ if isinstance(attr, attributes.BootstrapMethodsAttr):
322
+ writer.write_u2(len(attr.bootstrap_methods))
323
+ for method in attr.bootstrap_methods:
324
+ writer.write_u2(method.bootstrap_method_ref)
325
+ writer.write_u2(len(method.boostrap_arguments))
326
+ for argument in method.boostrap_arguments:
327
+ writer.write_u2(argument)
328
+ return
329
+
330
+ if isinstance(attr, attributes.MethodParametersAttr):
331
+ writer.write_u1(len(attr.parameters))
332
+ for parameter in attr.parameters:
333
+ writer.write_u2(parameter.name_index)
334
+ writer.write_u2(int(parameter.access_flags))
335
+ return
336
+
337
+ if isinstance(attr, attributes.ModuleAttr):
338
+ writer.write_u2(attr.module_name_index)
339
+ writer.write_u2(int(attr.module_flags))
340
+ writer.write_u2(attr.module_version_index)
341
+
342
+ writer.write_u2(len(attr.requires))
343
+ for require in attr.requires:
344
+ writer.write_u2(require.requires_index)
345
+ writer.write_u2(int(require.requires_flag))
346
+ writer.write_u2(require.requires_version_index)
347
+
348
+ writer.write_u2(len(attr.exports))
349
+ for export in attr.exports:
350
+ writer.write_u2(export.exports_index)
351
+ writer.write_u2(int(export.exports_flags))
352
+ writer.write_u2(len(export.exports_to_index))
353
+ for target in export.exports_to_index:
354
+ writer.write_u2(target)
355
+
356
+ writer.write_u2(len(attr.opens))
357
+ for opened in attr.opens:
358
+ writer.write_u2(opened.opens_index)
359
+ writer.write_u2(int(opened.opens_flags))
360
+ writer.write_u2(len(opened.opens_to_index))
361
+ for target in opened.opens_to_index:
362
+ writer.write_u2(target)
363
+
364
+ writer.write_u2(len(attr.uses_index))
365
+ for use in attr.uses_index:
366
+ writer.write_u2(use)
367
+
368
+ writer.write_u2(len(attr.provides))
369
+ for provide in attr.provides:
370
+ writer.write_u2(provide.provides_index)
371
+ writer.write_u2(len(provide.provides_with_index))
372
+ for implementation in provide.provides_with_index:
373
+ writer.write_u2(implementation)
374
+ return
375
+
376
+ if isinstance(attr, attributes.ModulePackagesAttr):
377
+ writer.write_u2(len(attr.package_index))
378
+ for package_index in attr.package_index:
379
+ writer.write_u2(package_index)
380
+ return
381
+
382
+ if isinstance(attr, attributes.NestMembersAttr):
383
+ writer.write_u2(len(attr.classes))
384
+ for class_index in attr.classes:
385
+ writer.write_u2(class_index)
386
+ return
387
+
388
+ if isinstance(attr, attributes.RecordAttr):
389
+ writer.write_u2(len(attr.components))
390
+ for component in attr.components:
391
+ writer.write_u2(component.name_index)
392
+ writer.write_u2(component.descriptor_index)
393
+ _write_attributes(writer, component.attributes)
394
+ return
395
+
396
+ if isinstance(attr, attributes.PermittedSubclassesAttr):
397
+ writer.write_u2(len(attr.classes))
398
+ for class_index in attr.classes:
399
+ writer.write_u2(class_index)
400
+ return
401
+
402
+ if isinstance(attr, attributes.UnimplementedAttr):
403
+ writer.write_bytes(attr.info)
404
+ return
405
+
406
+ raise ValueError(f"Unsupported attribute type: {type(attr).__name__}")
407
+
408
+
409
+ def _write_stack_map_frame_info(writer: BytesWriter, entry: attributes.StackMapFrameInfo) -> None:
410
+ writer.write_u1(entry.frame_type)
411
+
412
+ if isinstance(entry, attributes.SameFrameInfo):
413
+ return
414
+ if isinstance(entry, attributes.SameLocals1StackItemFrameInfo):
415
+ _write_verification_type_info(writer, entry.stack)
416
+ return
417
+ if isinstance(entry, attributes.SameLocals1StackItemFrameExtendedInfo):
418
+ writer.write_u2(entry.offset_delta)
419
+ _write_verification_type_info(writer, entry.stack)
420
+ return
421
+ if isinstance(entry, attributes.ChopFrameInfo):
422
+ writer.write_u2(entry.offset_delta)
423
+ return
424
+ if isinstance(entry, attributes.SameFrameExtendedInfo):
425
+ writer.write_u2(entry.offset_delta)
426
+ return
427
+ if isinstance(entry, attributes.AppendFrameInfo):
428
+ writer.write_u2(entry.offset_delta)
429
+ for local in entry.locals:
430
+ _write_verification_type_info(writer, local)
431
+ return
432
+ if isinstance(entry, attributes.FullFrameInfo):
433
+ writer.write_u2(entry.offset_delta)
434
+ writer.write_u2(len(entry.locals))
435
+ for local in entry.locals:
436
+ _write_verification_type_info(writer, local)
437
+ writer.write_u2(len(entry.stack))
438
+ for stack_item in entry.stack:
439
+ _write_verification_type_info(writer, stack_item)
440
+ return
441
+
442
+ raise ValueError(f"Unsupported stack-map frame type: {type(entry).__name__}")
443
+
444
+
445
+ def _write_verification_type_info(writer: BytesWriter, entry: attributes.VerificationTypeInfo) -> None:
446
+ writer.write_u1(int(entry.tag))
447
+
448
+ if isinstance(entry, attributes.ObjectVariableInfo):
449
+ writer.write_u2(entry.cpool_index)
450
+ elif isinstance(entry, attributes.UninitializedVariableInfo):
451
+ writer.write_u2(entry.offset)
452
+
453
+
454
+ def _write_annotation_info(writer: BytesWriter, annotation: attributes.AnnotationInfo) -> None:
455
+ writer.write_u2(annotation.type_index)
456
+ writer.write_u2(len(annotation.element_value_pairs))
457
+ for pair in annotation.element_value_pairs:
458
+ writer.write_u2(pair.element_name_index)
459
+ _write_element_value_info(writer, pair.element_value)
460
+
461
+
462
+ def _write_element_value_info(writer: BytesWriter, element_value: attributes.ElementValueInfo) -> None:
463
+ tag = _element_value_tag(element_value.tag)
464
+ writer.write_u1(tag)
465
+
466
+ if tag in {ord("B"), ord("C"), ord("D"), ord("F"), ord("I"), ord("J"), ord("S"), ord("Z"), ord("s")}:
467
+ if not isinstance(element_value.value, attributes.ConstValueInfo):
468
+ raise ValueError("const element value must carry ConstValueInfo")
469
+ writer.write_u2(element_value.value.const_value_index)
470
+ return
471
+
472
+ if tag == ord("e"):
473
+ if not isinstance(element_value.value, attributes.EnumConstantValueInfo):
474
+ raise ValueError("enum element value must carry EnumConstantValueInfo")
475
+ writer.write_u2(element_value.value.type_name_index)
476
+ writer.write_u2(element_value.value.const_name_index)
477
+ return
478
+
479
+ if tag == ord("c"):
480
+ if not isinstance(element_value.value, attributes.ClassInfoValueInfo):
481
+ raise ValueError("class element value must carry ClassInfoValueInfo")
482
+ writer.write_u2(element_value.value.class_info_index)
483
+ return
484
+
485
+ if tag == ord("@"):
486
+ if not isinstance(element_value.value, attributes.AnnotationInfo):
487
+ raise ValueError("annotation element value must carry AnnotationInfo")
488
+ _write_annotation_info(writer, element_value.value)
489
+ return
490
+
491
+ if tag == ord("["):
492
+ if not isinstance(element_value.value, attributes.ArrayValueInfo):
493
+ raise ValueError("array element value must carry ArrayValueInfo")
494
+ writer.write_u2(len(element_value.value.values))
495
+ for nested in element_value.value.values:
496
+ _write_element_value_info(writer, nested)
497
+ return
498
+
499
+ raise ValueError(f"Unsupported element-value tag: {tag!r}")
500
+
501
+
502
+ def _element_value_tag(tag: int | str) -> int:
503
+ if isinstance(tag, int):
504
+ if not 0 <= tag <= 255:
505
+ raise ValueError(f"element-value tag must fit in u1, got {tag}")
506
+ return tag
507
+ if len(tag) != 1:
508
+ raise ValueError(f"element-value tag must be a single character, got {tag!r}")
509
+ return ord(tag)
510
+
511
+
512
+ def _write_type_annotation_info(writer: BytesWriter, annotation: attributes.TypeAnnotationInfo) -> None:
513
+ writer.write_u1(annotation.target_type)
514
+ _write_target_info(writer, annotation.target_info)
515
+ _write_type_path_info(writer, annotation.target_path)
516
+ writer.write_u2(annotation.type_index)
517
+ writer.write_u2(len(annotation.element_value_pairs))
518
+ for pair in annotation.element_value_pairs:
519
+ writer.write_u2(pair.element_name_index)
520
+ _write_element_value_info(writer, pair.element_value)
521
+
522
+
523
+ def _write_target_info(writer: BytesWriter, target_info: attributes.TargetInfo) -> None:
524
+ if isinstance(target_info, attributes.TypeParameterTargetInfo):
525
+ writer.write_u1(target_info.type_parameter_index)
526
+ return
527
+ if isinstance(target_info, attributes.SupertypeTargetInfo):
528
+ writer.write_u2(target_info.supertype_index)
529
+ return
530
+ if isinstance(target_info, attributes.TypeParameterBoundTargetInfo):
531
+ writer.write_u1(target_info.type_parameter_index)
532
+ writer.write_u1(target_info.bound_index)
533
+ return
534
+ if isinstance(target_info, attributes.EmptyTargetInfo):
535
+ return
536
+ if isinstance(target_info, attributes.FormalParameterTargetInfo):
537
+ writer.write_u1(target_info.formal_parameter_index)
538
+ return
539
+ if isinstance(target_info, attributes.ThrowsTargetInfo):
540
+ writer.write_u2(target_info.throws_type_index)
541
+ return
542
+ if isinstance(target_info, attributes.LocalvarTargetInfo):
543
+ writer.write_u2(len(target_info.table))
544
+ for table_entry in target_info.table:
545
+ writer.write_u2(table_entry.start_pc)
546
+ writer.write_u2(table_entry.length)
547
+ writer.write_u2(table_entry.index)
548
+ return
549
+ if isinstance(target_info, attributes.CatchTargetInfo):
550
+ writer.write_u2(target_info.exception_table_index)
551
+ return
552
+ if isinstance(target_info, attributes.OffsetTargetInfo):
553
+ writer.write_u2(target_info.offset)
554
+ return
555
+ if isinstance(target_info, attributes.TypeArgumentTargetInfo):
556
+ writer.write_u2(target_info.offset)
557
+ writer.write_u1(target_info.type_argument_index)
558
+ return
559
+
560
+ raise ValueError(f"Unsupported target-info type: {type(target_info).__name__}")
561
+
562
+
563
+ def _write_type_path_info(writer: BytesWriter, type_path: attributes.TypePathInfo) -> None:
564
+ writer.write_u1(len(type_path.path))
565
+ for path_item in type_path.path:
566
+ writer.write_u1(path_item.type_path_kind)
567
+ writer.write_u1(path_item.type_argument_index)
568
+
569
+
570
+ def _write_instruction(writer: BytesWriter, insn: instructions.InsnInfo) -> None:
571
+ if isinstance(insn, instructions.LocalIndexW):
572
+ writer.write_u1(int(instructions.InsnInfoType.WIDE))
573
+ writer.write_u1(int(insn.type) - int(instructions.InsnInfoType.WIDE))
574
+ writer.write_u2(insn.index)
575
+ return
576
+
577
+ if isinstance(insn, instructions.IIncW):
578
+ writer.write_u1(int(instructions.InsnInfoType.WIDE))
579
+ writer.write_u1(int(insn.type) - int(instructions.InsnInfoType.WIDE))
580
+ writer.write_u2(insn.index)
581
+ writer.write_i2(insn.value)
582
+ return
583
+
584
+ writer.write_u1(int(insn.type))
585
+
586
+ if isinstance(insn, instructions.LocalIndex):
587
+ writer.write_u1(insn.index)
588
+ elif isinstance(insn, instructions.ConstPoolIndex):
589
+ writer.write_u2(insn.index)
590
+ elif isinstance(insn, instructions.ByteValue):
591
+ writer.write_i1(insn.value)
592
+ elif isinstance(insn, instructions.ShortValue):
593
+ writer.write_i2(insn.value)
594
+ elif isinstance(insn, instructions.Branch):
595
+ writer.write_i2(insn.offset)
596
+ elif isinstance(insn, instructions.BranchW):
597
+ writer.write_i4(insn.offset)
598
+ elif isinstance(insn, instructions.IInc):
599
+ writer.write_u1(insn.index)
600
+ writer.write_i1(insn.value)
601
+ elif isinstance(insn, instructions.InvokeDynamic):
602
+ if len(insn.unused) != 2:
603
+ raise ValueError("InvokeDynamic unused bytes must be exactly 2 bytes")
604
+ writer.write_u2(insn.index)
605
+ writer.write_bytes(insn.unused)
606
+ elif isinstance(insn, instructions.InvokeInterface):
607
+ if len(insn.unused) != 1:
608
+ raise ValueError("InvokeInterface unused bytes must be exactly 1 byte")
609
+ writer.write_u2(insn.index)
610
+ writer.write_u1(insn.count)
611
+ writer.write_bytes(insn.unused)
612
+ elif isinstance(insn, instructions.MultiANewArray):
613
+ writer.write_u2(insn.index)
614
+ writer.write_u1(insn.dimensions)
615
+ elif isinstance(insn, instructions.NewArray):
616
+ writer.write_u1(int(insn.atype))
617
+ elif isinstance(insn, instructions.LookupSwitch):
618
+ writer.align(4)
619
+ writer.write_i4(insn.default)
620
+ writer.write_u4(len(insn.pairs))
621
+ for pair in insn.pairs:
622
+ writer.write_i4(pair.match)
623
+ writer.write_i4(pair.offset)
624
+ elif isinstance(insn, instructions.TableSwitch):
625
+ writer.align(4)
626
+ writer.write_i4(insn.default)
627
+ writer.write_i4(insn.low)
628
+ writer.write_i4(insn.high)
629
+ for offset in insn.offsets:
630
+ writer.write_i4(offset)