cgen 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/History.txt +199 -0
- data/README.txt +34 -0
- data/examples/bench.rb +14 -0
- data/examples/complex.rb +63 -0
- data/examples/complex2.rb +48 -0
- data/examples/cshadow-example.rb +55 -0
- data/examples/cshadow-point.rb +58 -0
- data/examples/ctest.rb +34 -0
- data/examples/ctest2.rb +32 -0
- data/examples/ctest3.rb +179 -0
- data/examples/ctest4.rb +18 -0
- data/examples/ctest5.rb +27 -0
- data/examples/example-ruby-talk-30April2004.rb +65 -0
- data/examples/fixed-array.rb +221 -0
- data/examples/inherit-example.rb +26 -0
- data/examples/inherit-example.txt +80 -0
- data/examples/instance-eval.rb +66 -0
- data/examples/ivset.rb +55 -0
- data/examples/marshal-test.rb +19 -0
- data/examples/matrix.rb +91 -0
- data/examples/modular-def.rb +87 -0
- data/examples/objattr.rb +46 -0
- data/examples/opaque-struct-test.rb +36 -0
- data/examples/sample.rb +184 -0
- data/examples/struct.rb +103 -0
- data/examples/test.rb +24 -0
- data/examples/yaml.rb +56 -0
- data/install.rb +1015 -0
- data/lib/cgen/attribute.rb +414 -0
- data/lib/cgen/cgen.rb +2041 -0
- data/lib/cgen/cshadow.rb +1037 -0
- data/lib/cgen/inherit.rb +46 -0
- data/rakefile +42 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- data/test/test-attribute.rb +430 -0
- data/test/test-cgen.rb +127 -0
- data/test/test-cshadow.rb +289 -0
- data/test/test.rb +17 -0
- metadata +123 -0
data/History.txt
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
cgen 0.16.0
|
2
|
+
|
3
|
+
- Moved to Mr. Bones, git, gems, rubyforge.
|
4
|
+
|
5
|
+
- API doc reformatted from rd2 to rdoc.
|
6
|
+
|
7
|
+
cgen 0.15
|
8
|
+
|
9
|
+
- Reinstated "extern" for extern prototypes.
|
10
|
+
|
11
|
+
- CShadow.shadow_attr returns list of handles to the r/w funcs
|
12
|
+
|
13
|
+
- CGen does 'make clean' if extconf.rb changes
|
14
|
+
|
15
|
+
- #extconf yields line array
|
16
|
+
|
17
|
+
- Attributes remember their owner_class.
|
18
|
+
|
19
|
+
cgen 0.14
|
20
|
+
|
21
|
+
- Fixed to work with the YAML changes in ruby 1.8.4.
|
22
|
+
|
23
|
+
cgen 0.13
|
24
|
+
|
25
|
+
- InitAccumulators were writing code to execute every time, rather
|
26
|
+
than just the first time. Fixed the bug.
|
27
|
+
|
28
|
+
- #declare_struct may be passed attributes, such as
|
29
|
+
"__attribute__((__packed__))"
|
30
|
+
|
31
|
+
- Fixed a bug caused by having more than one ruby interpreter installed.
|
32
|
+
|
33
|
+
- MSVC compatibility fixes.
|
34
|
+
|
35
|
+
cgen 0.12
|
36
|
+
|
37
|
+
- CShadow.define_c_function for convenience.
|
38
|
+
|
39
|
+
- Improved sorting of component classes to reduce nondeterminism in code
|
40
|
+
generation, and to thereby reduce time to rebuild.
|
41
|
+
|
42
|
+
- Reorgnized CShadow base classes so that methods are provided by
|
43
|
+
extending with a module, CShadowClassMethods, instead of being
|
44
|
+
defined individually in each base class. This means that they can be
|
45
|
+
overridden and called with super. It's also cleaner and probably
|
46
|
+
faster.
|
47
|
+
|
48
|
+
- Included examples/yaml.rb, which was mistakenly left out of 0.11
|
49
|
+
|
50
|
+
- CShadow#inspect added. Shows both shadow attrs and instance vars.
|
51
|
+
|
52
|
+
cgen 0.11
|
53
|
+
|
54
|
+
- CShadow classes are YAML friendly--see docs on cshadow and
|
55
|
+
examples/yaml.rb.
|
56
|
+
|
57
|
+
- Library#literal_symbol to streamline use of rb_hash_aref etc.
|
58
|
+
|
59
|
+
- Improved granularity for efficient separate compilation.
|
60
|
+
|
61
|
+
- Improved indentation in CFunctions.
|
62
|
+
|
63
|
+
- CShadow: added a new statement accumulators to _dump_data_method
|
64
|
+
and _load_data_method, called 'pre_code' and 'post_code',
|
65
|
+
replacing 'extra_code'.
|
66
|
+
|
67
|
+
- Library#extconf should now return a string or array of strings,
|
68
|
+
which will be used as the contents of extconf.rb.
|
69
|
+
|
70
|
+
cgen 0.10
|
71
|
+
|
72
|
+
- For versions of ruby 1.7.3 and 1.8 after 20Dec2002, we use
|
73
|
+
rb_define_alloc_func() instead of defining an "allocate" class method,
|
74
|
+
which would cause a warning.
|
75
|
+
|
76
|
+
- Tested with MinGW/MSYS on Windows.
|
77
|
+
|
78
|
+
- Deprecated methods (define_method and define_class_method) removed. See
|
79
|
+
notes for 0.9, below.
|
80
|
+
|
81
|
+
cgen 0.9 [Never released]
|
82
|
+
|
83
|
+
- Now uses standard install.rb.
|
84
|
+
|
85
|
+
- Updated to ruby-1.7.3, 2002-10-30. (CShadow no longer uses class vars,
|
86
|
+
since their semantics have changed. It uses class instance vars instead.)
|
87
|
+
|
88
|
+
- Tested with ruby-1.6.7 and ruby-1.7.3 (no patch needed for either).
|
89
|
+
Patch for marshal.c in ruby-1.6.6 is still included.
|
90
|
+
|
91
|
+
- Tests now use Test::Unit.
|
92
|
+
|
93
|
+
- [INTERFACE CHANGE] Library#define_method and the define_method class
|
94
|
+
methods in shadow classes are now deprecated. They work correctly but issue
|
95
|
+
a warning. They will be removed in future releases. Use #define_c_method
|
96
|
+
instead. This change is necessary because ruby-1.7 already has
|
97
|
+
Module.define_method. For consistency, this name change propagates to other
|
98
|
+
define methods:
|
99
|
+
|
100
|
+
define --> define_c_function
|
101
|
+
define_method --> define_c_method
|
102
|
+
define_module_function --> define_c_module_function
|
103
|
+
define_global_function --> define_c_global_function
|
104
|
+
define_singleton_method --> define_c_singleton_method
|
105
|
+
|
106
|
+
cgen 0.8
|
107
|
+
- Minor fix to install.rb for compatibility with ruby 1.7.
|
108
|
+
- CGenerator::Library's purge_source_dir attribute now applies to .o files
|
109
|
+
as well as .c and .h.
|
110
|
+
- Shadow attributes can now be nonpersistent, using the :nonpersistent flag
|
111
|
+
in shadow_attr_accessor declarations. This reduces library size as well
|
112
|
+
as the size of the persistant image.
|
113
|
+
- CShadow: added a new statement accumulator to _dump_data_method and
|
114
|
+
_load_data_method, called 'extra_code', which can be used to pre- (in
|
115
|
+
the case of dump) or post- (in the case of load) process the object. For
|
116
|
+
instance, additonal (nonpersistent) resources may need to be created or
|
117
|
+
initialized based on the loaded attr values.
|
118
|
+
- [Interface change] Removed the before_commit and after_commit methods from
|
119
|
+
CShadow and added more general methods to CGen::Library, to which CShadow
|
120
|
+
delegates. See the docs in cshadow.rb.
|
121
|
+
|
122
|
+
cgen 0.7
|
123
|
+
- Added makedepend step to compilation so that the resulting library
|
124
|
+
reflects changes in headers. Library#makedepend can be overridden.
|
125
|
+
- Added CommentAccumulator, and gave each CFile a CommentAccumulator
|
126
|
+
called 'preamble' that comes before the include accumulator.
|
127
|
+
- Factored Library#write into #write and #update_file to give finer grained
|
128
|
+
control over checking whether a file needs updating.
|
129
|
+
- Added the purge_source_dir attribute of a library to optionally delete
|
130
|
+
or rename any source files that are not part of the current generation.
|
131
|
+
- Added show_times method (controlled by @@show_times) to print timing
|
132
|
+
information for the steps of the commit process.
|
133
|
+
|
134
|
+
cgen 0.6
|
135
|
+
- Fixed a bug in CShadow which caused attr initializers not to be
|
136
|
+
inherited by the 'new' method of a subclass. Fixed similar bugs
|
137
|
+
with attr dump and load code. Added tests for these.
|
138
|
+
- Added optional subclass arg to define_method, define_singleton_method,
|
139
|
+
etc. The subclass arg allows the generated template to belong to a
|
140
|
+
subclass of the function template it would normally belong to.
|
141
|
+
- IntAttribute, LongAttribute: Use INT2NUM rather than INT2FIX to handle
|
142
|
+
numbers on the order of 2**30 (n<=2**29 was ok before, n>=2**31 is too
|
143
|
+
large for native longs, and raises an exception). Added tests for this.
|
144
|
+
|
145
|
+
cgen 0.5
|
146
|
+
- Added before_commit and after_commit hooks for CShadow classes.
|
147
|
+
- Added LongAttribute.
|
148
|
+
- The protected and private declarations work on shadow attrs (in
|
149
|
+
the command form "protected :x", but not in the block form
|
150
|
+
"protected; shadow_attr_reader :x ...").
|
151
|
+
- declare_struct now uses declare, rather than a separate accumulator,
|
152
|
+
so that the order of declarations in a file is preserved.
|
153
|
+
|
154
|
+
cgen 0.4
|
155
|
+
- With a patch to marshal.c in the ruby source, CShadow now handles
|
156
|
+
marshalling of shadow objects. See attribute.rb and marshal.patch.
|
157
|
+
- Tests added to attribute.rb for marshalling.
|
158
|
+
- CGenerator::Structure now allows recursive structs, so this works:
|
159
|
+
class Foo; include CShadow; shadow_attr_accessor :foo => [Foo]
|
160
|
+
(It always worked without the [], but that's another beast.)
|
161
|
+
|
162
|
+
cgen 0.3
|
163
|
+
- Shadow structures: C structs painlessly attached to Ruby objects.
|
164
|
+
- Extensible architecture for shadow attributes
|
165
|
+
- Basic attributes for int, double, char*, Ruby object, etc.
|
166
|
+
- Inheritance of attributes.
|
167
|
+
- See docs in cshadow.html and attribute.html.
|
168
|
+
- Structure "inheritance":
|
169
|
+
a_struct.inherit another_struct.declare!
|
170
|
+
- Libraries are now inspectible, with hierarchical display of nested
|
171
|
+
templates and accumulators.
|
172
|
+
- Optional type checking for c_array_args.
|
173
|
+
- It's now easy to send definitions to other .c files besides the
|
174
|
+
main one for the library. See documentation for "add_file" and the
|
175
|
+
example in cgen.rb. CShadow takes advantage of this feature.
|
176
|
+
- Finer granularity in cgen's make process: write, mkmf, and make are
|
177
|
+
separate; mkmf still calls Library#extconf. You can pass arguments
|
178
|
+
to #make that the make program understands, such as 'distclean'.
|
179
|
+
- Cgen has now improved from alpha to beta quality code. Testing is
|
180
|
+
fairly thorough, especially in cshadow.rb and attribute.rb, and
|
181
|
+
documentation covers all public methods and many internal methods.
|
182
|
+
- Updated to work with Ruby 1.6.6.
|
183
|
+
- Now installs all four library files into cgen/ dir (the location of
|
184
|
+
this dir is controllable with the -d arg to install.rb.)
|
185
|
+
|
186
|
+
cgen 0.2
|
187
|
+
- Nice syntax for required, optional, rest, and block arguments, using
|
188
|
+
rb_scan_args. Performs default initialization for optional arguments.
|
189
|
+
See new code in sample.rb.
|
190
|
+
- Methods and other RubyFunctions return nil by default.
|
191
|
+
- Runs mkmf.rb in a forked process, because:
|
192
|
+
1. mkmf uses global scope |:(
|
193
|
+
2. might need to run mkmf twice in one session
|
194
|
+
3. this puts the mkmf log file in the lib dir, not the main dir.
|
195
|
+
- The cwd when the extension is 'require'-d is now the same as the main dir.
|
196
|
+
- Fixed bug with #c_array_args in the RubyFunction classes.
|
197
|
+
|
198
|
+
cgen 0.1
|
199
|
+
- First public release. Alpha, but basic functionality seems to work.
|
data/README.txt
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
high level overview
|
3
|
+
|
4
|
+
purpose and history
|
5
|
+
|
6
|
+
getting started
|
7
|
+
|
8
|
+
- will need compiler
|
9
|
+
|
10
|
+
advanced
|
11
|
+
|
12
|
+
==Object attributes
|
13
|
+
|
14
|
+
===class CShadow::ObjectAttribute
|
15
|
+
|
16
|
+
===class CShadow::ShadowObjectAttribute
|
17
|
+
|
18
|
+
|
19
|
+
examples
|
20
|
+
|
21
|
+
more docs
|
22
|
+
|
23
|
+
|
24
|
+
==web site
|
25
|
+
|
26
|
+
==license
|
27
|
+
|
28
|
+
==author
|
29
|
+
Copyright 2001-2009
|
30
|
+
Joel VanderWerf,
|
31
|
+
mailto:vjoel@users.sourceforge.net
|
32
|
+
|
33
|
+
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/24443
|
34
|
+
|
data/examples/bench.rb
ADDED
data/examples/complex.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'cgen/cshadow'
|
4
|
+
|
5
|
+
class MyComplex < Numeric
|
6
|
+
include CShadow
|
7
|
+
|
8
|
+
shadow_attr_accessor :re => "double re", :im => "double im"
|
9
|
+
|
10
|
+
def initialize re, im
|
11
|
+
self.re = re
|
12
|
+
self.im = im
|
13
|
+
end
|
14
|
+
|
15
|
+
define_c_method(:abs) {
|
16
|
+
include "<math.h>"
|
17
|
+
returns "rb_float_new(sqrt(pow(shadow->re, 2) + pow(shadow->im, 2)))"
|
18
|
+
}
|
19
|
+
|
20
|
+
define_c_method(:mul!) {
|
21
|
+
arguments :other
|
22
|
+
declare :other_shadow => "MyComplex_Shadow *other_shadow"
|
23
|
+
declare :new_re => "double new_re", :new_im => "double new_im"
|
24
|
+
body %{
|
25
|
+
switch (TYPE(other)) {
|
26
|
+
case T_FIXNUM: shadow->re *= FIX2INT(other);
|
27
|
+
shadow->im *= FIX2INT(other); break;
|
28
|
+
case T_FLOAT: shadow->re *= NUM2DBL(other);
|
29
|
+
shadow->im *= NUM2DBL(other); break;
|
30
|
+
default:
|
31
|
+
if (rb_obj_is_kind_of(other, #{declare_class MyComplex}) ==
|
32
|
+
Qtrue) {
|
33
|
+
Data_Get_Struct(other, MyComplex_Shadow, other_shadow);
|
34
|
+
new_re = shadow->re * other_shadow->re -
|
35
|
+
shadow->im * other_shadow->im;
|
36
|
+
new_im = shadow->re * other_shadow->im +
|
37
|
+
shadow->im * other_shadow->re;
|
38
|
+
shadow->re = new_re;
|
39
|
+
shadow->im = new_im;
|
40
|
+
}
|
41
|
+
else
|
42
|
+
rb_raise(#{declare_class ArgumentError},
|
43
|
+
"Argument to mul! is not numeric.");
|
44
|
+
}
|
45
|
+
}
|
46
|
+
returns "self"
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
require 'ftools'
|
51
|
+
dir = File.join("tmp", RUBY_VERSION)
|
52
|
+
File.mkpath dir
|
53
|
+
Dir.chdir dir
|
54
|
+
|
55
|
+
MyComplex.commit
|
56
|
+
|
57
|
+
z = MyComplex.new 5, 1.3
|
58
|
+
puts z.abs
|
59
|
+
z.mul! 10
|
60
|
+
p [z.re, z.im]
|
61
|
+
w = MyComplex.new 7.9, -1.2
|
62
|
+
z.mul! w
|
63
|
+
p [z.re, z.im]
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'cgen/cshadow'
|
4
|
+
|
5
|
+
class MyComplex2 < Numeric
|
6
|
+
include CShadow
|
7
|
+
|
8
|
+
shadow_attr_accessor :re => "double re", :im => "double im"
|
9
|
+
|
10
|
+
def initialize re, im
|
11
|
+
self.re = re
|
12
|
+
self.im = im
|
13
|
+
end
|
14
|
+
|
15
|
+
define_c_method(:abs) {
|
16
|
+
include "<math.h>"
|
17
|
+
returns "rb_float_new(sqrt(pow(shadow->re, 2) + pow(shadow->im, 2)))"
|
18
|
+
}
|
19
|
+
|
20
|
+
define_c_method(:scale!) {
|
21
|
+
c_array_args {
|
22
|
+
optional :factor
|
23
|
+
default :factor => "INT2NUM(10)"
|
24
|
+
typecheck :factor => Numeric
|
25
|
+
}
|
26
|
+
body %{
|
27
|
+
shadow->re *= NUM2DBL(factor);
|
28
|
+
shadow->im *= NUM2DBL(factor);
|
29
|
+
}
|
30
|
+
returns "self"
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
require 'ftools'
|
35
|
+
dir = File.join("tmp", RUBY_VERSION)
|
36
|
+
File.mkpath dir
|
37
|
+
Dir.chdir dir do
|
38
|
+
MyComplex2.commit
|
39
|
+
end
|
40
|
+
|
41
|
+
z = MyComplex2.new 5, 1.3
|
42
|
+
puts z.abs # ==> 5.1662365412358
|
43
|
+
z.scale! 3.0 # float
|
44
|
+
p [z.re, z.im] # ==> [15.0, 3.9]
|
45
|
+
z.scale! 3 # int
|
46
|
+
p [z.re, z.im] # ==> [45.0, 11.7]
|
47
|
+
z.scale! # use default value
|
48
|
+
p [z.re, z.im] # ==> [450.0, 117]
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/env/bin ruby
|
2
|
+
|
3
|
+
require 'cgen/cshadow'
|
4
|
+
|
5
|
+
class Test
|
6
|
+
include CShadow
|
7
|
+
shadow_attr_accessor\
|
8
|
+
:i => "int ii",
|
9
|
+
:d => "double d"
|
10
|
+
shadow_attr_reader :obj => Object
|
11
|
+
end
|
12
|
+
|
13
|
+
class SubTest < Test
|
14
|
+
shadow_attr :hidden_array => Array
|
15
|
+
shadow_attr_accessor\
|
16
|
+
:foo => "char *foo",
|
17
|
+
:bar => Symbol,
|
18
|
+
:test => [Test]
|
19
|
+
end
|
20
|
+
|
21
|
+
class OtherSubTest < Test
|
22
|
+
shadow_attr_accessor :j => "int j"
|
23
|
+
def initialize j_init
|
24
|
+
self.j = j_init
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class SubSubTest < SubTest
|
29
|
+
shadow_attr_accessor :z => Object
|
30
|
+
end
|
31
|
+
|
32
|
+
require 'ftools'
|
33
|
+
dir = File.join("tmp", RUBY_VERSION)
|
34
|
+
File.mkpath dir
|
35
|
+
Dir.chdir dir
|
36
|
+
|
37
|
+
SubTest.commit # same as Test.commit
|
38
|
+
|
39
|
+
x = SubTest.new
|
40
|
+
puts "i = #{x.i}, d = #{x.d}, " +
|
41
|
+
"foo = #{x.foo.inspect}, bar = #{x.bar.inspect}"
|
42
|
+
x.i = 7.5; x.d = 3; x.foo = "fred"; x.bar = :WILMA
|
43
|
+
puts "i = #{x.i}, d = #{x.d}, " +
|
44
|
+
"foo = #{x.foo.inspect}, bar = #{x.bar.inspect}"
|
45
|
+
|
46
|
+
y = OtherSubTest.new -123456789
|
47
|
+
puts y.j, y.d
|
48
|
+
|
49
|
+
# make sure ShadowAttribute works
|
50
|
+
puts "x.test = #{x.test || 'nil'}"
|
51
|
+
x.test = y
|
52
|
+
puts "x.test = #{x.test || 'nil'}"
|
53
|
+
puts x.test.j
|
54
|
+
|
55
|
+
SubSubTest.each_shadow_attr {|x| p x}
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/env/bin ruby
|
2
|
+
|
3
|
+
require 'cgen/cshadow'
|
4
|
+
|
5
|
+
class Point
|
6
|
+
include CShadow
|
7
|
+
|
8
|
+
###
|
9
|
+
|
10
|
+
shadow_attr_accessor\
|
11
|
+
:i => "int ii",
|
12
|
+
:d => "double d"
|
13
|
+
shadow_attr_reader :obj => Object
|
14
|
+
end
|
15
|
+
|
16
|
+
class SubTest < Test
|
17
|
+
shadow_attr :hidden_array => Array
|
18
|
+
shadow_attr_accessor\
|
19
|
+
:foo => "char *foo",
|
20
|
+
:bar => Symbol,
|
21
|
+
:test => [Test]
|
22
|
+
end
|
23
|
+
|
24
|
+
class OtherSubTest < Test
|
25
|
+
shadow_attr_accessor :j => "int j"
|
26
|
+
def initialize j_init
|
27
|
+
self.j = j_init
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class SubSubTest < SubTest
|
32
|
+
shadow_attr_accessor :z => Object
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'ftools'
|
36
|
+
dir = File.join("tmp", RUBY_VERSION)
|
37
|
+
File.mkpath dir
|
38
|
+
Dir.chdir dir
|
39
|
+
|
40
|
+
SubTest.commit # same as Test.commit
|
41
|
+
|
42
|
+
x = SubTest.new
|
43
|
+
puts "i = #{x.i}, d = #{x.d}, " +
|
44
|
+
"foo = #{x.foo.inspect}, bar = #{x.bar.inspect}"
|
45
|
+
x.i = 7.5; x.d = 3; x.foo = "fred"; x.bar = :WILMA
|
46
|
+
puts "i = #{x.i}, d = #{x.d}, " +
|
47
|
+
"foo = #{x.foo.inspect}, bar = #{x.bar.inspect}"
|
48
|
+
|
49
|
+
y = OtherSubTest.new -123456789
|
50
|
+
puts y.j, y.d
|
51
|
+
|
52
|
+
# make sure ShadowAttribute works
|
53
|
+
puts "x.test = #{x.test || 'nil'}"
|
54
|
+
x.test = y
|
55
|
+
puts "x.test = #{x.test || 'nil'}"
|
56
|
+
puts x.test.j
|
57
|
+
|
58
|
+
SubSubTest.each_shadow_attr {|x| p x}
|