ridl 2.2.5 → 2.5.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,28 +17,52 @@ module IDL
17
17
 
18
18
  class GenFile
19
19
 
20
- @@stack = []
21
- @@cur_trans = nil
20
+ self.singleton_class.class_eval do
21
+ private
22
22
 
23
+ def _stack
24
+ @stack ||= []
25
+ end
26
+
27
+ def _start_transaction
28
+ _stack << (@transaction = [])
29
+ end
30
+
31
+ def _close_transaction
32
+ _stack.pop
33
+ @transaction = _stack.last
34
+ end
35
+
36
+ def _transaction
37
+ @transaction
38
+ end
39
+
40
+ def _commit
41
+ _transaction.reject! { |fgen| fgen.save; true }
42
+ end
43
+
44
+ def _rollback
45
+ _transaction.reject! { |fgen| fgen.remove; true } if _transaction
46
+ end
47
+
48
+ def _push(fgen)
49
+ _transaction << fgen if _transaction
50
+ end
51
+
52
+ end
23
53
  def self.transaction(&block)
24
- @@cur_trans = []
25
- @@stack << @@cur_trans
54
+ _start_transaction
26
55
  begin
27
56
  block.call if block_given?
28
- @@cur_trans.each {|fgen| fgen.save }
29
- @@cur_trans.clear
57
+ _commit
30
58
  ensure
31
- self.rollback # after successful transaction should be nothing left
32
- @@stack.pop
33
- @@cur_trans = @@stack.last
59
+ _rollback # after successful transaction should be nothing left
60
+ _close_transaction
34
61
  end
35
62
  end
36
63
 
37
64
  def self.rollback
38
- if @@cur_trans
39
- @@cur_trans.each {|fgen| fgen.remove }
40
- @@cur_trans.clear
41
- end
65
+ _rollback
42
66
  end
43
67
 
44
68
  class Content
@@ -82,8 +106,9 @@ module IDL
82
106
  :regen_marker_prefix => '//',
83
107
  :regen_marker_postfix => nil,
84
108
  :regen_marker => REGEN_MARKER_DEFAULT,
85
- :regen_keep_header => false,
86
- :output_file => nil
109
+ :regen_keep_header => true,
110
+ :output_file => nil,
111
+ :create_missing_dir => false
87
112
  }.merge(opts)
88
113
  if @options[:regenerate] && File.exists?(@fullpath)
89
114
  parse_regeneration_content
@@ -91,7 +116,7 @@ module IDL
91
116
  @content = Content.new
92
117
  end
93
118
  @fout = @options[:output_file] || Tempfile.new(@name)
94
- @@cur_trans << self
119
+ self.class.__send__(:_push, self)
95
120
  end
96
121
 
97
122
  def <<(txt)
@@ -111,11 +136,14 @@ module IDL
111
136
  "#{@options[:regen_marker_prefix]}#{@options[:regen_marker]} - HEADER_END : #{sectionid}#{@options[:regen_marker_postfix]}"
112
137
  end
113
138
 
114
- def write_regen_section(sectionid, default_content, indent = '', options = {})
139
+ def write_regen_section(sectionid, options = {})
140
+ indent = options[:indent] || ''
115
141
  self << indent << regen_start_marker(sectionid) << "\n" unless options[:header]
116
142
  if content.has_section?(sectionid)
117
143
  self << content[sectionid].join unless content[sectionid].empty?
118
- else
144
+ elsif block_given?
145
+ yield # block should yield default content
146
+ elsif default_content = options[:default_content]
119
147
  default_content = (Array === default_content) ? default_content : default_content.to_s.split("\n")
120
148
  self << (default_content.collect {|l| (s = indent.dup) << l << "\n"; s }.join) unless default_content.empty?
121
149
  end
@@ -141,22 +169,29 @@ module IDL
141
169
  # replace original
142
170
  begin
143
171
  # rename newly generated file
144
- FileUtils::mv(fgen.path, @fullpath)
172
+ FileUtils.mv(fgen.path, @fullpath)
145
173
  # preserve file mode
146
- FileUtils::chmod(File.lstat(ftmp_name).mode, @fullpath)
174
+ FileUtils.chmod(File.lstat(ftmp_name).mode, @fullpath)
147
175
  rescue
