1 | #! perl |
1 | #! perl |
2 | |
2 | |
3 | # actually geninterface |
3 | # used to automatically create accessors/mutators and method interfaces |
|
|
4 | # to C++ classes for Perl. |
|
|
5 | # also write data structures as JSON object, for reflection |
|
|
6 | |
|
|
7 | use JSON::XS; |
4 | |
8 | |
5 | my $class = shift; |
9 | my $class = shift; |
6 | my $curclass = ""; |
10 | my $curclass = ""; |
7 | my (@scalar_member, @array_member); |
11 | my (@scalar_member, @array_member); |
|
|
12 | |
|
|
13 | # convert c member name to perl |
|
|
14 | sub c2perl($) { |
|
|
15 | local $_ = shift; |
|
|
16 | |
|
|
17 | s/^([^.]+)\.\1_/$1\_/g; # tcpi.tcpi_xxx => tcpi_xxx |
|
|
18 | |
|
|
19 | $_ |
|
|
20 | } |
8 | |
21 | |
9 | for my $file (@ARGV) { |
22 | for my $file (@ARGV) { |
10 | open my $fh, "<:utf8", $file |
23 | open my $fh, "<:utf8", $file |
11 | or die "$file: $!"; |
24 | or die "$file: $!"; |
12 | |
25 | |
13 | while (<$fh>) { |
26 | while (<$fh>) { |
|
|
27 | next if /^\s*\//; # skip lines starting with / |
|
|
28 | if ($curclass eq $class) { |
14 | while (/ACC\s*\(R([WO])\s*,\s*([^)\]]+)(?:\[(\S+)\])?\)/g) { |
29 | while (/ACC\s*\(R([WO])\s*,\s*([^)\]]+)(?:\[(\S+)\])?\)/g) { |
15 | next unless $curclass eq $class; |
|
|
16 | |
|
|
17 | if ($3) { |
30 | if ($3) { |
18 | push @array_member, [$1, $2, $3]; |
31 | push @array_member, [$1, $2, $3]; |
19 | } else { |
32 | } else { |
20 | push @scalar_member, [$1, $2]; |
33 | push @scalar_member, [$1, $2]; |
|
|
34 | } |
|
|
35 | } |
|
|
36 | if (/MTH \s+ ([^(]*?) \s* ([A-Za-z_0-9]+) \s* \(([^)]*)\)/x) { |
|
|
37 | push @method_member, [$1, $2, $3]; |
21 | } |
38 | } |
22 | } |
39 | } |
23 | while (/INTERFACE_CLASS\s*\((\S+)\)/g) { |
40 | while (/INTERFACE_CLASS\s*\((\S+)\)/g) { |
24 | $curclass = $1; |
41 | $curclass = $1; |
25 | } |
42 | } |
26 | } |
43 | } |
|
|
44 | } |
|
|
45 | |
|
|
46 | for (@method_member) { |
|
|
47 | my ($rettype, $name, $params) = @$_; |
|
|
48 | |
|
|
49 | if ($rettype =~ s/static\s+//) { |
|
|
50 | my $args = join ", ", $params =~ m/.*?([a-zA-Z_0-9]+)(?:,\s*|$)/g; |
|
|
51 | if ($rettype ne "void") { |
|
|
52 | print "$rettype\n$name ($params)\n", |
|
|
53 | "\tCODE:\n", |
|
|
54 | "\tRETVAL = $class\::$name ($args);\n", |
|
|
55 | "\tOUTPUT:\n", |
|
|
56 | "\tRETVAL\n"; |
|
|
57 | } else { |
|
|
58 | print "$rettype\n$name ($params)\n", |
|
|
59 | "\tCODE:\n", |
|
|
60 | "\t$class\::$name ($args);\n", |
|
|
61 | } |
|
|
62 | } else { |
|
|
63 | print "$rettype\n$class\::$name ($params)\n"; |
|
|
64 | } |
|
|
65 | |
|
|
66 | print "\n"; |
27 | } |
67 | } |
28 | |
68 | |
29 | if (@scalar_member) { |
69 | if (@scalar_member) { |
30 | print "SV *$scalar_member[0][1] ($class *self, SV *newval = 0)\n"; |
70 | print "SV *$scalar_member[0][1] ($class *self, SV *newval = 0)\n"; |
31 | print "\tPROTOTYPE: \$;\$\n"; |
71 | print "\tPROTOTYPE: \$;\$\n"; |
32 | |
72 | |
33 | if (@scalar_member > 1) { |
73 | if (@scalar_member > 1) { |
34 | print "\tALIAS:\n"; |
74 | print "\tALIAS:\n"; |
35 | for (1 .. $#scalar_member) { |
75 | for (1 .. $#scalar_member) { |
36 | print "\t\t$scalar_member[$_][1]\t= $_\n"; |
76 | print "\t\t" . (c2perl $scalar_member[$_][1]) . "\t= $_\n"; |
37 | } |
77 | } |
38 | } |
78 | } |
39 | |
79 | |
40 | print "\tCODE:\n"; |
80 | print "\tCODE:\n"; |
41 | |
81 | |
|
|
82 | my $ix = @scalar_member == 1 ? 0 : "ix"; |
|
|
83 | |
42 | # read |
84 | # read |
43 | print "\tif (GIMME_V == G_VOID)\n", |
85 | print "\tif (GIMME_V == G_VOID)\n", |
44 | "\t RETVAL = &PL_sv_undef;\n", |
86 | "\t RETVAL = &PL_sv_undef;\n", |
45 | "\telse\n", |
87 | "\telse\n", |
46 | "\t switch (ix)\n", |
88 | "\t switch ($ix)\n", |
47 | "\t {\n", |
89 | "\t {\n", |
48 | (map "\t case $_: RETVAL = to_sv (self->$scalar_member[$_][1]); break;\n", |
90 | (map "\t case $_: RETVAL = to_sv (self->$scalar_member[$_][1]); break;\n", |
49 | 0 .. $#scalar_member), |
91 | 0 .. $#scalar_member), |
50 | "\t default: croak (\"scalar_member is write-only\");\n", |
92 | "\t default: croak (\"scalar_member is write-only\");\n", |
51 | "\t };\n"; |
93 | "\t };\n"; |
52 | |
94 | |
53 | # write |
95 | # write |
54 | print "\tif (newval)\n", |
96 | print "\tif (newval)\n", |
55 | "\t switch (ix)\n", |
97 | "\t switch ($ix)\n", |
56 | "\t {\n", |
98 | "\t {\n", |
57 | (map "\t case $_: sv_to (newval, self->$scalar_member[$_][1]); break;\n", |
99 | (map "\t case $_: sv_to (newval, self->$scalar_member[$_][1]); break;\n", |
58 | grep $scalar_member[$_][0] eq "W", |
100 | grep $scalar_member[$_][0] eq "W", |
59 | 0 .. $#scalar_member), |
101 | 0 .. $#scalar_member), |
60 | "\t default: croak (\"scalar_member is read-only\");\n", |
102 | "\t default: croak (\"scalar_member is read-only\");\n", |
… | |
… | |
68 | print "\tPROTOTYPE: \$;\$\n"; |
110 | print "\tPROTOTYPE: \$;\$\n"; |
69 | |
111 | |
70 | if (@array_member > 1) { |
112 | if (@array_member > 1) { |
71 | print "\tALIAS:\n"; |
113 | print "\tALIAS:\n"; |
72 | for (1 .. $#array_member) { |
114 | for (1 .. $#array_member) { |
73 | print "\t\t$array_member[$_][1]\t= $_\n"; |
115 | print "\t\t" . (c2perl $array_member[$_][1]) . "\t= $_\n"; |
74 | } |
116 | } |
75 | } |
117 | } |
76 | |
118 | |
77 | print "\tCODE:\n"; |
119 | print "\tCODE:\n"; |
78 | |
120 | |
79 | print "\tif (idx < 0) croak (\"negative array index\");\n"; |
121 | print "\tif (idx < 0) croak (\"negative array index\");\n"; |
80 | |
122 | |
|
|
123 | my $ix = @array_member == 1 ? 0 : "ix"; |
|
|
124 | |
81 | # range |
125 | # range |
82 | print "\t switch (ix)\n", |
126 | print "\t switch ($ix)\n", |
83 | "\t {\n", |
127 | "\t {\n", |
84 | (map "\t case $_: if (idx >= $array_member[$_][2]) croak (\"array index out of bounds\"); break;\n", |
128 | (map "\t case $_: if (idx >= $array_member[$_][2]) croak (\"array index out of bounds\"); break;\n", |
85 | 0 .. $#array_member), |
129 | 0 .. $#array_member), |
86 | "\t };\n"; |
130 | "\t };\n"; |
87 | |
131 | |
88 | # read |
132 | # read |
89 | print "\tif (GIMME_V == G_VOID)\n", |
133 | print "\tif (GIMME_V == G_VOID)\n", |
90 | "\t RETVAL = &PL_sv_undef;\n", |
134 | "\t RETVAL = &PL_sv_undef;\n", |
91 | "\telse\n", |
135 | "\telse\n", |
92 | "\t switch (ix)\n", |
136 | "\t switch ($ix)\n", |
93 | "\t {\n", |
137 | "\t {\n", |
94 | (map "\t case $_: RETVAL = to_sv (self->$array_member[$_][1] [idx]); break;\n", |
138 | (map "\t case $_: RETVAL = to_sv (self->$array_member[$_][1] [idx]); break;\n", |
95 | 0 .. $#array_member), |
139 | 0 .. $#array_member), |
96 | "\t default: croak (\"array_member is write-only\");\n", |
140 | "\t default: croak (\"array_member is write-only\");\n", |
97 | "\t };\n"; |
141 | "\t };\n"; |
98 | |
142 | |
99 | # write |
143 | # write |
100 | print "\tif (newval)\n", |
144 | print "\tif (newval)\n", |
101 | "\t switch (ix)\n", |
145 | "\t switch ($ix)\n", |
102 | "\t {\n", |
146 | "\t {\n", |
103 | (map "\t case $_: sv_to (newval, self->$array_member[$_][1] [idx]); break;\n", |
147 | (map "\t case $_: sv_to (newval, self->$array_member[$_][1] [idx]); break;\n", |
104 | grep $array_member[$_][0] eq "W", |
148 | grep $array_member[$_][0] eq "W", |
105 | 0 .. $#array_member), |
149 | 0 .. $#array_member), |
106 | "\t default: croak (\"array_member is read-only\");\n", |
150 | "\t default: croak (\"array_member is read-only\");\n", |
107 | "\t };\n"; |
151 | "\t };\n"; |
108 | |
152 | |
109 | print "\tOUTPUT: RETVAL\n\n"; |
153 | print "\tOUTPUT: RETVAL\n\n"; |
110 | } |
154 | } |
111 | |
155 | |
|
|
156 | my $json = JSON::XS->new->utf8->encode ({ |
|
|
157 | class => $class, |
|
|
158 | methods => { map +($_->[1], [$_->[0], $_->[2]]), @method_member }, |
|
|
159 | scalars => { map +($_->[1], [$_->[0] ]), @scalar_member }, |
|
|
160 | arrays => { map +($_->[1], [$_->[0], $_->[2]]), @array_member }, |
|
|
161 | }); |
|
|
162 | |
|
|
163 | $json = join "\n", map { |
|
|
164 | my $part = $_; |
|
|
165 | $part =~ s/(["\\])/\\$1/g; |
|
|
166 | "\"$part\"" |
|
|
167 | } unpack "(a80)*", $json; |
|
|
168 | |
|
|
169 | print "BOOT:\n", |
|
|
170 | "\tav_push (av_reflect, newSVpv ($json, 0));\n\n"; |
|
|
171 | |