source: EcnlProtoTool/trunk/asp3_dcre/tecsgen/tecslib/plugin/MrubyBridgePlugin.rb@ 321

Last change on this file since 321 was 321, checked in by coas-nagasima, 7 years ago

文字コードを設定

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby;charset=UTF-8
File size: 39.3 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# mruby => TECS bridge
4#
5# Copyright (C) 2008-2015 by TOPPERS Project
6#
7# 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
8# ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
9# 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
10# (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
11# 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
12# スコード中に含まれていること.
13# (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
14# 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
15# 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
16# の無保証規定を掲載すること.
17# (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
18# 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
19# と.
20# (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
21# 作権表示,この利用条件および下記の無保証規定を掲載すること.
22# (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
23# 報告すること.
24# (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
25# 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
26# また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
27# 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
28# 免責すること.
29#
30# 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
31# よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
32# に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
33# アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
34# の責任を負わない.
35#
36# $Id$
37#
38
39# Todo:
40# 生成するもの
41# gen_cdl_file
42# ブリッジ初期化セルタイプ (シグニチャごと)
43# @@init_celltypes に記録
44# ブリッジセルタイプ (シグニチャごと)
45# @@celltypes に記録
46# 構造体セルタイプ
47# @@struct_list に記録
48# new_cell
49# TECS 初期化セル(プロトタイプ宣言)
50# @@VM_init_cells に記録
51# @@VM_struct_list に記録
52# @@VM_ptr_list に記録
53# gen_post_code
54# 構造体初期化セル
55# ポインタ初期化セル
56# TECS 初期化セル
57#
58# ep_func の作成
59# signature, ポインタ、構造体 … 初期化受け口=mruby VM への登録
60# ポインタ
61# preamble の作成
62# ポインタ、構造体 … アクセス用コードの生成
63# signature … ブリッジ関数のプロトタイプ宣言
64# postamble の作成
65# signature … ブリッジ関数の定義
66
67class MrubyBridgePlugin < SignaturePlugin
68
69 # プラグイン引数名 => Proc
70 MrubyBridgePluginArgProc = {
71 "ignoreUnsigned" => Proc.new { |obj,rhs| obj.set_ignoreUnsigned rhs },
72 "include" => Proc.new { |obj,rhs| obj.set_include rhs },
73 "exclude" => Proc.new { |obj,rhs| obj.set_exclude rhs },
74 }
75
76 @@celltypes = { } # {celltype_name => [ BridgePlugin のインスタンスの配列 }
77 @@init_celltypes = { } # {celltype_name => [ BridgePlugin のインスタンスの配列 }
78 @@struct_list = { } # {struct_name=>StructType}
79 @@ptr_list = { } # {ptr_celltype_name=> @@TYPE_MAP の対応するもの}
80 @@VM_list = { } # VM_name => true
81 @@VM_celltypes = { } # VM_name => { @celltype_name => セルの配列 }
82 @@VM_struct_list = { } # {name=>StructType}
83 @@VM_ptr_list = { } # { VM_name => {name=> @@TYPE_MAP の対応するもの} }
84 @@TYPE_MAP = { # type_str class GET_SET
85 :char_t => [:char_t, "Char", :Char, :INT ],
86 :uchar_t => [:uchar_t, "UChar", :Char, :INT ],
87 :schar_t => [:schar_t, "SChar", :Char, :INT ],
88
89 :bool_t => [:bool_t, "Bool", :Bool, :BOOL ],
90 :int8_t => [:int8_t, "Int8", :Int, :INT ],
91 :int16_t => [:int16_t, "Int16", :Int, :INT ],
92 :int32_t => [:int32_t, "Int32", :Int, :INT ],
93 :int64_t => [:int64_t, "Int64", :Int, :INT ],
94 :uint8_t => [:uint8_t, "UInt8", :Int, :INT ],
95 :uint16_t => [:uint16_t, "UInt16", :Int, :INT ],
96 :uint32_t => [:uint32_t, "UInt32", :Int, :INT ],
97 :uint64_t => [:uint64_t, "UInt64", :Int, :INT ],
98
99 :int => [:int, "Int", :Int, :INT ],
100 :char => [:char, "Char", :Char, :INT ], # char は char_t として扱う
101 :short => [:short, "Short", :Int, :INT ],
102 :long => [:long, "Long", :Int, :INT ],
103
104 :"unsigned char" => [:uchar_t, "UChar", :Char, :INT ],
105 :"unsigned int" => [:"unsigned int", "UInt", :Int, :INT ],
106 :"unsigned short" => [:"unsigned short", "UShort", :Int, :INT ],
107 :"unsigned long" => [:"unsigned long", "ULong", :Int, :INT ],
108 :"signed char" => [:schar_t, "SChar", :Char, :INT ],
109 :"signed int" => [:int, "Int", :Int, :INT ],
110 :"signed short" => [:short, "Short", :Int, :INT ],
111 :"signed long" => [:long, "Long", :Int, :INT ],
112
113 :float32_t => [:float32_t, "Float32", :Float, :FLOAT ],
114 :double64_t => [:double64_t,"Double64", :Float, :FLOAT ],
115
116 :float => [:float, "Float32", :Float, :FLOAT ],
117 :double => [:double, "Double64", :Float, :FLOAT ]
118 }
119
120 # included or excluded functions
121
122 ### ロードされた時点で実行される ###
123
124 # -I に $(TECSPATH)/mruby を追加
125 # TECSGEN::Makefile.add_obj "$(MRUBY_MAIN_OBJ)"
126 TECSGEN::Makefile.add_ldflag "-lmruby -L$(MRUBYPATH)/lib -lm"
127 TECSGEN::Makefile.add_search_path "$(MRUBYPATH)/include"
128 TECSGEN::Makefile.add_var "MRUBYPATH", "..", "CHANGE this to suitable path"
129 # TECSGEN::Makefile.add_var "MRUBY_MAIN_OBJ", "$(_TECS_OBJ_DIR)tecs_mruby.o", "CHANGE this if your have your main"
130
131
132 #=== プラグインインスタンスの初期化
133 # 戻り値、引数の型が使用可能なものかチェックする
134 #
135 def initialize( signature, option )
136 super
137
138 if ! $no_banner
139 STDERR << "MrubyBridgePlugin: version 1.2.0 (Suitable for mruby ver 1.2.0. Has backward compatibility with ver 1.1.0)\n"
140 end
141
142 @b_ignoreUnsigned = false
143 @includes = []
144 @excludes = []
145 @struct_list = { }
146 @ptr_list = { }
147
148 @plugin_arg_check_proc_tab = MrubyBridgePluginArgProc
149 parse_plugin_arg
150
151 @celltype_name = :"t#{@signature.get_global_name}"
152 @init_celltype_name = :"#{@celltype_name}_Initializer"
153 # this variable is sometimes not used. rhs coded directry.
154 @class_name = :"T#{@signature.get_global_name}"
155
156 @func_head_array = []
157 if @includes.length > 0 && @excludes.length > 0 then
158 cdl_error( "MRB1011 both include && exclude are specified" )
159 end
160
161 if signature.get_function_head_array == nil then
162 return # 以前に文法エラー発生
163 end
164
165 signature.get_function_head_array.each{ |func_head|
166 if @includes.length > 0 then
167 if @includes.index func_head.get_name then
168 dbgPrint "MrubyBridgePlugin: #{func_head.get_name} INCLUDED\n"
169 @func_head_array << func_head
170 else
171 dbgPrint "MrubyBridgePlugin: #{func_head.get_name} NOT included\n"
172 end
173 elsif @excludes.length > 0 then
174 if @excludes.index( func_head.get_name ) == nil then
175 dbgPrint "MrubyBridgePlugin: #{func_head.get_name} NOT excluded\n"
176 @func_head_array << func_head
177 else
178 dbgPrint "MrubyBridgePlugin: #{func_head.get_name} EXCLUDED\n"
179 end
180 else
181 @func_head_array << func_head
182 end
183 }
184
185 if @func_head_array.length == 0 then
186 cdl_error( "MRB1012 '$1' no function remained by exclude", @signature.get_name )
187 end
188
189 check_name_and_return_type @func_head_array
190 check_parameter_type @func_head_array
191
192 end
193
194 #=== check function name & return type
195 def check_name_and_return_type func_head_array
196 b_init = false; b_init_cell = false
197 func_head_array.each{ |func_head|
198 if( func_head.get_name == :initialize )then
199 cdl_warning( "MRW2001 initialize: internally defined. change to initialize_cell in ruby" )
200 b_init = true
201 elsif( func_head.get_name == :initialize_cell )then
202 b_init_cell = true
203 end
204 rtype = func_head.get_return_type.get_original_type
205 case rtype
206 when BoolType, IntType, FloatType, VoidType
207 else
208 cdl_error( "MRB1001 cannot return type $1", rtype.get_type_str )
209 end
210 }
211 if( b_init && b_init_cell )then
212 cdl_warning( "MRB1002 initialize: internally defined. change to initialize_cell in ruby" )
213 end
214 end
215
216 #=== check paramter type
217 def check_parameter_type func_head_array
218 # check type of parameters
219 func_head_array.each{ |fh|
220 fh.get_paramlist.get_items.each{ |param_decl|
221 case param_decl.get_direction
222 when :SEND, :RECEIVE
223 cdl_error( "MRB1003 $1: $2 parameter cannot be used in mruby Bridge", param_decl.get_name, param_decl.get_direction.to_s.downcase )
224 end
225 type = param_decl.get_type
226 type_org = type.get_original_type
227 type_str = type.get_type_str + type.get_type_str_post
228
229 b_ng = false
230 case type_org
231 when IntType
232 case type_org.get_bit_size
233 when 8, 16, 32, 64
234 when -1, -2, -3, -4, -11
235 else
236 b_ng = true
237 end
238 when BoolType
239 when FloatType
240 when PtrType
241 ttype_org = type_org.get_type # ポインタの指している先の型
242 ttype = ttype_org.get_original_type # 上記の typedef されている場合、元の型
243 register_ptr_type ttype_org
244
245 if( type_org.get_string.to_s == "-1" ) then
246 case param_decl.get_direction
247 when :OUT, :INOUT
248 cdl_error( "MRB9999 string specifier without length cannot be used for out & inout parameter")
249 end
250 end
251
252 case ttype
253 when IntType
254 bit_size = ttype.get_bit_size
255 # if bit_size < 0 && bit_size != -1 then
256 # b_ng = true
257 # end
258 when FloatType
259 when BoolType
260 when StructType
261 if( type_org.get_size || type_org.get_string || type_org.get_count ) then
262 cdl_error( "MRB1004 $1: size_is, count_is, string cannot be specified for struct pointer", param_decl.get_name )
263 end
264 check_struct_member ttype_org
265 else
266 b_ng = true
267 end
268 when StructType
269 check_struct_member type_org
270 else # ArrayType, FuncType, EnumType, VoidType
271 b_ng = true
272 end
273 if b_ng then
274 cdl_error( "MRB1005 $1: type $2 cannot be used in mruby Bridge", param_decl.get_name, type_str )
275 end
276 }
277 }
278 end
279
280 #=== 構造体のメンバーの型のチェック
281 def check_struct_member struct_type
282 #p "tag name:#{struct_type.get_name}"
283 # sttype = Namespace.find_tag( struct_type.get_name )
284 sttype = struct_type.get_original_type
285 if sttype.get_name == nil then
286 cdl_error( "MRB10007 tagless-struct cannot be handled")
287 end
288 sttype.get_members_decl.get_items.each { |d|
289 t = d.get_type.get_original_type
290 case t
291 when IntType, FloatType, BoolType
292 else
293 cdl_error( "MRB1006 $1: type $2 not allowed for struct member", d.get_name, d.get_type.get_type_str + d.get_type.get_type_str_post )
294 end
295 }
296 st_name = :"t{}"
297 if @struct_list[ sttype.get_name ] == nil then
298 # print_msg " MrubyBridgePlugin: [struct] #{struct_type.get_type_str} => class TECS::Struct#{sttype.get_name}\n"
299 print " MrubyBridgePlugin: [struct] #{struct_type.get_type_str} => class TECS::Struct#{sttype.get_name}\n"
300 @struct_list[ sttype.get_name ] = sttype
301 end
302 end
303
304 def register_ptr_type ttype
305 t_org = ttype.get_original_type
306 tment = get_type_map_ent t_org
307 if tment == nil then
308 return
309 cdl_error( "MRB1008 unknown pointer type '$1'", ttype.get_type_str )
310 end
311 ptr_celltype_name = :"t#{tment[1]}Pointer"
312 if @@ptr_list[ ptr_celltype_name ] == nil then
313 # print_msg " MrubyBridgePlugin: [pointer] #{ttype.get_type_str}* => class TECS::#{tment[1]}Pointer\n"
314 print " MrubyBridgePlugin: [pointer] #{ttype.get_type_str}* => class TECS::#{tment[1]}Pointer\n"
315 @@ptr_list[ ptr_celltype_name ] = tment
316 end
317 if @ptr_list[ ptr_celltype_name ] == nil then
318 @ptr_list[ ptr_celltype_name ] = tment
319 end
320 end
321
322 def get_type_map_ent ttype
323 # structure type is registerd in check_struct_member
324 if ttype.kind_of? StructType
325 return
326 end
327 tstr = ttype.get_type_str.sub( /const /, "" ) # const は無視
328 tstr = tstr.sub( /volatile /, "" ) # volatile も無視
329 if @b_ignoreUnsigned then
330 tstr = tstr.sub( /unsigned /, "" ) # volatile も無視
331 tstr = tstr.sub( /uint/, "int" ) # volatile も無視
332 tstr = tstr.sub( /[cs]char/, "char" ) # volatile も無視
333 end
334 return @@TYPE_MAP[ tstr.to_sym ]
335 end
336
337 #=== CDL ファイルの生成
338 # typedef, signature, celltype, cell コードを生成
339 #file:: FILE 生成するファイル
340 def gen_cdl_file(file)
341
342 # ブリッジセルタイプの生成
343 if @@celltypes[ @celltype_name ] == nil then
344 @@celltypes[ @celltype_name ] = [ self ]
345 @@init_celltypes[ @init_celltype_name ] = true
346 print_msg <<EOT
347 MrubyBridgePlugin: [signature] #{@signature.get_namespace_path} => [celltype] nMruby::#{@celltype_name} => [class] TECS::#{@class_name}
348EOT
349
350 file.print <<EOT
351import( <mruby.cdl> );
352
353/**** Ruby => TECS Bridge Celltype (MBP500) ****/
354namespace nMruby{
355 // bridge celltype
356 [idx_is_id,active] // not actually active, to avoid warning W1002, W1007
357 celltype #{@celltype_name} {
358 call #{@signature.get_namespace_path.to_s} cTECS;
359 attr {
360 [omit]
361 char_t *VMname = "VM";
362 };
363 };
364 // bridge initializer celltype
365 celltype #{@init_celltype_name} {
366 entry sInitializeTECSBridge eInitialize;
367 };
368};
369EOT
370
371 # 構造体セルタイプの生成
372 @struct_list.each{ |name, sttype|
373 if @@struct_list[ name ] == nil then
374 file.print <<EOT
375namespace nMruby{
376 [singleton]
377 celltype #{name} {
378 entry sInitializeTECSBridge eInitialize;
379 };
380};
381EOT
382 @@struct_list[ name ] = sttype
383 end
384 }
385
386 else
387 cdl_warning( "MRBW001 MrubyBridgePlugin: signature '$1' duplicate. ignored current one", @signature.get_namespace_path )
388 @@celltypes[ @celltype_name ] << self
389 end
390 end
391
392 #=== gen_cdl_file で定義したセルタイプに 新しいセルが定義された
393 # cell のセルタイプの名前は @celltype_name
394 def new_cell cell
395 if cell.get_celltype.get_name != @celltype_name then
396 return
397 end
398
399 join = cell.get_join_list.get_item :VMname
400 if join then
401 vm_name = CDLString.remove_dquote(join.get_rhs.to_s).to_sym
402 else
403 vm_name = :"VM"
404 end
405
406 if @@VM_list[ vm_name ] == nil then
407 @@VM_list[ vm_name ] = true
408
409 initializer_celltype_cdl = "#{$gen}/#{cell.get_name}Initializer.cdl"
410 file = CFile.open( initializer_celltype_cdl, "w" )
411
412 # TECS 初期化セル(プロトタイプ宣言)
413 print_msg " MrubyBridgePlugin: join your VM's cInitialize to #{vm_name}_TECSInitializer.eInitialize\n"
414
415 file.print <<EOT
416
417 // prototype of TECSInitializer (MBP510)
418 cell nMruby::tTECSInitializer #{vm_name}_TECSInitializer;
419EOT
420 file.close
421
422 Generator.parse( initializer_celltype_cdl, self )
423 end
424
425 if @@VM_celltypes[ vm_name ] then
426 vma = @@VM_celltypes[ vm_name ]
427
428 if vma[ @celltype_name ] then
429 vma[ @celltype_name ] << cell
430 else
431 vma[ @celltype_name ] = [cell]
432 @@VM_celltypes[ vm_name ] = vma
433 end
434 else
435 vma = { }
436 vma[ @celltype_name ] = [cell]
437 @@VM_celltypes[ vm_name ] = vma
438 end
439
440 @struct_list.each{ |stname, sttype|
441 if @@VM_struct_list[ vm_name ] then
442 @@VM_struct_list[ vm_name ][ sttype.get_name ] = sttype
443 else
444 @@VM_struct_list[ vm_name ] = { sttype.get_name => sttype }
445 end
446 }
447 @ptr_list.each{ |ptr_celltype_name, tment|
448 if @@VM_ptr_list[ vm_name ] then
449 @@VM_ptr_list[ vm_name ][ ptr_celltype_name ] = tment
450 else
451 @@VM_ptr_list[ vm_name ] = { ptr_celltype_name => tment }
452 end
453 }
454
455 end
456
457 #=== プラグインが CDL の POST コードを生成
458 # tmp_plugin_post_code.cdl への出力
459 def self.gen_post_code file
460
461# file.print <<EOT
462# namespace nMruby {
463# EOT
464#
465# @@ptr_list.each{ |name,tment|
466# file.print <<EOT
467#
468# // MBP600
469# [singleton]
470# celltype #{name} {
471# entry sInitializeTECSBridge eInitialize;
472# };
473# EOT
474# }
475#
476# file.print <<EOT
477# };
478# EOT
479
480# gen_post_code で生成した celltype は gen_ep_func が呼び出されない #847
481# @@struct_list.each{ |name,sttype|
482# file.print <<EOT
483#
484# [singleton]
485# celltype #{name} {
486# entry sInitializeTECSBridge eInitialize;
487# };
488#EOT
489# }
490
491 file.print " // MBP601\n"
492 @@VM_celltypes.each{ |vm_name, instance_list|
493 instance_list.each { |celltype_name, array|
494 cell = array[0]
495 if cell.get_celltype then
496 ct_name = cell.get_celltype.get_name
497 file.print <<EOT
498 cell nMruby::#{ct_name}_Initializer #{vm_name}_#{ct_name}_Initializer{ };
499EOT
500 end
501 }
502 }
503
504 file.print " // MBP602\n"
505 @@ptr_list.each{ |name,tment|
506 file.print <<EOT
507 cell nMruby::#{name} C#{name} { };
508EOT
509 }
510
511 file.print " // MBP603\n"
512 @@struct_list.each{ |name,sttype|
513 file.print <<EOT
514 cell nMruby::#{name} C#{name} { };
515EOT
516 }
517
518 if @@VM_celltypes == nil
519 raise "are0"
520 end
521 @@VM_celltypes.each{ |vm_name, instance_list|
522 file.print " /* === VM #{vm_name} === (MBP610) */\n"
523 init_cell_name = "#{vm_name}_TECSInitializer"
524
525 file.print " cell nMruby::tTECSInitializer #{init_cell_name} {\n"
526
527 instance_list.each { |celltype_name, array|
528 array.each{ |cell|
529 ct_name = cell.get_celltype.get_name
530 file.print " cInitialize[] = #{vm_name}_#{ct_name}_Initializer.eInitialize;\n"
531 }
532 }
533 if @@VM_ptr_list[vm_name] then
534 @@VM_ptr_list[vm_name].each{ |name, tment|
535 file.print " cInitialize[] = C#{name}.eInitialize;\n"
536 }
537 end
538 if @@VM_struct_list[vm_name] then
539 @@VM_struct_list[vm_name].each{ |name, sttype|
540 file.print " cInitialize[] = C#{name}.eInitialize;\n"
541 }
542 end
543 file.print " };"
544 }
545
546 end
547
548 ####### 以下コード生成段階 ######
549
550 #=== 受け口関数の本体コードを生成(頭部と末尾は別途出力)
551 #ct_name:: Symbol (プラグインで生成された) セルタイプ名 .Symbol として送られてくる
552 def gen_ep_func_body( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
553 if @@celltypes[ ct_name ] then
554 gen_ep_func_body_bridge( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
555 elsif @@init_celltypes[ ct_name ] then
556 gen_ep_func_body_bridge_init( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
557 elsif @@ptr_list[ ct_name ] then
558 gen_ep_func_body_ptr( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
559 elsif @@struct_list[ ct_name ] then
560 gen_ep_func_body_struct( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
561 else
562 raise "Unknown #{ct_name}"
563 end
564 end
565
566 def gen_ep_func_body_bridge( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
567 raise "unexpected "
568 end
569
570 def gen_ep_func_body_bridge_init( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
571 file.print <<EOT
572 CELLCB *p_cellcb = GET_CELLCB( idx ); /* no error check */ /* MBP700 */
573 struct RClass *rc;
574
575 rc = mrb_define_class_under( mrb, TECS, \"#{@class_name}\", mrb->object_class );
576 mrb_define_method( mrb, rc, "initialize", MrubyBridge_#{@celltype_name}_initialize, MRB_ARGS_REQ(1) );
577 MRB_SET_INSTANCE_TT(rc, MRB_TT_DATA);
578EOT
579
580 @func_head_array.each{ |f|
581 if ! f.is_function? then
582 next
583 end
584 if f.get_name != :initialize then
585 func_name = f.get_name
586 else
587 func_name = :initialize_cell
588 end
589
590 ret_type = f.get_return_type
591 n_param = 0
592 f.get_paramlist.get_items.each{ |param|
593 case param.get_direction
594 when :IN, :INOUT, :OUT
595 n_param += 1
596 when :SEND, :RECEIVE
597 raise "send, receive"
598 end
599 }
600 if n_param > 0 then
601 p_str = "MRB_ARGS_REQ( #{n_param} )"
602 else
603 p_str = "MRB_ARGS_NONE()"
604 end
605 file.print <<EOT
606 mrb_define_method( mrb, rc, "#{func_name}", MrubyBridge_#{@celltype_name}_#{func_name}, #{p_str} );
607EOT
608 }
609 end
610
611 def gen_ep_func_body_ptr( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
612
613 t = @@ptr_list[ct_name]
614 type = t[1]
615 file.print <<EOT
616 struct RClass *a; /* MBP710 */
617
618 a = mrb_define_class_under(mrb, TECS, "#{type}Pointer", mrb->object_class);
619 MRB_SET_INSTANCE_TT(a, MRB_TT_DATA);
620
621 mrb_define_method(mrb, a, "initialize", #{type}Pointer_initialize, MRB_ARGS_REQ(1));
622 mrb_define_method(mrb, a, "[]", #{type}Pointer_aget, MRB_ARGS_REQ(1));
623 mrb_define_method(mrb, a, "value", #{type}Pointer_get_val, MRB_ARGS_NONE());
624 mrb_define_method(mrb, a, "[]=", #{type}Pointer_aset, MRB_ARGS_REQ(2));
625 mrb_define_method(mrb, a, "value=", #{type}Pointer_set_val, MRB_ARGS_REQ(1));
626 mrb_define_method(mrb, a, "size", #{type}Pointer_size, MRB_ARGS_NONE());
627 mrb_define_method(mrb, a, "length", #{type}Pointer_size, MRB_ARGS_NONE());
628EOT
629
630 if t[2] == :Char then
631 file.print <<EOT
632 mrb_define_method(mrb, a, "to_s", CharPointer_to_s, MRB_ARGS_NONE());
633 mrb_define_method(mrb, a, "from_s", CharPointer_from_s, MRB_ARGS_REQ(1));
634EOT
635 end
636 end
637
638 def gen_ep_func_body_struct( file, b_singleton, ct_name, global_ct_name, sig_name, ep_name, func_name, func_global_name, func_type, params )
639 tag = ct_name
640 structType = @@struct_list[ tag ]
641 file.print <<EOT
642 struct RClass *a; /* MBP720 */
643
644 a = mrb_define_class_under(mrb, TECS, "Struct#{tag}", mrb->object_class);
645 MRB_SET_INSTANCE_TT(a, MRB_TT_DATA);
646
647 mrb_define_method(mrb, a, "initialize", Struct_#{tag}_initialize, MRB_ARGS_NONE());
648EOT
649
650 structType.get_members_decl.get_items.each{ |d|
651 file.print " STRUCT_INIT_MEMBER( #{tag}, #{d.get_name} )\n"
652 }
653 end
654
655 #=== 受け口関数の preamble (C言語)を生成する
656 # 必要なら preamble 部に出力する
657 #file:: FILE 出力先ファイル
658 #b_singleton:: bool true if singleton
659 #ct_name:: Symbol
660 #global_ct_name:: string
661 def gen_preamble( file, b_singleton, ct_name, global_ct_name )
662 if @@celltypes[ ct_name ] then
663 gen_preamble_mruby( file, b_singleton, ct_name, global_ct_name )
664 gen_preamble_instance( file, b_singleton, ct_name, global_ct_name )
665 gen_preamble_instance_initialize( file, b_singleton, ct_name, global_ct_name )
666 gen_preamble_bridge_func( file, b_singleton, ct_name, global_ct_name )
667 elsif @@init_celltypes[ ct_name ] then
668 gen_preamble_mruby( file, b_singleton, ct_name, global_ct_name )
669 gen_preamble_instance_proto( file, b_singleton, ct_name, global_ct_name )
670 elsif @@ptr_list[ ct_name ] then
671 gen_preamble_ptr( file, b_singleton, ct_name, global_ct_name )
672 elsif @@struct_list[ ct_name ] then
673 gen_preamble_struct( file, b_singleton, ct_name, global_ct_name )
674 else
675 raise "Unknown #{ct_name}"
676 end
677 end
678
679 def gen_preamble_mruby( file, b_singleton, ct_name, global_ct_name )
680 file.print <<EOT
681/* MBP: MrubyBridgePlugin: MBP000 */
682#include "mruby.h"
683#include "mruby/class.h"
684#include "mruby/data.h"
685#include "mruby/string.h"
686#include "TECSPointer.h"
687#include "TECSStruct.h"
688
689#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
690#define DLLEXPORT __declspec(dllexport)
691#else
692#define DLLEXPORT
693#endif
694
695#ifndef NULL
696#define NULL 0
697#endif
698EOT
699 end
700
701 def gen_preamble_instance( file, b_singleton, ct_name, global_ct_name )
702 file.print <<EOT
703
704/* RData MBP001 */
705static void
706#{@celltype_name}_free( mrb_state *mrb, void *p )
707{
708 if( p )
709 (void)mrb_free( mrb, p );
710}
711
712/* RData MBP002 */
713struct mrb_data_type data_type_#{@celltype_name} =
714{
715 "#{@celltype_name}",
716 #{@celltype_name}_free
717};
718
719/* RData MBP003 */
720struct tecs_#{@celltype_name} {
721 CELLCB *cbp;
722};
723
724/* name_to_cbp MBP010 */
725const struct name_to_cbp_#{@celltype_name} {
726 char *name; /* Cell Name */
727 CELLCB *cbp;
728} Name_to_cbp_#{@celltype_name}[] = {
729EOT
730
731 # mikan namespace
732 nsp = NamespacePath.new( :nMruby, true )
733 nsp.append! ct_name
734 ct = Namespace.find nsp
735
736 ct.get_cell_list.each{ |cell|
737 if cell.is_generate? then
738 name_array = ct.get_name_array( cell )
739 file.print "\t{ \"#{cell.get_name}\", #{name_array[8]} },\n"
740 end
741 }
742
743 file.print <<EOT
744\t{ 0, 0 },
745};
746
747EOT
748
749 end
750
751 def gen_preamble_ptr( file, b_singleton, ct_name, global_ct_name )
752 tment = @@ptr_list[ ct_name ]
753 file.print <<EOT
754
755GET_SET_#{tment[3]}( #{tment[1]}, #{tment[0]} )
756POINTER_CLASS( #{tment[1]}, #{tment[0]} )
757EOT
758 end
759
760 def gen_preamble_struct( file, b_singleton, ct_name, global_ct_name )
761 tag = ct_name
762 structType = @@struct_list[ tag ]
763 file.print <<EOT
764/* struct #{tag} */
765STRUCT_CLASS( #{tag} )
766EOT
767
768 structType.get_members_decl.get_items.each{ |d|
769 type = d.get_type.get_original_type
770 case type
771 when IntType, CIntType
772 bit_size = type.get_bit_size
773 case bit_size
774 when -11, -1
775 tType = "Char"
776 ttype = "char"
777 when -2
778 tType = "Short"
779 ttype = "short"
780 when -3
781 tType = "Int"
782 ttype = "int"
783 when -4
784 tType = "Long"
785 ttype = "long"
786 when -5
787 tType = "IntPtr"
788 ttype = "intptr"
789 when 8, 16, 32, 64
790 tType = "Int#{bit_size}"
791 ttype = "int#{bit_size}"
792 else
793 raise "cannot handle bit_size #{bit_size}"
794 end
795 file.print "MEMBER_GET_SET_INT( #{tag}, #{d.get_name}, #{tType}, #{ttype} )\n"
796 when FloatType, CFloatType
797 file.print "MEMBER_GET_SET_FLOAT( #{tag}, #{d.get_name} )\n"
798 else
799 raise "cannot handle type"
800 end
801 }
802
803 end
804
805 def gen_preamble_instance_proto( file, b_singleton, ct_name, global_ct_name )
806 file.print <<EOT
807// Prototype MBP400
808mrb_value MrubyBridge_#{@celltype_name}_initialize( mrb_state *mrb, mrb_value self);
809EOT
810
811 @func_head_array.each{ |f|
812 if ! f.is_function? then
813 next
814 end
815 if f.get_name != :initialize then
816 func_name = f.get_name
817 else
818 func_name = :initialize_cell
819 end
820
821 ret_type = f.get_return_type
822 ret_type0 = f.get_return_type.get_original_type
823 b_void = ret_type0.is_void?
824 plist = f.get_paramlist.get_items
825
826 file.print <<EOT
827mrb_value MrubyBridge_#{@celltype_name}_#{func_name}( mrb_state *mrb, mrb_value self );
828EOT
829 }
830 end
831
832 def gen_preamble_instance_initialize( file, b_singleton, ct_name, global_ct_name )
833 file.print <<EOT
834
835/* MBP100 */
836mrb_value
837MrubyBridge_#{@celltype_name}_initialize( mrb_state *mrb, mrb_value self)
838{
839 mrb_value name;
840 struct tecs_#{@celltype_name} *tecs_cb;
841 const struct name_to_cbp_#{@celltype_name} *ntc;
842
843 /* set DATA_TYPE earlier to avoid SEGV */
844 DATA_TYPE( self ) = &data_type_#{@celltype_name};
845
846 mrb_get_args(mrb, "o", &name );
847 if( mrb_type( name ) != MRB_TT_STRING ){
848 mrb_raise(mrb, E_NAME_ERROR, "cell name not string");
849 }
850 for( ntc = &Name_to_cbp_#{@celltype_name}[0]; ntc->name != NULL; ntc++ ){
851 if( strcmp( ntc->name, RSTRING_PTR( name ) ) == 0 )
852 break;
853 }
854 if( ntc->name == 0 ){
855 mrb_raise(mrb, E_ARGUMENT_ERROR, "cell not found");
856 }
857 tecs_cb = (struct tecs_#{@celltype_name} *)mrb_malloc(mrb, sizeof(struct tecs_#{@celltype_name}) );
858 tecs_cb->cbp = ntc->cbp;
859 DATA_PTR( self ) = (void *)tecs_cb;
860
861 return self;
862}
863EOT
864 end
865
866 def gen_preamble_bridge_func( file, b_singleton, ct_name, global_ct_name )
867
868 @func_head_array.each{ |f|
869 if ! f.is_function? then
870 next
871 end
872 if f.get_name != :initialize then
873 func_name = f.get_name
874 else
875 func_name = :initialize_cell
876 end
877
878 ret_type = f.get_return_type
879 ret_type0 = f.get_return_type.get_original_type
880 b_void = ret_type0.is_void?
881 plist = f.get_paramlist.get_items
882
883 file.print <<EOT
884
885/* bridge function (MBP101) */
886mrb_value
887MrubyBridge_#{ct_name}_#{func_name}( mrb_state *mrb, mrb_value self )
888{
889 /* cellcbp (MBP105) */
890 CELLCB *p_cellcb = ((struct tecs_#{@celltype_name} *)DATA_PTR(self))->cbp;
891EOT
892
893 file.print " /* variables for return & parameter (MBP110) */\n"
894 if ! b_void then
895 file.print " ", ret_type.get_type_str, "\tret_val", ret_type.get_type_str_post, ";\n"
896 end
897 arg_str = ""
898 n_param = 0
899 n_scalar = 0
900 n_ptr = 0
901 n_struct = 0
902 plist.each{ |param|
903 case param.get_direction
904 when :IN, :INOUT, :OUT
905 type = param.get_type.get_original_type
906 case type
907 when IntType
908 file.print " mrb_int mrb_", param.get_name, ";\n"
909 file.print " #{param.get_type.get_type_str} #{param.get_name}#{param.get_type.get_type_str_post};\n"
910 arg_str += "i"
911 n_param += 1
912 n_scalar += 1
913 when FloatType
914 file.print " mrb_float mrb_", param.get_name, ";\n"
915 file.print " #{param.get_type.get_type_str} #{param.get_name}#{param.get_type.get_type_str_post};\n"
916 arg_str += "f"
917 n_param += 1
918 n_scalar += 1
919 when BoolType
920 file.print " mrb_value mrb_", param.get_name, ";\n"
921 file.print " #{param.get_type.get_type_str} #{param.get_name}#{param.get_type.get_type_str_post};\n"
922 arg_str += "o"
923 n_param += 1
924 n_scalar += 1
925 when PtrType
926 file.print " mrb_value mrb_", param.get_name, ";\n"
927 file.print " #{param.get_type.get_type_str} #{param.get_name}#{param.get_type.get_type_str_post};\n"
928 arg_str += "o"
929 n_param += 1
930 n_ptr += 1
931 when StructType
932 file.print " mrb_value mrb_", param.get_name, ";\n"
933 file.print " #{param.get_type.get_type_str} *#{param.get_name}#{param.get_type.get_type_str_post};\n"
934 arg_str += "o"
935 n_param += 1
936 n_struct += 1
937 else
938 raise "Unkown type"
939 end
940 end
941 }
942
943 if n_param > 0 then
944 file.print " /* retrieve arguments (MBP111) */\n"
945 file.print " mrb_get_args(mrb, \"#{arg_str}\""
946 plist.each{ |param|
947 case param.get_direction
948 when :IN, :INOUT, :OUT
949 type = param.get_type.get_original_type
950 case type
951 when IntType
952 file.print ", &mrb_", param.get_name
953 when FloatType
954 file.print ", &mrb_", param.get_name
955 when BoolType
956 file.print ", &mrb_", param.get_name
957 when PtrType
958 file.print ", &mrb_", param.get_name
959 when StructType
960 file.print ", &mrb_", param.get_name
961 else
962 raise "Unkown type"
963 end
964 end
965 }
966 file.print " );\n"
967
968 if n_scalar > 0 || n_struct > 0 then
969 file.print " /* convert mrb to C (MBP112) */\n"
970 end
971 plist.each{ |param|
972 case param.get_direction
973 when :IN, :INOUT, :OUT
974 type = param.get_type.get_original_type
975 case type
976 when IntType
977 ttype = type.get_original_type
978 tment = get_type_map_ent ttype
979 file.print " VALCHECK_#{tment[1]}( mrb, mrb_#{param.get_name} );\n"
980 file.print " #{param.get_name} = (#{param.get_type.get_type_str})mrb_#{param.get_name};\n"
981 when FloatType
982 file.print " #{param.get_name} = (#{param.get_type.get_type_str})mrb_#{param.get_name};\n"
983 when BoolType
984 file.print " #{param.get_name} = mrb_test( mrb_#{param.get_name} );\n"
985 when PtrType
986 ttype = type.get_type.get_original_type
987 case ttype
988 when StructType
989 file.print " CHECK_STRUCT( #{ttype.get_name}, mrb_#{param.get_name} );\n"
990 file.print " #{param.get_name} = (struct #{ttype.get_name}*)DATA_PTR(mrb_#{param.get_name});\n"
991 when IntType
992 when FloatType
993 when BoolType
994 else
995 raise "cannot handle type"
996 end
997 when StructType
998 file.print " CHECK_STRUCT( #{type.get_name}, mrb_#{param.get_name} );\n"
999 file.print " #{param.get_name} = (struct #{type.get_name}*)DATA_PTR(mrb_#{param.get_name});\n"
1000 else
1001 raise( "canot treat class" )
1002 end
1003 end
1004 }
1005
1006 if n_ptr > 0 then
1007 file.print " /* convert mrb to C for pointer types (MBP113) */\n"
1008 end
1009 plist.each{ |param|
1010 case param.get_direction
1011 when :IN, :INOUT, :OUT
1012 type = param.get_type.get_original_type
1013 case type
1014 when IntType
1015 when FloatType
1016 when BoolType
1017 when PtrType
1018 case type.get_type.get_original_type
1019 when StructType
1020 when IntType
1021 ptrMrb2C file, type, param
1022 when FloatType
1023 ptrMrb2C file, type, param
1024 when BoolType
1025 ptrMrb2C file, type, param
1026 else
1027 raise "cannot handle type"
1028 end
1029 when StructType
1030 else
1031 raise( "canot treat class" )
1032 end
1033 end
1034 }
1035
1036 end
1037
1038 file.print " /* calling target (MBP120) */\n"
1039 if ! b_void then
1040 file.print " ret_val = "
1041 else
1042 file.print " "
1043 end
1044 delim = ""
1045 file.print "cTECS_", f.get_name, "( "
1046 plist.each{ |param|
1047 if param.get_type.get_original_type.kind_of? StructType then
1048 aster = "*"
1049 else
1050 aster = ""
1051 end
1052 file.print delim, aster, param.get_name
1053 delim = ", "
1054 }
1055 file.print " );\n"
1056
1057 file.print " /* return (MBP130) */\n"
1058 case ret_type0
1059 when BoolType
1060 file.print " return ret_val ? mrb_true_value() : mrb_false_value();\n"
1061 when IntType
1062 file.print " return mrb_fixnum_value( ret_val );\n"
1063 when FloatType
1064 file.print " return mrb_float_value( mrb, ret_val );\n"
1065 when VoidType
1066 file.print " return mrb_nil_value();\n"
1067 else
1068 raise "unknown type"
1069 end
1070
1071 file.print "}\n"
1072 }
1073 end
1074
1075 def ptrMrb2C file, type, param
1076 ttype = type.get_type.get_original_type
1077 tment = get_type_map_ent ttype
1078 tstr = tment[1]
1079=begin
1080 case ttype
1081 when IntType
1082 bit_size = ttype.get_bit_size
1083 case bit_size
1084 when -1, -11
1085 tstr = "Char"
1086 when 8, 16, 32, 64
1087 tstr = "Int#{bit_size}"
1088 when -2
1089 tstr = "Short"
1090 when -3
1091 tstr = "Int"
1092 when -4
1093 tstr = "Long"
1094 when -5
1095 tstr = "IntPtr"
1096 else
1097 raise "not handle type"
1098 end
1099 when FloatType
1100 if ttype.get_bit_size == 32 then
1101 tstr = "Float32"
1102 else
1103 tstr = "Double64"
1104 end
1105 when BoolType
1106 tstr = "Bool"
1107 when StructType
1108 raise "not handle type 2 #{ttype}"
1109 else
1110 raise "not handle type 2 #{ttype}"
1111 end
1112=end
1113 if( param.get_size ) then
1114 sz_str = param.get_size.to_s
1115 elsif param.get_string then # mikan とりあえず size_is と string の同時指定 (二重ポインタ) はなし
1116 sz_str = param.get_string.to_s
1117 else
1118 sz_str = "1"
1119 end
1120 # unsigned 型の場合には cast が必要
1121 if ttype.get_original_type.get_type_str != param.get_type.get_type.get_type_str then
1122 cast_str = "(#{param.get_type.get_type_str})"
1123 else
1124 cast_str = ""
1125 end
1126
1127 modify = ""
1128 case param.get_direction
1129 when :OUT, :INOUT
1130 case tstr
1131 when "Char", "SChar", "UChar"
1132 modify = "Mod"
1133 end
1134 end
1135 if param.is_nullable? then
1136 nullable = "Nullable"
1137 else
1138 nullable = ""
1139 end
1140
1141 # file.print " CHECK_POINTER( #{tstr}, mrb_#{param.get_name}, #{sz_str} );\n"
1142 # file.print " #{param.get_name} = #{cast_str}((struct #{tstr}PointerBody*)(DATA_PTR(mrb_#{param.get_name})))->buf;\n"
1143 file.print " #{param.get_name} = CheckAndGet#{tstr}Pointer#{modify}#{nullable}( mrb, mrb_#{param.get_name}, #{sz_str} );\n"
1144 end
1145
1146 def get_celltype_name
1147 @celltype_name
1148 end
1149
1150 #=== プラグイン引数 ignoreUnsigned
1151 def set_ignoreUnsigned rhs
1152 if rhs == "true" || rhs == nil then
1153 @b_ignoreUnsigned = true
1154 end
1155 end
1156 #=== プラグイン引数 include
1157 def set_include rhs
1158 funcs = rhs.split ','
1159 funcs.each{ |rhs_func|
1160 found = false
1161 rhs_func.gsub!( /\s/, "" )
1162 @signature.get_function_head_array.each{ |a|
1163 if rhs_func.to_sym == a.get_name then
1164 found = true
1165 end
1166 }
1167 if found == false then
1168 cdl_error( "MRB1009 include function '$1' not found in signagture '$2'", rhs, @signature.get_name )
1169 else
1170 @includes << rhs_func.to_sym
1171 end
1172 }
1173 end
1174 #=== プラグイン引数 exclude
1175 def set_exclude rhs
1176 funcs = rhs.split ','
1177 funcs.each{ |rhs_func|
1178 found = false
1179 rhs_func.gsub!( /\s/, "" )
1180 @signature.get_function_head_array.each{ |a|
1181 if rhs_func.to_sym == a.get_name then
1182 found = true
1183 end
1184 }
1185 if found == false then
1186 cdl_error( "MRB1010 exclude function '$1' not found in signagture '$2", rhs, @signature.get_name )
1187 else
1188 @excludes << rhs_func.to_sym
1189 end
1190 }
1191 end
1192end
1193
Note: See TracBrowser for help on using the repository browser.