148
176
  IDL.log(0, %Q{ERROR: FAILED updating #{@path}: #{$!}})
149
177
  # restore backup
150
- FileUtils::mv(ftmp_name, @fullpath)
178
+ FileUtils.mv(ftmp_name, @fullpath)
151
179
  raise
152
180
  end
153
181
  # remove backup
154
182
  File.unlink(ftmp_name)
155
183
  else
184
+ unless File.directory?(File.dirname(@fullpath))
185
+ unless @options[:create_missing_dir]
186
+ IDL.log(0, %Q{ERROR: Cannot access output folder #{File.dirname(@fullpath)}})
187
+ exit(1)
188
+ end
189
+ FileUtils.mkdir_p(File.dirname(@fullpath))
190
+ end
156
191
  # just rename newly generated file
157
- FileUtils::mv(fgen.path, @fullpath)
192
+ FileUtils.mv(fgen.path, @fullpath)
158
193
  # set default mode for new files
159
- FileUtils::chmod(0666 - File.umask, @fullpath)
194
+ FileUtils.chmod(0666 - File.umask, @fullpath)
160
195
  end
161
196
  end
162
197
  end
@@ -115,6 +115,10 @@ module IDL::AST
115
115
  @annotations = Annotations.new
116
116
  end
117
117
 
118
+ def unescaped_name
119
+ @name.unescaped_name
120
+ end
121
+
118
122
  def parsed_name_scope
119
123
  (@enclosure ? @enclosure.parsed_name_scope : '') + '::' + @name
120
124
  end
@@ -128,7 +132,7 @@ module IDL::AST
128
132
  end
129
133
 
130
134
  def scoped_lm_name
131
- @scoped_lm_name ||= @scopes.collect{|s| s.lm_name_for_scope }.join("::").freeze
135
+ @scoped_lm_name ||= @scopes.collect{|s| s.lm_name_for_scope }.join('::').freeze
132
136
  end
133
137
 
134
138
  def marshal_dump
@@ -314,11 +318,15 @@ module IDL::AST
314
318
  end
315
319
 
316
320
  def walk_members(&block)
317
- @children.each { |c| yield(c) }
321
+ @children.each(&block)
318
322
  end
319
323
 
320
324
  def match_members(&block)
321
- !(@children.find { |c| yield(c) }).nil?
325
+ !(@children.find(&block)).nil?
326
+ end
327
+
328
+ def select_members(&block)
329
+ @children.select(&block)
322
330
  end
323
331
 
324
332
  def replace_prefix(pfx)
@@ -403,12 +411,14 @@ module IDL::AST
403
411
  IDL::AST::Union, IDL::AST::Enum, IDL::AST::Enumerator, IDL::AST::Typedef, IDL::AST::Include,
404
412
  IDL::AST::Home, IDL::AST::Porttype, IDL::AST::Component, IDL::AST::Connector
405
413
  ]
406
- attr_reader :anchor, :next
414
+ attr_reader :anchor, :next, :template, :template_params
407
415
  def initialize(_name, _enclosure, params)
408
416
  super(_name, _enclosure)
409
417
  @anchor = params[:anchor]
410
418
  @prefix = params[:prefix] || @prefix
411
419
  @not_in_repo_id = params[:not_in_repo_id]
420
+ @template = params[:template]
421
+ @template_params = (params[:template_params] || []).dup
412
422
  @next = nil
413
423
  end
414
424
 
@@ -416,6 +426,23 @@ module IDL::AST
416
426
  !@anchor.nil?
417
427
  end
418
428
 
429
+ def is_templated?
430
+ @template ? true : false
431
+ end
432
+
433
+ def template_param(param)
434
+ return nil unless @template
435
+ param = param.to_s if ::Symbol === param
436
+ if ::String === param
437
+ @template.params.each_with_index do |tp, ix|
438
+ return @template_params[ix] if tp.name == param
439
+ end
440
+ nil
441
+ else
442
+ @template_params[param] rescue nil
443
+ end
444
+ end
445
+
419
446
  def annotations
420
447
  (has_anchor? ? self.anchor : self).get_annotations
421
448
  end
@@ -452,9 +479,9 @@ module IDL::AST
452
479
  when IDL::AST::Module
453
480
  # Module reopening
454
481
  _anchor = node.has_anchor? ? node.anchor : node
455
- _anchor.annotations.concat(params[:annotations])
482
+ _anchor.annotations.concat(params.delete(:annotations))
456
483
  _last = _anchor.find_last
457
- _params = { :anchor => _anchor, :prefix => node.prefix }
484
+ _params = params.merge({ :anchor => _anchor, :prefix => node.prefix })
458
485
  _next = IDL::AST::Module.new(node.name, self, _params)
459
486
  _last.set_next(_next)
460
487
  @children << _next
@@ -685,12 +712,16 @@ module IDL::AST
685
712
  true
686
713
  end
687
714
 
688
- def instantiate(_module_instance, _concrete_params, _context = {})
715
+ def params
716
+ @template_params
717
+ end
718
+
719
+ def instantiate(_module_instance, _context = {})
689
720
  # process concrete parameters
690
721
  @template_params.each_with_index do |_tp, _ix|
691
722
  raise RuntimeError,
692
- "missing template parameter for #{typename} #{scoped_lm_name}: #{_tp.name}" unless _ix < _concrete_params.size
693
- _cp = _concrete_params[_ix]
723
+ "missing template parameter for #{typename} #{scoped_lm_name}: #{_tp.name}" unless _ix < _module_instance.template_params.size
724
+ _cp = _module_instance.template_params[_ix]
694
725
  if _cp.is_a?(IDL::Type)
695
726
  raise RuntimeError, "anonymous type definitions are not allowed!" if _cp.is_anonymous?
696
727
  # parameter should be a matching IDL::Type
@@ -772,13 +803,13 @@ module IDL::AST
772
803
  end
773
804
 
774
805
  def instantiate(_context, _enclosure)
775
- mod_inst = IDL::AST::Module.new(self.name, _enclosure, {})
776
806
  inst_params = @params.collect do |tp|
777
807
  # concrete objects are either Expression or Node; latter needs to be repacked as IDL::Type::ScopedName
778
808
  # as that is what the TemplateModule#instantiate expects
779
809
  tp.concrete.is_a?(IDL::Expression) ? tp.concrete : IDL::Type::ScopedName.new(tp.concrete)
780
810
  end
781
- @template.instantiate(mod_inst, inst_params, _context)
811
+ mod_inst = IDL::AST::Module.new(self.name, _enclosure, { :template => @template, :template_params => inst_params })
812
+ @template.instantiate(mod_inst, _context)
782
813
  mod_inst
783
814
  end
784
815
 
@@ -788,10 +819,11 @@ module IDL::AST
788
819
  end # TemplateModuleReference
789
820
 
790
821
  class Include < Module
791
- attr_reader :filename
822
+ attr_reader :filename, :fullpath
792
823
  def initialize(_name, _enclosure, params)
793
824
  super(_name, _enclosure, params)
794
825
  @filename = params[:filename]
826
+ @fullpath = params[:fullpath]
795
827
  @defined = params[:defined] || false
796
828
  @preprocessed = params[:preprocessed] || false
797
829
  #overrule
@@ -341,14 +341,14 @@ module IDL
341
341
  @options.delete(switch)
342
342
  end
343
343
 
344
- def to_option_parser(optp, idl_options)
344
+ def to_option_parser(optp, option_holder)
345
345
  @options.each do |sw, op|
346
346
  (arg_list = [sw]) << op.type
347
347
  arg_list.concat(op.description(optp.summary_indent))
348
348
  optp.on(*arg_list) do |v|
349
- op.run(v, idl_options)
349
+ op.run(v, option_holder.options)
350
350
  end
351
- optp.separator "" if op.separator
351
+ optp.separator '' if op.separator
352
352
  end
353
353
  end
354
354
 
@@ -499,7 +499,7 @@ def parse(src)
499
499
  rescue IDL::ParseError
500
500
  raise
501
501
  rescue
502
- STDERR.puts "#{$!}\n#{$!.backtrace.join("\n")}" if $VERBOSE
502
+ STDERR.puts "#{$!}\n#{$!.backtrace.join("\n")}" if IDL.verbose_level>0
503
503
  raise IDL::ParseError.new($!.message, @scanner.positions)
504
504
  end
505
505
  @d.post_parse
@@ -529,8 +529,8 @@ def is_included?(s)
529
529
  @d.is_included?(s)
530
530
  end
531
531
 
532
- def enter_include(s)
533
- @d.enter_include(s)
532
+ def enter_include(s, fp)
533
+ @d.enter_include(s, fp)
534
534
  end
535
535
 
536
536
  def leave_include()
@@ -541,8 +541,8 @@ def declare_include(s)
541
541
  @d.declare_include(s)
542
542
  end
543
543
 
544
- def define_annotation(annid, annbody)
545
- @d.define_annotation(annid, annbody)
544
+ def define_annotation(*args)
545
+ @d.define_annotation(*args)
546
546
  end
547
547
 
548
548
  def next_token
@@ -873,7 +873,7 @@ def parse(src)
873
873
  rescue IDL::ParseError
874
874
  raise
875
875
  rescue
876
- STDERR.puts "#{$!}\n#{$!.backtrace.join("\n")}" if $VERBOSE
876
+ STDERR.puts "#{$!}\n#{$!.backtrace.join("\n")}" if IDL.verbose_level>0
877
877
  raise IDL::ParseError.new($!.message, @scanner.positions)
878
878
  end
879
879
  @d.post_parse
@@ -903,8 +903,8 @@ def is_included?(s)
903
903
  @d.is_included?(s)
904
904
  end
905
905
 
906
- def enter_include(s)
907
- @d.enter_include(s)
906
+ def enter_include(s, fp)
907
+ @d.enter_include(s, fp)
908
908
  end
909
909
 
910
910
  def leave_include()
@@ -915,8 +915,8 @@ def declare_include(s)
915
915
  @d.declare_include(s)
916
916
  end
917
917
 
918
- def define_annotation(annid, annbody)
919
- @d.define_annotation(annid, annbody)
918
+ def define_annotation(*args)
919
+ @d.define_annotation(*args)
920
920
  end
921
921
 
922
922
  def next_token
@@ -17,219 +17,195 @@ require 'ridl/backend'
17
17
 
18
18
  # -----------------------------------------------------------------------
19
19
 
20
- $VERBOSE = $VERBOSE || ENV['RIDL_VERBOSE']
21
-
22
20
  module IDL
23
21
 
22
+ # TODO : LEGACY solution for R2CORBA; to be removed when R2CORBA has been updated
23
+ # See also IDL#init
24
24
  @@embedded = false unless class_variable_defined?(:@@embedded)
25
25
  @@be_name = nil unless class_variable_defined?(:@@be_name)
26
- @@preprocessing = false
27
- @@no_pidl = false
28
- @@idlstack = []
29
- @@backend = nil
30
- @@verbose_level = 0
31
26
 
32
27
  OPTIONS = {
33
28
  :outputdir => nil,
34
29
  :includepaths => [],
35
- :verbose => 0,
30
+ :xincludepaths => [],
31
+ :verbose => (ENV['RIDL_VERBOSE'] || 0).to_i,
36
32
  :debug => false,
37
33
  :namespace => nil,
38
34
  :search_incpath => false,
39
35
  :backend => nil,
40
36
  :macros => {
41
- :__RIDL__ => "#{RIDL_VERSION}",
42
- :__RIDLBE__ => nil,
43
- :__RIDLBE_VER__ => nil
37
+ :__RIDL__ => "#{RIDL_VERSION}",
38
+ :__RIDLBE__ => nil,
39
+ :__RIDLBE_VER__ => nil
44
40
  }
45
41
  }
46
42
 
47
- def IDL.preprocessing?
48
- @@preprocessing
49
- end
50
-
51
- def IDL.no_pidl?
52
- @@no_pidl
53
- end
43
+ class Engine
44
+ def initialize(backend, options)
45
+ @backend = backend ? Backend.load(backend) : Backend.null_be
46
+ @initopts = options.merge({
47
+ backend: @backend.name,
48
+ macros: options[:macros].merge({
49
+ __RIDLBE__: @backend.name.to_s,
50
+ __RIDLBE_VER__: @backend.version
51
+ })
52
+ })
53
+ @optparser = init_optparser
54
+ @inputstack = []
55
+ @options = nil
56
+ end
54
57
 
55
- def IDL.backend
56
- @@backend
57
- end
58
+ def backend
59
+ @backend
60
+ end
58
61
 
59
- def IDL.init
60
- unless @@embedded
61
- # check commandline args for explicit language mapping backend
62
- if ARGV.first =~ /^:\S+/
63
- @@be_name = ARGV.shift.reverse.chop.reverse.to_sym
64
- elsif ENV['RIDL_BE_SELECT'] # or from environment
65
- @@be_name = ENV['RIDL_BE_SELECT'].to_sym
66
- end
62
+ def options
63
+ @options || @initopts
64
+ end
67
65
 
68
- # add optional search paths for RIDL backends
69
- $:.concat(ENV['RIDL_BE_PATH'].split(/:|;/)) if ENV['RIDL_BE_PATH']
66
+ def push_input(idlfile, opts)
67
+ @inputstack << [idlfile, opts]
68
+ end
70
69
 
71
- # check for special bootstrapping switches
72
- if ARGV.first == '--preprocess'
73
- @@preprocessing = true
74
- ARGV.shift
75
- elsif ARGV.first == '--ignore-pidl'
76
- @@no_pidl = true
77
- ARGV.shift
78
- end
70
+ def pop_input
71
+ @inputstack.shift
79
72
  end
80
- # try to load the active laguage mapping backend
81
- @@backend = @@be_name ? Backend.load(@@be_name) : Backend.null_be
82
- # finalize base options
83
- OPTIONS[:preprocess] = preprocessing?
84
- OPTIONS[:ignore_pidl] = no_pidl?
85
- OPTIONS[:backend] = @@backend
86
- OPTIONS[:__RIDLBE__] = @@backend.name.to_s
87
- OPTIONS[:__RIDLBE_VER__] = @@backend.version
88
- end
89
73
 
90
- # parse commandline arguments
91
- #
92
- def IDL.parse_args
93
- script_name = File.basename($0, '.*')
94
- if not script_name =~ /ridlc/
95
- script_name = "ruby "+$0
74
+ def peek_input
75
+ @inputstack.first
96
76
  end
97
77
 
98
- # set up option parser with common options
99
- opts = OptionParser.new
100
- opts.banner = "Usage: #{script_name} [:backend] [options] [<idlfile> [<idlfile> ...]]\n\n" +
101
- " backend\t\tSpecifies the IDL language mapping backend to use.\n"+
102
- " \t\tDefault = :null\n\n"+
103
- " Active language mapping = :#{IDL.backend.name}"
104
- opts.separator ""
105
- opts.on("-I PATH", "--include=PATH", String,
106
- "Adds include searchpath.",
107
- "Default: nil") { |v| OPTIONS[:includepaths] << v }
108
- opts.on('-Dmacro=[value]', String, 'defines preprocessor macro') { |v|
109
- name, value = v.split('=')
110
- OPTIONS[:macros][name] = (value ? value : true)
111
- }
112
- opts.on("-n NAMESPACE", "--namespace=NAMESPACE", String,
113
- "Defines rootlevel enclosing namespace.",
114
- "Default: nil") { |v| OPTIONS[:namespace]=v }
115
- opts.on("-v", "--verbose",
116
- "Set verbosity level. Repeat to increment.",
117
- "Default: 0") { |v| OPTIONS[:verbose] += 1 }
118
- opts.on("--debug",
119
- "Set parser debug mode. Don't do this at home!",
120
- "Default: off") { |v| OPTIONS[:debug] = true }
121
- opts.on('--stdidl',
122
- 'Adds include path to standard IDL files provided with RIDL.',
123
- 'Default: not set') { |v|
124
- OPTIONS[:includepaths] << File.expand_path(File.join(File.dirname(__FILE__), '..', 'idl'))
125
- }
126
- opts.on("--search-includepath",
127
- "Use include paths to find main IDL source.",
128
- "Default: off") { |v| OPTIONS[:search_incpath]=v }
129
- if preprocessing?
130
- opts.on("--output=FILE", String,
131
- "Specifies filename to generate output in.",
132
- "Default: File.basename(idlfile, '.idl')+<postfix>+<ext>") { |v| OPTIONS[:output]=v }
78
+ def has_input?
79
+ !@inputstack.empty?
133
80
  end
134
81
 
135
- # setup language mapping specific options
136
- be_options = OptionList.new
137
- @@backend.setup_be(be_options, OPTIONS)
138
- be_options.to_option_parser(opts, OPTIONS)
82
+ def verbose_level
83
+ options[:verbose]
84
+ end
139
85
 
140
- opts.on('-V', "--version",
141
- "Show version information and exit.") {
142
- puts "RIDL compiler #{OPTIONS[:macros][:__RIDL__]}"
143
- puts RIDL_COPYRIGHT
144
- puts '---'
145
- @@backend.print_version
146
- exit
147
- }
86
+ def verbose_level=(l)
87
+ options[:verbose] = l
88
+ end
148
89
 
149
- opts.separator ""
90
+ def run(argv, runopts = {})
150
91
 
151
- opts.on("-h", "--help",
152
- "Show this help message.") { puts opts; puts; exit }
92
+ # initialize options
93
+ @options = @initopts.merge(runopts)
153
94
 
154
- opts.parse!(ARGV)
155
- end
95
+ # backup current engine (if any)
96
+ cur_engine = Thread.current[:ridl_engine]
97
+ # store currently running engine for current thread
98
+ Thread.current[:ridl_engine] = self
156
99
 
157
- def IDL.push_input(idlfile, opts)
158
- @@idlstack << [idlfile, opts]
159
- end
100
+ begin
101
+ # parse arguments
102
+ begin
103
+ @optparser.parse!(argv)
104
+ rescue ArgumentError => ex
105
+ IDL.error(ex.inspect)
106
+ IDL.error(ex.backtrace.join("\n")) if IDL.verbose_level>0
107
+ return false
108
+ end
160
109
 
161
- def IDL.pop_input
162
- @@idlstack.shift
163
- end
110
+ if options[:preprocess]
164
111
 
165
- def IDL.peek_input
166
- @@idlstack.first
167
- end
112
+ ## PREPROCESSING
113
+ o = if options[:output].nil?
114
+ $stdout
115
+ else
116
+ File.open(options[:output], 'w+')
117
+ end
118
+ options[:output] = o
168
119
 
169
- def IDL.has_input?
170
- !@@idlstack.empty?
171
- end
120
+ input_base = File.basename(argv.first)
121
+ if (input_base != argv.first)
122
+ options[:xincludepaths] << File.dirname(argv.first)
123
+ end
172
124
 
173
- # main run method
174
- #
175
- def IDL.run
176
- # parse arguments
177
- begin
178
- parse_args
179
- rescue ArgumentError => ex
180
- IDL.error(ex.inspect)
181
- IDL.error(ex.backtrace.join("\n")) if $VERBOSE
182
- exit 1
183
- end
125
+ return !parse("#include \"#{input_base}\"", options).nil?
126
+ else
127
+ ## collect input files from commandline
128
+ collect_input(argv)
129
+
130
+ ## CODE GENERATION
131
+ while has_input?
132
+ # get input from stack
133
+ _idlfile, _opts = pop_input
134
+
135
+ _fio = if IO === _idlfile || StringIO === _idlfile
136
+ _idlfile
137
+ else
138
+ File.open(_idlfile, 'r')
139
+ end
140
+ raise RuntimeError, 'cannot read from STDOUT' if $stdout == _fio
141
+
142
+ # parse IDL source
143
+ IDL.log(1, "RIDL - parsing #{IO === _idlfile ? 'from STDIN': (StringIO === _idlfile ? 'from string' : _idlfile)}")
144
+
145
+ unless _parser = parse(_fio, _opts)
146
+ return false
147
+ end
184
148
 
185
- verbose_level = OPTIONS[:verbose]
149
+ # process parse result -> code generation
150
+ IDL.log(2, 'RIDL - starting code generation')
186
151
 
187
- if preprocessing?
188
- ## PREPROCESSING
189
- o = if OPTIONS[:output].nil?
190
- $stdout
191
- else
192
- File.open(OPTIONS[:output], "w+")
152
+ GenFile.transaction do
153
+ begin
154
+ backend.process_input(_parser, _opts)
155
+ rescue Backend::ProcessStop
156
+ IDL.log(2, "RIDL - processing #{IO === _idlfile ? 'from STDIN': (StringIO === _idlfile ? 'from string' : _idlfile)} stopped with \"#{$!.message}\"")
157
+ end
158
+ end
159
+ end
193
160
  end
194
- OPTIONS[:output] = o
161
+ ensure
162
+ # restore previous state
163
+ Thread.current[:ridl_engine] = cur_engine
164
+ end
165
+ true
166
+ end
195
167
 
196
- parser = ::IDL::Parser.new(OPTIONS)
197
- parser.yydebug = OPTIONS[:debug]
168
+ def parse(io, opts)
169
+ # parse IDL source
170
+ _parser = ::IDL::Parser.new(opts)
171
+ _parser.yydebug = opts[:debug]
198
172
 
199
173
  begin
200
- input_base = File.basename(ARGV.first)
201
- if (input_base != ARGV.first)
202
- OPTIONS[:includepaths] << File.dirname(ARGV.first)
203
- end
204
- parser.parse("#include \"#{input_base}\"")
174
+ _parser.parse(io)
205
175
  rescue => ex
206
176
  IDL.error(ex.inspect)
207
177
  IDL.error(ex.backtrace.join("\n")) unless ex.is_a? IDL::ParseError
178
+ return nil
208
179
  ensure
209
- o.close
180
+ io.close unless String === io || io == $stdin
210
181
  end
211
- else
182
+ _parser
183
+ end
184
+
185
+ private
186
+
187
+ def collect_input(argv)
212
188
  ## collect input files from commandline
213
- ARGV.each do |_arg|
214
- _opts = OPTIONS.dup
189
+ argv.each do |_arg|
190
+ _opts = options.dup
215
191
 
216
192
  _opts[:idlfile] = _arg
217
193
  if _opts[:search_incpath]
218
194
  _fname = _arg
219
195
  _fpath = if File.file?(_fname) && File.readable?(_fname)
220
- _fname
221
- else
222
- _fp = _opts[:includepaths].find do |_p|
223
- _f = _p + "/" + _fname
224
- File.file?(_f) && File.readable?(_f)
225
- end
226
- _opts[:outputdir] = _fp unless _fp.nil? || !_opts[:outputdir].nil?
227
- _fp += '/' + _fname unless _fp.nil?
228
- _fp
229
- end
196
+ _fname
197
+ else
198
+ _fp = _opts[:includepaths].find do |_p|
199
+ _f = _p + "/" + _fname
200
+ File.file?(_f) && File.readable?(_f)
201
+ end
202
+ _opts[:outputdir] = _fp unless _fp.nil? || !_opts[:outputdir].nil?
203
+ _fp += '/' + _fname unless _fp.nil?
204
+ _fp
205
+ end
230
206
  _arg = _fpath unless _fpath.nil?
231
207
  end
232
- _opts[:includepaths] << File.dirname(_arg)
208
+ _opts[:xincludepaths] << File.dirname(_arg)
233
209
 
234
210
  _opts[:outputdir] ||= '.'
235
211
 
@@ -238,59 +214,109 @@ module IDL
238
214
 
239
215
  ## if no IDL input file specified read from STDIN
240
216
  unless has_input?
241
- _opts = OPTIONS.dup
217
+ _opts = options.dup
242
218
  _opts[:outputdir] ||= '.'
243
219
  push_input($stdin, _opts)
244
220
  end
221
+ end
245
222
 
246
- ## CODE GENERATION
247
- while has_input?
248
- # get input from stack
249
- _idlfile, _opts = pop_input
250
-
251
- _fio = if IO === _idlfile || StringIO === _idlfile
252
- _idlfile
253
- else
254
- File.open(_idlfile, "r")
255
- end
256
- raise RuntimeError, 'cannot read from STDOUT' if $stdout == _fio
223
+ def init_optparser
224
+ script_name = File.basename($0, '.*')
225
+ if not script_name =~ /ridlc/
226
+ script_name = 'ruby '+$0
227
+ end
257
228
 
258
- # parse IDL source
259
- IDL.log(1, "RIDL - parsing #{IO === _idlfile ? 'from STDIN': _idlfile}")
229
+ # set up option parser with common options
230
+ opts = OptionParser.new
231
+ opts.banner = "Usage: #{script_name} [:backend] [options] [<idlfile> [<idlfile> ...]]\n\n" +
232
+ " backend\t\tSpecifies the IDL language mapping backend to use.\n"+
233
+ " \t\tDefault = :null\n\n"+
234
+ " Active language mapping = :#{backend.name}"
235
+ opts.separator ""
236
+ opts.on("-I PATH", "--include=PATH", String,
237
+ "Adds include searchpath.",
238
+ "Default: nil") { |v| @options[:includepaths] << v }
239
+ opts.on('-Dmacro=[value]', String, 'defines preprocessor macro') { |v|
240
+ name, value = v.split('=')
241
+ @options[:macros][name] = (value ? value : true)
242
+ }
243
+ opts.on("-n NAMESPACE", "--namespace=NAMESPACE", String,
244
+ "Defines rootlevel enclosing namespace.",
245
+ "Default: nil") { |v| @options[:namespace]=v }
246
+ opts.on("-v", "--verbose",
247
+ "Set verbosity level. Repeat to increment.",
248
+ "Default: 0") { |v| @options[:verbose] += 1 }
249
+ opts.on("--debug",
250
+ "Set parser debug mode. Don't do this at home!",
251
+ "Default: off") { |v| @options[:debug] = true }
252
+ opts.on('--stdidl',
253
+ 'Adds include path to standard IDL files provided with RIDL.',
254
+ 'Default: not set') { |v|
255
+ @options[:includepaths] << File.expand_path(File.join(File.dirname(__FILE__), '..', 'idl'))
256
+ }
257
+ opts.on("--search-includepath",
258
+ "Use include paths to find main IDL source.",
259
+ "Default: off") { |v| @options[:search_incpath]=v }
260
+ if @initopts[:preprocess]
261
+ opts.on("--output=FILE", String,
262
+ "Specifies filename to generate output in.",
263
+ "Default: basename(idlfile)-'.idl'+<postfix>+<ext>") { |v| @options[:output]=v }
264
+ end
260
265
 
261
- _parser = ::IDL::Parser.new(_opts)
262
- _parser.yydebug = _opts[:debug]
266
+ # setup language mapping specific options
267
+ be_options = OptionList.new
268
+ @backend.setup_be(be_options, @initopts)
269
+ be_options.to_option_parser(opts, self)
270
+
271
+ opts.on('-V', '--version',
272
+ 'Show version information and exit.') {
273
+ puts "RIDL compiler #{@options[:macros][:__RIDL__]}"
274
+ puts RIDL_COPYRIGHT
275
+ puts '---'
276
+ @backend.print_version
277
+ exit
278
+ }
263
279
 
264
- begin
265
- _parser.parse(_fio)
266
- rescue => ex
267
- IDL.error(ex.inspect)
268
- IDL.error(ex.backtrace.join("\n")) unless ex.is_a? IDL::ParseError
269
- exit 1
270
- ensure
271
- _fio.close unless _fio == $stdin
272
- end
280
+ opts.separator ""
273
281
 
274
- # process parse result -> code generation
275
- IDL.log(2, 'RIDL - starting code generation')
282
+ opts.on('-h', '--help',
283
+ 'Show this help message.') { puts opts; puts; exit }
276
284
 
277
- GenFile.transaction do
278
- begin
279
- @@backend.process_input(_parser, _opts)
280
- rescue Backend::ProcessStop
281
- IDL.log(2, "RIDL - processing #{IO === _idlfile ? 'from STDIN': _idlfile} stopped from #{$!.message}")
282
- end
283
- end
284
- end
285
+ opts
285
286
  end
286
- end # IDL.run
287
+
288
+ end
289
+
290
+ def IDL.backend
291
+ Thread.current[:ridl_engine] ? Thread.current[:ridl_engine].backend : nil
292
+ end
293
+
294
+ def IDL.push_input(idlfile, opts)
295
+ Thread.current[:ridl_engine].push_input(idlfile, opts) if Thread.current[:ridl_engine]
296
+ end
297
+
298
+ def IDL.pop_input
299
+ Thread.current[:ridl_engine].pop_input if Thread.current[:ridl_engine]
300
+ end
301
+
302
+ def IDL.peek_input
303
+ Thread.current[:ridl_engine].peek_input if Thread.current[:ridl_engine]
304
+ end
305
+
306
+ def IDL.has_input?
307
+ Thread.current[:ridl_engine].has_input? if Thread.current[:ridl_engine]
308
+ end
287
309
 
288
310
  def IDL.verbose_level
289
- @@verbose_level
311
+ Thread.current[:ridl_engine] ? Thread.current[:ridl_engine].verbose_level : OPTIONS[:verbose]
290
312
  end
291
313
 
292
314
  def IDL.verbose_level=(l)
293
- @@verbose_level = l
315
+ if Thread.current[:ridl_engine]
316
+ Thread.current[:ridl_engine].verbose_level = l.to_i
317
+ else
318
+ OPTIONS[:verbose] = l.to_i
319
+ end
294
320
  end
295
321
 
296
322
  def IDL.log(level, message)
@@ -301,4 +327,41 @@ module IDL
301
327
  STDERR.puts(message)
302
328
  end
303
329
 
330
+ def IDL.init(argv = ARGV)
331
+ options = OPTIONS.dup
332
+
333
+ unless @@embedded
334
+ # check commandline args for explicit language mapping backend
335
+ if argv.first =~ /^:\S+/
336
+ @@be_name = argv.shift.reverse.chop.reverse.to_sym
337
+ elsif ENV['RIDL_BE_SELECT'] # or from environment
338
+ @@be_name = ENV['RIDL_BE_SELECT'].to_sym
339
+ end
340
+
341
+ # add optional search paths for RIDL backends
342
+ $:.concat(ENV['RIDL_BE_PATH'].split(/:|;/)) if ENV['RIDL_BE_PATH']
343
+
344
+ # check for special bootstrapping switches
345
+ if argv.first == '--preprocess'
346
+ options[:preprocess] = true
347
+ argv.shift
348
+ elsif argv.first == '--ignore-pidl'
349
+ options[:ignore_pidl] = true
350
+ argv.shift
351
+ end
352
+ end
353
+
354
+ # create RIDL engine
355
+ Thread.current[:ridl_engine] = Engine.new(@@be_name, options)
356
+ end
357
+
358
+ # main run method
359
+ #
360
+ def IDL.run(argv = ARGV)
361
+ # run default engine if available
362
+ if Thread.current[:ridl_engine]
363
+ exit(1) unless Thread.current[:ridl_engine].run(argv)
364
+ end
365
+ end # IDL.run
366
+
304
367
  end