gogyou 0.1.240911.prototype → 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,504 @@
1
+ module Gogyou
2
+ #
3
+ # 構造体の構成情報などを保持するクラスです。
4
+ #
5
+ # 構造体の大きさや各フィールドの名前、バイト位置、型などを管理します。
6
+ #
7
+ class Model < ::Struct.new(:bytesize, # total bytesize in bytes
8
+ :bytealign, # byte alignment
9
+ :fields) # array of field
10
+ BasicStruct = superclass
11
+
12
+ FIELDNAME_PATTERN = /\A[A-Za-z_][0-9A-Za-z_]*\Z/
13
+
14
+ undef :bytesize=, :bytealign=, :fields=
15
+
16
+ def initialize(*args)
17
+ case
18
+ when args.size < 3
19
+ raise ArgumentError, "wrong argument size (#{args.size} for 3+)"
20
+ when args.size < 4 && args[2].kind_of?(::Array)
21
+ super
22
+ else
23
+ super(args[0], args[1], args.slice(2 .. -1))
24
+ end
25
+ end
26
+
27
+ def aset(buffer, offset, value)
28
+ raise NotImplementedError
29
+ end
30
+
31
+ def aref(buffer, offset)
32
+ raise NotImplementedError
33
+ end
34
+
35
+ def extensible?
36
+ fields.any? { |f| f.extensible? }
37
+ end
38
+
39
+ def to_s
40
+ "#{self.class}[bytesize=#{bytesize.inspect}, bytealign=#{bytealign.inspect}, fields=#{fields.inspect}]"
41
+ end
42
+
43
+ alias inspect to_s
44
+
45
+ def pretty_print(q)
46
+ #bytesize, bytealign, fields
47
+ q.group(1, "#{self.class}[") do
48
+ #q.breakable
49
+ q.text "bytesize="
50
+ q.pp bytesize
51
+ q.text ", "
52
+ #q.breakable
53
+ q.text "bytealign="
54
+ q.pp bytealign
55
+ q.text ", "
56
+ #q.breakable(" ")
57
+ q.text "fields="
58
+ q.breakable
59
+ q.pp fields
60
+ end
61
+ q.text "]"
62
+ end
63
+
64
+ # 構造体の各メンバの情報を保持する
65
+ class Field < ::Struct.new(:offset, # field offset in model
66
+ :name, # field name
67
+ :vector, # 要素数。任意数配列の場合は 0。配列でないならば nil。
68
+ :type, # type specification (or model object) of this field
69
+ :flags) # 0x01: const / 0x02: packed (not aligned)
70
+ BasicStruct = superclass
71
+
72
+ FLAG_CONST = 0x01
73
+ FLAG_PACKED = 0x02
74
+
75
+ def initialize(offset, name, vector, type, flags = 0)
76
+ super(offset, name, vector, type, flags)
77
+ end
78
+
79
+ def extensible?
80
+ if vector
81
+ vector[-1] == 0 ? true : false
82
+ else
83
+ type.extensible?
84
+ end
85
+ end
86
+
87
+ def const?
88
+ ((flags & FLAG_CONST) == FLAG_CONST) ? true : false
89
+ end
90
+
91
+ def packed?
92
+ ((flags & FLAG_PACKED) == FLAG_PACKED) ? true : false
93
+ end
94
+
95
+ def mark_const
96
+ self.flags |= FLAG_CONST
97
+ self
98
+ end
99
+
100
+ def mark_packed
101
+ self.flags |= FLAGS_PACKED
102
+ self
103
+ end
104
+
105
+ def strflags
106
+ set = [const? ? "const" : nil, packed? ? "packed" : nil]
107
+ set.compact!
108
+ return nil if set.empty?
109
+ set.join(",")
110
+ end
111
+
112
+ def strflags_with_paren
113
+ set = strflags
114
+ set ? "(#{set})" : ""
115
+ end
116
+
117
+ def to_s
118
+ "#{self.class}[offset=#{offset.inspect}, name=#{name.inspect}, vector=#{vector.inspect}, type=#{type.inspect}, flags=0x#{flags.to_s(16)}#{strflags_with_paren}]"
119
+ end
120
+
121
+ alias inspect to_s
122
+
123
+ def pretty_print(q)
124
+ q.group(1, "#{self.class}[") do
125
+ #q.breakable
126
+ q.text "offset="
127
+ q.pp offset
128
+ q.text ", "
129
+ #q.breakable
130
+ q.text "name="
131
+ q.pp name
132
+ q.text ", "
133
+ #q.breakable
134
+ q.text "vector="
135
+ q.pp vector
136
+ q.text ", "
137
+ #q.breakable
138
+ q.text "flags=0x%02x%s" % [flags, strflags_with_paren]
139
+ q.text ","
140
+ q.breakable(" ")
141
+ q.text "type="
142
+ q.pp type
143
+ end
144
+ q.text "]"
145
+ end
146
+ end
147
+
148
+ def self.struct(typemap, &block)
149
+ define_container(typemap, Model::Struct, &block)
150
+ end
151
+
152
+ def self.union(typemap, &block)
153
+ define_container(typemap, Model::Union, &block)
154
+ end
155
+
156
+ def self.typedef(typemap, type, aliasname, *elements)
157
+ raise ArgumentError, "informal aliasname (#{aliasname.inspect})" unless aliasname =~ FIELDNAME_PATTERN
158
+ aliasname = aliasname.intern
159
+
160
+ case type
161
+ when Symbol, String
162
+ type0 = type
163
+ type = typemap[type.intern]
164
+ raise ArgumentError, "type not defined (#{type0})" unless type
165
+ else
166
+ # 型情報子を用いる方法
167
+ raise ArgumentError, "type is not typeinfo (#{type.inspect})" unless Model.check_typeinfo(type)
168
+ end
169
+
170
+ unless elements.empty?
171
+ # 配列型
172
+ # TODO: Accessor::Array を構築するのではなく、Model::Array インスタンスを生成するようにする
173
+ type = Accessor.define_subarray(Model::Field[0, nil, elements, type, 0])
174
+ end
175
+
176
+ typemap[aliasname] = type
177
+
178
+ nil
179
+ end
180
+
181
+ def self.define_container(typemap, model_type, &block)
182
+ creator = model_type::Creator.new(typemap, 0, [])
183
+ proxy = model_type::Creator::Proxy.new(creator)
184
+ proxy.instance_exec(&block)
185
+ model = creator.to_model
186
+ model
187
+ end
188
+
189
+ def self.check_typeinfo(obj)
190
+ if obj.kind_of?(Model) ||
191
+ (obj.kind_of?(Module) && obj < Accessor) ||
192
+ (obj.respond_to?(:bytesize) &&
193
+ obj.respond_to?(:bytealign) &&
194
+ obj.respond_to?(:extensible?) &&
195
+ obj.respond_to?(:aset) &&
196
+ obj.respond_to?(:aref))
197
+ true
198
+ else
199
+ false
200
+ end
201
+ end
202
+
203
+
204
+ BasicCreator = ::Struct.new(:typemap, :offset, :fields)
205
+
206
+ class BasicCreator
207
+ def maxalign(fields = self.fields)
208
+ fields.map { |f| f.type.bytealign }.max
209
+ end
210
+
211
+ def maxsize(fields = self.fields)
212
+ fields.map { |f| s = f.type.bytesize; f.vector ? f.vector.inject(&:*) * s : s }.max
213
+ end
214
+
215
+ def flatten_field(fields = self.fields)
216
+ #pp fields
217
+ fields2 = []
218
+ fields.each do |f|
219
+ #p f
220
+ #p f.class
221
+ if f.name
222
+ fields2 << f
223
+ else
224
+ raise "BUG? : field.type is not a Model (%p)" % f.type unless f.type.kind_of?(Model)
225
+ fs = flatten_field(f.type.fields)
226
+ fs.each { |ff| ff.offset += f.offset; ff.mark_const if f.const? }
227
+ fields2.concat fs
228
+ end
229
+ end
230
+ fields2
231
+ end
232
+
233
+ # :nodoc: all
234
+ class Proxy < Object
235
+ #class Proxy < BasicObject
236
+ def initialize(creator)
237
+ #singleton_class = (class << proxy; self; end)
238
+ singleton_class.class_eval do
239
+ latest_fields = nil
240
+ #define_method(:method_missing, ->(type, *args) { latest_fields = creator.addfield(type, args); nil })
241
+ creator.typemap.each_key do |t|
242
+ define_method(t, ->(*args) { latest_fields = creator.addfield(t, args); nil })
243
+ end
244
+ define_method(:struct, ->(*args, &block) { latest_fields = creator.struct(args, &block); nil })
245
+ define_method(:union, ->(*args, &block) { latest_fields = creator.union(args, &block); nil })
246
+ define_method(:const, ->(dummy_fields) { creator.const(latest_fields); latest_fields = nil; nil })
247
+ define_method(:typedef, ->(*args, &block) { creator.typedef(args, &block) })
248
+ if creator.respond_to?(:bytealign)
249
+ define_method(:bytealign, ->(bytesize, &block) { creator.bytealign(bytesize, &block) })
250
+ end
251
+ if creator.respond_to?(:padding)
252
+ define_method(:padding, ->(bytesize, &block) { creator.padding(bytesize, &block) })
253
+ end
254
+ end
255
+ end
256
+ end
257
+
258
+ #
259
+ # call-seq:
260
+ # struct type, name, *vector
261
+ # struct proc, name, *vector
262
+ # struct { ... }
263
+ #
264
+ # 最初の呼び出し方法は、既存の (typedef していない) 型情報を用いる、または構造体をその場で定義するために利用できます。
265
+ #
266
+ # 二番目の呼び出し方法は、無名構造体を定義するために利用できます。
267
+ #
268
+ # === example (型情報を用いる)
269
+ #
270
+ # Type1 = struct {
271
+ # struct UserType, :a, :b, 2, 3, 4
272
+ # }
273
+ #
274
+ # === example (構造体をその場で定義して、構造体へのアクセッサを定義する)
275
+ #
276
+ # Type2 = struct {
277
+ # struct -> {
278
+ # int :x, y, z
279
+ # }, :a, :b, 2, 3, 4
280
+ # }
281
+ #
282
+ # === example (無名構造体)
283
+ #
284
+ # Type3 = struct {
285
+ # struct {
286
+ # int :a, :b, 2, 3, 4
287
+ # }
288
+ # }
289
+ #
290
+ def struct(args, &block)
291
+ define_container(args, block, Model.method(:struct))
292
+ end
293
+
294
+ #
295
+ # call-seq:
296
+ # union type, name, *vector
297
+ # union proc, name, *vector
298
+ # union { ... }
299
+ #
300
+ # 共用体を定義します。
301
+ #
302
+ # 呼び出し方は struct と変わりません。
303
+ #
304
+ # ただ、<tt>union type, ...</tt> の場合は、<tt>struct type, ...</tt> と同じ結果となります。
305
+ # これは type がどのような構造になっているのかを gogyou が管理も把握もしないためです。
306
+ # この記述ができる唯一の理由は、人間が見てわかりやすくすることを意図しています
307
+ # (ただし、ミスリードを誘う手口にも利用されてしまうのが最大の欠点です)。
308
+ #
309
+ def union(args, &block)
310
+ define_container(args, block, Model.method(:union))
311
+ end
312
+
313
+ def define_container(args, anonymblock, container)
314
+ if anonymblock
315
+ raise ArgumentError, "given block and arguments" unless args.empty?
316
+ model = container.(typemap.dup, &anonymblock)
317
+ raise "BUG - object is not a Model (#{model.class})" unless model.kind_of?(Model)
318
+ #p model: model, superclass: model.superclass
319
+ self.offset = offset.align_ceil(model.bytealign) unless kind_of?(Model::Union::Creator)
320
+ fields << f = Field[offset, nil, nil, model, 0]
321
+ self.offset += model.bytesize unless kind_of?(Model::Union::Creator)
322
+ [f]
323
+ else
324
+ type = args.shift
325
+ type = container.(typemap.dup, &type) if type.kind_of?(::Proc)
326
+ addfield!(type, args)
327
+ end
328
+ end
329
+
330
+ def typedef(args)
331
+ raise NotImplementedError
332
+ end
333
+
334
+ def const(fields)
335
+ fields.each { |f| f.mark_const }
336
+ end
337
+
338
+ #
339
+ # フィールド名の解析
340
+ #
341
+ def parse!(args)
342
+ raise ArgumentError, "nothing argument" if args.empty?
343
+ name = nil
344
+ vector = nil
345
+ while arg = args.shift
346
+ case arg
347
+ when Symbol, String
348
+ yield(name, vector) if name
349
+ raise ArgumentError, "informal field name (#{arg.to_s})" unless arg =~ FIELDNAME_PATTERN
350
+ name = arg.intern
351
+ vector = nil
352
+ when Integer
353
+ raise ArgumentError, "first argument is field name only (#{arg})" unless name
354
+ raise ArgumentError, "given negative number (#{arg})" unless arg >= 0
355
+ vector ||= []
356
+ vector << arg.to_i
357
+ if vector[-1] == 0
358
+ yield(name, vector)
359
+ unless args.empty?
360
+ raise ArgumentError, "given fields after extensible vector"
361
+ end
362
+ return nil
363
+ end
364
+ else
365
+ raise ArgumentError, "given any object (#{arg.inspect})"
366
+ end
367
+ end
368
+
369
+ yield(name, vector)
370
+
371
+ nil
372
+ end
373
+
374
+ def addfield(type, args)
375
+ typeobj = typemap[type.intern]
376
+ unless typeobj
377
+ raise NoMethodError, "typename or method is missing (#{type})"
378
+ end
379
+
380
+ addfield!(typeobj, args)
381
+ end
382
+
383
+ def addfield!(typeobj, args)
384
+ #p typeobj
385
+ # check extensible field >>> creator.fields[-1].vector[-1]
386
+ if (x = fields[-1]) && (x = x.vector) && x[-1] == 0
387
+ raise ArgumentError, "not given fields after extensible vector"
388
+ end
389
+
390
+ typesize = typeobj.bytesize
391
+ typealign = typeobj.bytealign
392
+
393
+ tmpfields = []
394
+
395
+ parse!(args) do |name, vect|
396
+ self.offset = offset.align_ceil(typealign) unless kind_of?(Model::Union::Creator)
397
+ fields << f = Field[offset, name, vect, typeobj, 0]
398
+ tmpfields << f
399
+ unless kind_of?(Model::Union::Creator)
400
+ elements = vect ? vect.inject(1, &:*) : 1
401
+ self.offset += typesize * elements
402
+ end
403
+ end
404
+
405
+ tmpfields
406
+ end
407
+ end
408
+
409
+ class Struct < Model
410
+ class Creator < Model::BasicCreator
411
+ def bytealign(bytesize)
412
+ raise NotImplementedError
413
+ end
414
+
415
+ def padding(bytesize)
416
+ raise NotImplementedError
417
+ end
418
+
419
+ def to_model
420
+ Model::Struct.new(offset.align_ceil(maxalign), maxalign, flatten_field)
421
+ end
422
+ end
423
+
424
+ def aset(buffer, offset, value)
425
+ raise NotImplementedError
426
+ end
427
+
428
+ def aref(buffer, offset)
429
+ v = Accessor::TemporaryStruct.new(buffer, offset, self)
430
+ v.infect_from(self, buffer) unless v.frozen?
431
+ v.freeze if frozen? || buffer.frozen?
432
+ v
433
+ end
434
+
435
+ def create_accessor
436
+ Accessor::Struct.define(self)
437
+ end
438
+ end
439
+
440
+ class Union < Model
441
+ class Creator < Model::BasicCreator
442
+ def to_model
443
+ Model::Union.new(maxsize.align_ceil(maxalign), maxalign, flatten_field)
444
+ end
445
+ end
446
+
447
+ def aset(buffer, offset, value)
448
+ raise NotImplementedError
449
+ end
450
+
451
+ def aref(buffer, offset)
452
+ v = Accessor::TemporaryUnion.new(buffer, offset, self)
453
+ v.infect_from(self, buffer) unless v.frozen?
454
+ v.freeze if frozen? || buffer.frozen?
455
+ v
456
+ end
457
+
458
+ def create_accessor
459
+ Accessor::Union.define(self)
460
+ end
461
+ end
462
+
463
+ #
464
+ # C の配列を模造するクラス。
465
+ #
466
+ class Array < Model
467
+ def extensible?
468
+ fields[-1] == 0 ? true : false
469
+ end
470
+
471
+ def aset(buffer, offset, value)
472
+ raise NotImplementedError
473
+ end
474
+
475
+ def aref(buffer, offset)
476
+ raise NotImplementedError
477
+ accessor = Accessor::Array[buffer, offset, self]
478
+ accessor.instance_eval do
479
+ field = fields[0]
480
+ type = field.type
481
+ elements = field.vector[-1]
482
+
483
+ define_singleton_method(:check_index, ->(i) {
484
+ i = i.to_i
485
+ raise IndexError unless i >= 0 && (elements.nil? || i < elements)
486
+ i
487
+ })
488
+
489
+ define_singleton_method(:[], ->(i) {
490
+ v = type.aref(buffer__GOGYOU__, offset__GOGYOU__ + type.bytesize * check_index(i))
491
+ v.infect_from(self, buffer) unless v.frozen?
492
+ v.freeze if frozen? || buffer.frozen? || field.const?
493
+ v
494
+ })
495
+
496
+ define_singleton_method(:[]=, ->(i, v) {
497
+ type.aset(buffer__GOGYOU__, offset__GOGYOU__ + type.bytesize * check_index(i), v)
498
+ })
499
+ end
500
+ accessor
501
+ end
502
+ end
503
+ end
504
+ end