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

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

mruby版ECNLプロトタイピング・ツールを追加

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