cgen 0.16.6 → 0.16.7
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.
- data/History.txt +8 -0
- data/lib/cgen/attribute.rb +13 -1
- data/lib/cgen/cgen.rb +32 -6
- data/lib/cgen/cshadow.rb +54 -31
- data/test/test-attribute.rb +44 -1
- metadata +5 -5
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
cgen 0.16.7
|
2
|
+
|
3
|
+
- misc refactoring, cleanup, docs, error checking
|
4
|
+
|
5
|
+
- added BooleanAttribute with tests
|
6
|
+
|
7
|
+
- improved placement of alloc funcs in library init code
|
8
|
+
|
1
9
|
cgen 0.16.6
|
2
10
|
|
3
11
|
- optimization: don't generate a mark or free function when an attribute
|
data/lib/cgen/attribute.rb
CHANGED
@@ -199,7 +199,7 @@ module CShadow
|
|
199
199
|
super
|
200
200
|
@class = @match
|
201
201
|
|
202
|
-
ssn = @class.
|
202
|
+
ssn = @class.shadow_struct_name
|
203
203
|
|
204
204
|
@cvar = @var
|
205
205
|
if @class < CShadow
|
@@ -307,6 +307,18 @@ module CShadow
|
|
307
307
|
end
|
308
308
|
end
|
309
309
|
|
310
|
+
class BooleanAttribute < CNativeAttribute
|
311
|
+
@pattern = /\A(bool(?:ean)?)\s+(\w+)\z/
|
312
|
+
def initialize(*args)
|
313
|
+
super
|
314
|
+
@cdecl = @cdecl.sub(@match[1], "int")
|
315
|
+
@reader = "result = shadow->#{@cvar} ? Qtrue : Qfalse"
|
316
|
+
@writer = "shadow->#{@cvar} = RTEST(arg)" # type conversion
|
317
|
+
@dump = "rb_ary_push(result, shadow->#{@cvar} ? Qtrue : Qfalse)"
|
318
|
+
@load = "tmp = rb_ary_shift(from_array); shadow->#{@cvar} = RTEST(tmp)"
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
310
322
|
# Does not check for overflow.
|
311
323
|
class ShortAttribute < IntAttribute
|
312
324
|
@pattern = /\A(short)\s+(\w+)\z/
|
data/lib/cgen/cgen.rb
CHANGED
@@ -418,7 +418,7 @@ require 'cgen/inherit'
|
|
418
418
|
# way that makes clear that the problem is really with commit.
|
419
419
|
module CGenerator
|
420
420
|
|
421
|
-
VERSION = '0.16.
|
421
|
+
VERSION = '0.16.7'
|
422
422
|
|
423
423
|
class Accumulator ## should be a mixin? "Cumulative"?
|
424
424
|
|
@@ -624,7 +624,8 @@ class Library < Template
|
|
624
624
|
rb_define_method!,
|
625
625
|
rb_define_module_function!,
|
626
626
|
rb_define_global_function!,
|
627
|
-
rb_define_singleton_method
|
627
|
+
rb_define_singleton_method!,
|
628
|
+
rb_define_alloc_func!
|
628
629
|
## odd, putting an accum inside
|
629
630
|
## a template which is not the parent
|
630
631
|
end
|
@@ -1101,6 +1102,34 @@ class Library < Template
|
|
1101
1102
|
:rb_define_module_function,
|
1102
1103
|
:rb_define_global_function,
|
1103
1104
|
:rb_define_singleton_method) {RbDefineAccumulator}
|
1105
|
+
|
1106
|
+
class RbDefineAllocAccumulator < Accumulator
|
1107
|
+
def add spec
|
1108
|
+
klass = spec[:class]
|
1109
|
+
cfile = spec[:cfile]
|
1110
|
+
|
1111
|
+
if @pile.find {|s| s[:class] == klass}
|
1112
|
+
raise ArgumentError, "Duplicate alloc func definition for #{klass}"
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
klass_c_name =
|
1116
|
+
spec[:class_c_name] ||= @parent.declare_class(klass, cfile) ## @parent ?
|
1117
|
+
spec[:c_name] ||= "alloc_func_#{klass_c_name}".intern
|
1118
|
+
@pile << spec
|
1119
|
+
|
1120
|
+
spec[:c_name]
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
def to_s
|
1124
|
+
@pile.collect { |spec|
|
1125
|
+
c_name = spec[:c_name]
|
1126
|
+
klass_c_name = spec[:class_c_name]
|
1127
|
+
"rb_define_alloc_func(#{klass_c_name}, #{c_name});"
|
1128
|
+
}.join "\n"
|
1129
|
+
end
|
1130
|
+
end # class RbDefineAllocAccumulator
|
1131
|
+
|
1132
|
+
accumulator(:rb_define_alloc_func) {RbDefineAllocAccumulator}
|
1104
1133
|
|
1105
1134
|
# call-seq:
|
1106
1135
|
# define_c_method mod, name, subclass
|
@@ -1465,10 +1494,7 @@ class CFile < CFragment
|
|
1465
1494
|
alias define_c_class_method define_c_singleton_method
|
1466
1495
|
|
1467
1496
|
def define_alloc_func klass
|
1468
|
-
|
1469
|
-
c_name = "alloc_func_#{klass_c_name}"
|
1470
|
-
library.init_library_function.body \
|
1471
|
-
%{rb_define_alloc_func(#{klass_c_name}, #{c_name})}
|
1497
|
+
c_name = rb_define_alloc_func :class => klass, :cfile => self
|
1472
1498
|
define c_name, Function
|
1473
1499
|
end
|
1474
1500
|
|
data/lib/cgen/cshadow.rb
CHANGED
@@ -268,13 +268,7 @@ module CShadow
|
|
268
268
|
classes = Library.sort_class_tree(@classes_to_commit)
|
269
269
|
|
270
270
|
classes.each do |cl|
|
271
|
-
|
272
|
-
cl.shadow_struct
|
273
|
-
cl.new_method; cl._alloc_method
|
274
|
-
cl.check_inherited_functions
|
275
|
-
if cl == cl.base_class
|
276
|
-
cl._dump_data_method; cl._load_data_method
|
277
|
-
end
|
271
|
+
cl.fill_in_defs
|
278
272
|
end
|
279
273
|
end
|
280
274
|
|
@@ -468,8 +462,9 @@ module CShadow
|
|
468
462
|
if defined? @shadow_library_file
|
469
463
|
if file
|
470
464
|
raise RuntimeError,
|
471
|
-
"
|
472
|
-
"
|
465
|
+
"Cannot assign class #{self} to file #{file.inspect}; class" +
|
466
|
+
" is already associated" +
|
467
|
+
" with file #{@shadow_library_file[0].name}."
|
473
468
|
end
|
474
469
|
@shadow_library_file
|
475
470
|
elsif file
|
@@ -522,9 +517,9 @@ module CShadow
|
|
522
517
|
sf = shadow_library_source_file
|
523
518
|
m = sf.define_c_method self, name, subclass
|
524
519
|
m.scope :extern
|
525
|
-
m.declare :shadow => "#{
|
520
|
+
m.declare :shadow => "#{shadow_struct_name} *shadow"
|
526
521
|
m.setup :shadow =>
|
527
|
-
"Data_Get_Struct(self, #{
|
522
|
+
"Data_Get_Struct(self, #{shadow_struct_name}, shadow)"
|
528
523
|
m.instance_eval(&block) if block
|
529
524
|
m
|
530
525
|
end
|
@@ -562,7 +557,7 @@ module CShadow
|
|
562
557
|
def define_inheritable_c_function name,
|
563
558
|
subclass = CGenerator::Function, &block
|
564
559
|
sf = shadow_library_source_file
|
565
|
-
m = sf.define_c_function "#{name}_#{
|
560
|
+
m = sf.define_c_function "#{name}_#{shadow_struct_name}", subclass
|
566
561
|
c_function_templates[name] = m
|
567
562
|
m.scope :extern
|
568
563
|
m.instance_eval(&block) if block
|
@@ -571,7 +566,18 @@ module CShadow
|
|
571
566
|
|
572
567
|
#== Internal methods ==#
|
573
568
|
|
574
|
-
def
|
569
|
+
def fill_in_defs
|
570
|
+
shadow_struct
|
571
|
+
new_method; _alloc_method
|
572
|
+
|
573
|
+
check_inherited_functions
|
574
|
+
|
575
|
+
if self == base_class
|
576
|
+
_dump_data_method; _load_data_method
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
def c_function_templates; @c_function_templates ||= {}; end
|
575
581
|
# Note that {} nondeterministic, so these should only be used to
|
576
582
|
# check existence or get value, not to iterate.
|
577
583
|
|
@@ -581,15 +587,17 @@ module CShadow
|
|
581
587
|
superclass.find_super_function(sym))
|
582
588
|
end
|
583
589
|
|
584
|
-
# Construct the name used for the shadow struct.
|
590
|
+
# Construct the name used for the shadow struct. Attempts to preserve
|
591
|
+
# the full class path.
|
585
592
|
def shadow_struct_name
|
586
|
-
|
587
|
-
|
593
|
+
@shadow_struct_name ||=
|
594
|
+
name.gsub(/_/, '__').gsub(/::/, '_o_') + CShadow::SHADOW_SUFFIX
|
588
595
|
end
|
589
596
|
|
590
597
|
# Return the object for managing the shadow struct.
|
591
598
|
def shadow_struct
|
592
599
|
unless defined?(@shadow_struct) and @shadow_struct
|
600
|
+
raise if @inherited_shadow_struct
|
593
601
|
sf = shadow_library_source_file
|
594
602
|
ssn = shadow_struct_name
|
595
603
|
@shadow_struct = sf.declare_extern_struct(ssn)
|
@@ -599,7 +607,7 @@ module CShadow
|
|
599
607
|
sss = superclass.shadow_struct
|
600
608
|
shadow_struct.inherit\
|
601
609
|
sss.inherit!,
|
602
|
-
"/* #{superclass.
|
610
|
+
"/* #{superclass.shadow_struct_name} members */",
|
603
611
|
sss.declare!, " "
|
604
612
|
|
605
613
|
unless superclass.shadow_library_source_file ==
|
@@ -616,7 +624,7 @@ module CShadow
|
|
616
624
|
def new_method
|
617
625
|
unless defined?(@new_method) and @new_method
|
618
626
|
sf = shadow_library_source_file
|
619
|
-
ssn =
|
627
|
+
ssn = shadow_struct_name
|
620
628
|
mark_name = refer_to_function :mark
|
621
629
|
free_name = refer_to_function :free
|
622
630
|
@new_method = sf.define_c_singleton_method self,
|
@@ -647,20 +655,35 @@ module CShadow
|
|
647
655
|
@new_method
|
648
656
|
end
|
649
657
|
|
658
|
+
# Set of function names (symbols) that have been referenced in the
|
659
|
+
# implementation of this class. The names are like :free or :mark,
|
660
|
+
# rather than :free_in_class_C, to give a common identity to all free
|
661
|
+
# functions.
|
650
662
|
def referenced_functions
|
651
663
|
@referenced_functions ||= {}
|
652
664
|
end
|
653
665
|
|
666
|
+
# Generate a string which, by convention, names the function for
|
667
|
+
# instances of this particular class. Also, keeps track of
|
668
|
+
# referenced_functions.
|
654
669
|
def refer_to_function sym
|
655
670
|
referenced_functions[sym] = true
|
656
|
-
"#{sym}_#{
|
671
|
+
"#{sym}_#{shadow_struct_name}"
|
672
|
+
end
|
673
|
+
|
674
|
+
def inherited_function
|
675
|
+
@inherited_function ||= {}
|
657
676
|
end
|
658
677
|
|
678
|
+
# For each function referenced in this class, but not defined, resolve
|
679
|
+
# the reference by defining a macro to evaluate to the first
|
680
|
+
# implementation found by ascending the class tree.
|
659
681
|
def check_inherited_functions
|
660
682
|
syms = referenced_functions.keys.sort_by{|k|k.to_s}
|
661
683
|
syms.reject {|sym| c_function_templates[sym]}.each do |sym|
|
662
|
-
fname = "#{sym}_#{
|
684
|
+
fname = "#{sym}_#{shadow_struct_name}"
|
663
685
|
pf = find_super_function(sym)
|
686
|
+
inherited_function[sym] = true
|
664
687
|
pf_str = pf ? pf.name : (sym == :free ? -1 : 0)
|
665
688
|
# -1 means free the struct; See README.EXT
|
666
689
|
shadow_library_source_file.declare fname.intern =>
|
@@ -671,8 +694,9 @@ module CShadow
|
|
671
694
|
# Return the object for managing the mark function of the class.
|
672
695
|
def mark_function
|
673
696
|
unless defined?(@mark_function) and @mark_function
|
697
|
+
raise if inherited_function[:mark]
|
674
698
|
sf = shadow_library_source_file
|
675
|
-
ssn =
|
699
|
+
ssn = shadow_struct_name
|
676
700
|
@mark_function = define_inheritable_c_function(:mark, MarkFunction) do
|
677
701
|
arguments "#{ssn} *shadow"
|
678
702
|
return_type "void"
|
@@ -687,8 +711,9 @@ module CShadow
|
|
687
711
|
# Return the object for managing the free function of the class.
|
688
712
|
def free_function
|
689
713
|
unless defined?(@free_function) and @free_function
|
714
|
+
raise if inherited_function[:free]
|
690
715
|
sf = shadow_library_source_file
|
691
|
-
ssn =
|
716
|
+
ssn = shadow_struct_name
|
692
717
|
@free_function = define_inheritable_c_function(:free, FreeFunction) do
|
693
718
|
arguments "#{ssn} *shadow"
|
694
719
|
return_type "void"
|
@@ -706,8 +731,8 @@ module CShadow
|
|
706
731
|
return nil unless persistent?
|
707
732
|
unless defined?(@_dump_data_method) and @_dump_data_method
|
708
733
|
@_dump_data_method = define_c_method(:_dump_data, AttrMethod) {
|
709
|
-
declare :result => "VALUE
|
710
|
-
setup :result => "result
|
734
|
+
declare :result => "VALUE result"
|
735
|
+
setup :result => "result = rb_ary_new()"
|
711
736
|
body pre_code!, attr_code!, post_code!
|
712
737
|
returns "result"
|
713
738
|
}
|
@@ -743,7 +768,7 @@ module CShadow
|
|
743
768
|
return nil unless persistent?
|
744
769
|
unless defined?(@_alloc_method) and @_alloc_method
|
745
770
|
sf = shadow_library_source_file
|
746
|
-
ssn =
|
771
|
+
ssn = shadow_struct_name
|
747
772
|
mark_name = refer_to_function :mark
|
748
773
|
free_name = refer_to_function :free
|
749
774
|
@_alloc_method = sf.define_alloc_func(self)
|
@@ -857,7 +882,7 @@ module CShadow
|
|
857
882
|
end
|
858
883
|
|
859
884
|
source_file = shadow_library_source_file
|
860
|
-
ssn =
|
885
|
+
ssn = shadow_struct_name
|
861
886
|
@shadow_attrs ||= []
|
862
887
|
|
863
888
|
meths = nil
|
@@ -901,17 +926,15 @@ module CShadow
|
|
901
926
|
|
902
927
|
new_method.attr_code attr.init if attr.init
|
903
928
|
|
904
|
-
m = attr.mark
|
905
|
-
|
906
|
-
f = attr.free
|
907
|
-
free_function.free f if f
|
929
|
+
m = attr.mark and mark_function.mark m
|
930
|
+
f = attr.free and free_function.free f
|
908
931
|
|
909
932
|
if persistent?
|
910
933
|
if attr_persists
|
911
934
|
_dump_data_method.attr_code attr.dump
|
912
935
|
_load_data_method.attr_code attr.load
|
913
936
|
else
|
914
|
-
|
937
|
+
i = attr.init and _load_data_method.attr_code i
|
915
938
|
end
|
916
939
|
end
|
917
940
|
|
data/test/test-attribute.rb
CHANGED
@@ -154,7 +154,8 @@ class ShadowObjectAttributeTest < AttributeTest
|
|
154
154
|
n = ObjectSpace.each_object(c) {}
|
155
155
|
make_things c, 10
|
156
156
|
GC.start
|
157
|
-
|
157
|
+
n2 = ObjectSpace.each_object(c) {}
|
158
|
+
assert_send( [[n, n+1], :include?, n2] )
|
158
159
|
end
|
159
160
|
|
160
161
|
def test_marshal_uninitialized
|
@@ -258,6 +259,48 @@ class IntAttributeTest < AttributeTest
|
|
258
259
|
end
|
259
260
|
end
|
260
261
|
|
262
|
+
class BooleanAttributeTest < AttributeTest
|
263
|
+
class BooleanAttributeSample < AttributeSample
|
264
|
+
shadow_attr_accessor :x => "boolean x"
|
265
|
+
end
|
266
|
+
|
267
|
+
def test__initial
|
268
|
+
@ias = BooleanAttributeSample.new
|
269
|
+
assert_equal(false, @ias.x)
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_accessor
|
273
|
+
@ias = BooleanAttributeSample.new
|
274
|
+
@ias.x = true
|
275
|
+
assert_equal(true, @ias.x)
|
276
|
+
@ias.x = false
|
277
|
+
assert_equal(false, @ias.x)
|
278
|
+
@ias.x = nil
|
279
|
+
assert_equal(false, @ias.x)
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_conversion
|
283
|
+
@ias = BooleanAttributeSample.new
|
284
|
+
@ias.x = 5
|
285
|
+
assert_equal(true, @ias.x)
|
286
|
+
@ias.x = {:foo => "bar"}
|
287
|
+
assert_equal(true, @ias.x)
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_marshal
|
291
|
+
@ias = BooleanAttributeSample.new
|
292
|
+
@ias.x = true
|
293
|
+
s = Marshal.dump @ias
|
294
|
+
t = Marshal.load s
|
295
|
+
assert_equal(@ias.x, t.x)
|
296
|
+
|
297
|
+
@ias.x = false
|
298
|
+
s = Marshal.dump @ias
|
299
|
+
t = Marshal.load s
|
300
|
+
assert_equal(@ias.x, t.x)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
261
304
|
class LongAttributeTest < AttributeTest
|
262
305
|
class LongAttributeSample < AttributeSample
|
263
306
|
shadow_attr_accessor :x => "long x"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cgen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 81
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 16
|
9
|
-
-
|
10
|
-
version: 0.16.
|
9
|
+
- 7
|
10
|
+
version: 0.16.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Joel VanderWerf
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-08-11 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -124,6 +124,6 @@ signing_key:
|
|
124
124
|
specification_version: 3
|
125
125
|
summary: C code generator
|
126
126
|
test_files:
|
127
|
-
- test/test-attribute.rb
|
128
127
|
- test/test-cgen.rb
|
128
|
+
- test/test-attribute.rb
|
129
129
|
- test/test-cshadow.rb
|