ridl 2.5.6 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,7 +8,6 @@
8
8
  # included with this program.
9
9
  #
10
10
  # Copyright (c) Remedy IT Expertise BV
11
- # Chamber of commerce Rotterdam nr.276339, The Netherlands
12
11
  #--------------------------------------------------------------------
13
12
  require 'optparse'
14
13
 
@@ -2620,13 +2620,13 @@ module_eval(<<'.,.,', 'parser.ry', 316)
2620
2620
 
2621
2621
  module_eval(<<'.,.,', 'parser.ry', 318)
2622
2622
  def _reduce_174(val, _values)
2623
- [FALSE, [val[0]]]
2623
+ [false, [val[0]]]
2624
2624
  end
2625
2625
  .,.,
2626
2626
 
2627
2627
  module_eval(<<'.,.,', 'parser.ry', 319)
2628
2628
  def _reduce_175(val, _values)
2629
- [TRUE, [val[1]]]
2629
+ [true, [val[1]]]
2630
2630
  end
2631
2631
  .,.,
2632
2632
 
@@ -3102,13 +3102,13 @@ module_eval(<<'.,.,', 'parser.ry', 512)
3102
3102
 
3103
3103
  module_eval(<<'.,.,', 'parser.ry', 514)
3104
3104
  def _reduce_275(val, _values)
3105
- TRUE
3105
+ true
3106
3106
  end
3107
3107
  .,.,
3108
3108
 
3109
3109
  module_eval(<<'.,.,', 'parser.ry', 515)
3110
3110
  def _reduce_276(val, _values)
3111
- FALSE
3111
+ false
3112
3112
  end
3113
3113
  .,.,
3114
3114
 
@@ -8,7 +8,6 @@
8
8
  # included with this program.
9
9
  #
10
10
  # Copyright (c) Remedy IT Expertise BV
11
- # Chamber of commerce Rotterdam nr.276339, The Netherlands
12
11
  #--------------------------------------------------------------------
13
12
 
14
13
  class Parser
@@ -52,7 +51,7 @@ rule
52
51
  { @d.register_template_module_name(val[1]) }
53
52
 
54
53
  template_module_parameters : template_module_parameter
55
- | template_module_parameters "," template_module_parameter
54
+ | template_module_parameters "," template_module_parameter
56
55
 
57
56
  template_module_parameter : "typename" identifier
58
57
  { @d.define_template_parameter(val[1], IDL::Type::Any.new) }
@@ -78,7 +77,7 @@ rule
78
77
  { @d.define_template_parameter(val[1], val[0]) }
79
78
 
80
79
  template_module_body : template_module_definition
81
- | template_module_body template_module_definition
80
+ | template_module_body template_module_definition
82
81
 
83
82
  template_module_definition : type_dcl ";"
84
83
  | const_dcl ";"
@@ -117,11 +116,11 @@ rule
117
116
 
118
117
  template_module_inst : template_module_header "<" template_module_inst_parameters ">" identifier
119
118
  { @d.instantiate_template_module(val[4], val[2]) }
120
-
119
+
121
120
  template_module_inst_parameters : template_module_inst_parameter
122
121
  { [val[0]] }
123
122
  | template_module_inst_parameters "," template_module_inst_parameter
124
- { val[0] << val[2]; val[0] }
123
+ { val[0] << val[2]; val[0] }
125
124
 
126
125
  template_module_inst_parameter : base_type_spec
127
126
  { val[0] }
@@ -132,7 +131,7 @@ rule
132
131
 
133
132
  template_module_reference : "alias" scoped_name "<" _scoped_name_list ">" identifier
134
133
  { @d.declare_template_reference(val[5], val[1], val[3]) }
135
-
134
+
136
135
  interface : interface_dcl
137
136
  | forward_dcl
138
137
 
@@ -194,7 +193,7 @@ rule
194
193
 
195
194
  home : home_header "{" home_body "}"
196
195
  { @d.end_home(val[0]) }
197
-
196
+
198
197
  home_header : "home" identifier ":" home_inheritance_spec "supports" home_supports_spec "manages" scoped_name "primarykey" home_primarykey_spec
199
198
  { @d.define_home(val[1], val[3], val[7], val[9], val[5]) }
200
199
  | "home" identifier ":" home_inheritance_spec "supports" home_supports_spec "manages" scoped_name
@@ -211,11 +210,11 @@ rule
211
210
  { @d.define_home(val[1], nil, val[3], val[5], nil) }
212
211
  | "home" identifier "manages" scoped_name
213
212
  { @d.define_home(val[1], nil, val[3], nil, nil) }
214
-
215
- home_inheritance_spec : scoped_name
216
-
213
+
214
+ home_inheritance_spec : scoped_name
215
+
217
216
  home_supports_spec : _interface_name_list
218
-
217
+
219
218
  home_primarykey_spec : scoped_name
220
219
 
221
220
  home_body : home_export
@@ -227,26 +226,26 @@ rule
227
226
 
228
227
  porttype : porttype_header "{" porttype_body "}"
229
228
  { @d.end_porttype(val[0]) }
230
-
229
+
231
230
  porttype_header : "porttype" identifier
232
231
  { @d.define_porttype(val[1]) }
233
-
232
+
234
233
  porttype_body : porttype_export
235
234
  | porttype_body porttype_export
236
235
 
237
236
  porttype_export : provides_dcl ";"
238
237
  | uses_dcl ";"
239
238
  | attr_dcl ";"
240
-
239
+
241
240
  component : component_dcl
242
241
  | component_forward_dcl
243
-
242
+
244
243
  component_forward_dcl : "component" identifier
245
244
  { @d.declare_component(val[1]) }
246
-
245
+
247
246
  component_dcl : component_header "{" component_body "}"
248
247
  { @d.end_component(val[0]) }
249
-
248
+
250
249
  component_header : "component" identifier ":" component_inheritance_spec "supports" component_supports_spec
251
250
  { @d.define_component(val[1], val[3], val[5]) }
252
251
  | "component" identifier ":" component_inheritance_spec
@@ -255,11 +254,11 @@ rule
255
254
  { @d.define_component(val[1], nil, val[3]) }
256
255
  | "component" identifier
257
256
  { @d.define_component(val[1], nil, nil) }
258
-
257
+
259
258
  component_inheritance_spec : scoped_name
260
-
259
+
261
260
  component_supports_spec : _interface_name_list
262
-
261
+
263
262
  component_body : component_export
264
263
  | component_body component_export
265
264
 
@@ -274,7 +273,7 @@ rule
274
273
 
275
274
  connector : connector_header "{" connector_body "}"
276
275
  { @d.end_connector(val[0]) }
277
-
276
+
278
277
  connector_header : "connector" identifier ":" scoped_name
279
278
  { @d.define_connector(val[1], val[3]) }
280
279
  | "connector" identifier
@@ -291,33 +290,33 @@ rule
291
290
 
292
291
  provides_dcl : "provides" interface_type identifier
293
292
  { @d.declare_port(val[2], :facet, val[1]) }
294
-
293
+
295
294
  uses_dcl : "uses" "multiple" interface_type identifier
296
295
  { @d.declare_port(val[3], :receptacle, val[2], true) }
297
296
  | "uses" interface_type identifier
298
297
  { @d.declare_port(val[2], :receptacle, val[1], false) }
299
-
298
+
300
299
  publishes_dcl : "publishes" scoped_name identifier
301
300
  { @d.declare_port(val[2], :publisher, val[1]) }
302
-
301
+
303
302
  emits_dcl : "emits" scoped_name identifier
304
303
  { @d.declare_port(val[2], :emitter, val[1]) }
305
-
304
+
306
305
  consumes_dcl : "consumes" scoped_name identifier
307
306
  { @d.declare_port(val[2], :consumer, val[1]) }
308
-
307
+
309
308
  port_dcl : "port" scoped_name identifier
310
309
  { @d.declare_port(val[2], :port, val[1]) }
311
310
  | "mirrorport" scoped_name identifier
312
311
  { @d.declare_port(val[2], :mirrorport, val[1]) }
313
-
312
+
314
313
  interface_type : scoped_name
315
- | object_type
314
+ | object_type
316
315
 
317
316
  scoped_name : scoped_name_0 { @d.parse_scopedname(*val[0]) }
318
317
 
319
- scoped_name_0 : identifier { [FALSE, [val[0]]] }
320
- | "::" identifier { [TRUE, [val[1]]] }
318
+ scoped_name_0 : identifier { [false, [val[0]]] }
319
+ | "::" identifier { [true, [val[1]]] }
321
320
  | scoped_name_0 "::" identifier
322
321
  { val[0][1] << val[2]; val[0] }
323
322
 
@@ -396,8 +395,8 @@ rule
396
395
 
397
396
  value_name : scoped_name
398
397
 
399
- value_element : export
400
- | state_member ";"
398
+ value_element : export
399
+ | state_member ";"
401
400
  | init_dcl ";"
402
401
 
403
402
  state_member : "public" type_spec declarators
@@ -460,7 +459,7 @@ rule
460
459
  const_exp : or_expr
461
460
 
462
461
  or_expr : xor_expr
463
- | or_expr "|" xor_expr
462
+ | or_expr "|" xor_expr
464
463
  { Expression::Operation::Or.new(val[0], val[2]) }
465
464
 
466
465
  xor_expr : and_expr
@@ -512,8 +511,8 @@ rule
512
511
  | floating_pt_literal { @d.parse_literal(:float, val[0]) }
513
512
  | boolean_literal { @d.parse_literal(:boolean, val[0]) }
514
513
 
515
- boolean_literal : "TRUE" { TRUE }
516
- | "FALSE" { FALSE }
514
+ boolean_literal : "TRUE" { true }
515
+ | "FALSE" { false }
517
516
 
518
517
  positive_int_const : const_exp { @d.parse_positive_int(val[0]) }
519
518
 
@@ -525,7 +524,7 @@ rule
525
524
  | enum_type
526
525
  | "native" native_declarator
527
526
 
528
- type_declarator : type_spec declarators
527
+ type_declarator : type_spec declarators
529
528
  {
530
529
  dcls = parse_type_declarator(val[0], val[1])
531
530
  dcls.each do |d|
@@ -624,7 +623,7 @@ rule
624
623
  member_list : member
625
624
  | member_list member
626
625
 
627
- member : type_spec declarators ";"
626
+ member : type_spec declarators ";"
628
627
  {
629
628
  dcls = parse_type_declarator(val[0], val[1])
630
629
  dcls.each do |d|
@@ -659,10 +658,10 @@ rule
659
658
  | union_body union_case
660
659
 
661
660
  union_case : _case_label_1 element_spec ";"
662
- {
661
+ {
663
662
  dcls = parse_type_declarator(val[1][0], [val[1][1]])
664
663
  dcls.each do |d|
665
- @d.define_case(val[0], d[0], d[1])
664
+ @d.define_case(val[0], d[0], d[1])
666
665
  end
667
666
  }
668
667
 
@@ -684,7 +683,7 @@ rule
684
683
  _enumerator_list : enumerator
685
684
  | _enumerator_list "," enumerator
686
685
 
687
- enumerator : identifier
686
+ enumerator : identifier
688
687
  {
689
688
  @d.declare_enumerator(val[0])
690
689
  }
@@ -746,7 +745,7 @@ rule
746
745
  attr_no_raises_expr : { [[], []] }
747
746
 
748
747
  attr_declarator_list : simple_declarator "," _simple_declarator_list
749
- { [val[0]].concat(val[2]) }
748
+ { [val[0]].concat(val[2]) }
750
749
 
751
750
  readonly_attr_declarator : simple_declarator raises_expr
752
751
  { [[val[0]], val[1]] }
@@ -8,7 +8,6 @@
8
8
  # included with this program.
9
9
  #
10
10
  # Copyright (c) Remedy IT Expertise BV
11
- # Chamber of commerce Rotterdam nr.276339, The Netherlands
12
11
  #--------------------------------------------------------------------
13
12
  require 'ridl/version'
14
13
  require 'ridl/scanner'
@@ -13,7 +13,6 @@
13
13
  # included with this program.
14
14
  #
15
15
  # Copyright (c) Remedy IT Expertise BV
16
- # Chamber of commerce Rotterdam nr.276339, The Netherlands
17
16
  #--------------------------------------------------------------------
18
17
  require 'ridl/require'
19
18
 
@@ -8,12 +8,12 @@
8
8
  # included with this program.
9
9
  #
10
10
  # Copyright (c) Remedy IT Expertise BV
11
- # Chamber of commerce Rotterdam nr.276339, The Netherlands
12
11
  #--------------------------------------------------------------------
13
12
  require 'stringio'
14
13
  require 'ridl/optparse_ext'
15
14
  require 'ridl/genfile'
16
15
  require 'ridl/backend'
16
+ require 'ridl/options'
17
17
 
18
18
  # -----------------------------------------------------------------------
19
19
 
@@ -24,7 +24,7 @@ module IDL
24
24
  @@embedded = false unless class_variable_defined?(:@@embedded)
25
25
  @@be_name = nil unless class_variable_defined?(:@@be_name)
26
26
 
27
- OPTIONS = {
27
+ OPTIONS = Options.new({
28
28
  :outputdir => nil,
29
29
  :includepaths => [],
30
30
  :xincludepaths => [],
@@ -34,11 +34,9 @@ module IDL
34
34
  :search_incpath => false,
35
35
  :backend => nil,
36
36
  :macros => {
37
- :__RIDL__ => "#{RIDL_VERSION}",
38
- :__RIDLBE__ => nil,
39
- :__RIDLBE_VER__ => nil
40
37
  }
41
- }
38
+ })
39
+ CORE_OPTIONS = OPTIONS.keys
42
40
 
43
41
  class Engine
44
42
  def initialize(backend, options)
@@ -46,12 +44,15 @@ module IDL
46
44
  @initopts = options.merge({
47
45
  backend: @backend.name,
48
46
  macros: options[:macros].merge({
47
+ __RIDL__: "#{RIDL_VERSION}",
49
48
  __RIDLBE__: @backend.name.to_s,
50
49
  __RIDLBE_VER__: @backend.version
51
50
  })
52
51
  })
53
52
  @optparser = init_optparser
54
53
  @inputstack = []
54
+ @productionbatch = {}
55
+ @productionstack = []
55
56
  @options = nil
56
57
  end
57
58
 
@@ -63,6 +64,8 @@ module IDL
63
64
  @options || @initopts
64
65
  end
65
66
 
67
+ # Input management
68
+
66
69
  def push_input(idlfile, opts)
67
70
  @inputstack << [idlfile, opts]
68
71
  end
@@ -79,6 +82,48 @@ module IDL
79
82
  !@inputstack.empty?
80
83
  end
81
84
 
85
+ # Production management
86
+
87
+ def push_production(id, producer)
88
+ raise RuntimeError, "Producer #{id} already queued" if @productionbatch.has_key?(id.to_sym)
89
+ @productionbatch[id.to_sym] = @productionstack.size
90
+ @productionstack << [id.to_sym, producer]
91
+ end
92
+
93
+ def pop_production
94
+ return nil unless has_productions?
95
+ id, producer = @productionstack.shift
96
+ @productionbatch.delete(id)
97
+ producer
98
+ end
99
+
100
+ def peek_production
101
+ return nil unless has_productions?
102
+ id, _ = @productionstack.first
103
+ id
104
+ end
105
+
106
+ def remove_production(id)
107
+ return nil unless has_production?(id)
108
+ i = @productionbatch.delete(id.to_sym)
109
+ _, producer = @productionstack.delete(i)
110
+ producer
111
+ end
112
+
113
+ def has_productions?
114
+ !@productionstack.empty?
115
+ end
116
+
117
+ def has_production?(id)
118
+ @productionbatch.has_key?(id.to_sym)
119
+ end
120
+
121
+ def production(id)
122
+ @productionstack[@productionbatch[id.to_sym]].last
123
+ end
124
+
125
+ # Verbosity control
126
+
82
127
  def verbose_level
83
128
  options[:verbose]
84
129
  end
@@ -92,6 +137,9 @@ module IDL
92
137
  # initialize options
93
138
  @options = @initopts.merge(runopts)
94
139
 
140
+ # mark current (clean) state
141
+ @options.mark
142
+
95
143
  # backup current engine (if any)
96
144
  cur_engine = Thread.current[:ridl_engine]
97
145
  # store currently running engine for current thread
@@ -118,7 +166,7 @@ module IDL
118
166
  options[:output] = o
119
167
 
120
168
  input_base = File.basename(argv.first)
121
- if (input_base != argv.first)
169
+ if input_base != argv.first
122
170
  options[:xincludepaths] << (File.dirname(argv.first)+'/')
123
171
  end
124
172
 
@@ -147,13 +195,31 @@ module IDL
147
195
  end
148
196
 
149
197
  # process parse result -> code generation
150
- IDL.log(2, 'RIDL - starting code generation')
198
+ IDL.log(2, 'RIDL - processing input')
151
199
 
152
200
  GenFile.transaction do
153
201
  begin
202
+
154
203
  backend.process_input(_parser, _opts)
204
+
205
+ # handle productions
206
+ while has_productions?
207
+ IDL.log(2, "RIDL - running production #{peek_production}")
208
+
209
+ # get next-in-line producer
210
+ producer = pop_production
211
+
212
+ # execute the producer
213
+ producer.run(_parser)
214
+ end
215
+
155
216
  rescue Backend::ProcessStop
156
217
  IDL.log(2, "RIDL - processing #{IO === _idlfile ? 'from STDIN': (StringIO === _idlfile ? 'from string' : _idlfile)} stopped with \"#{$!.message}\"")
218
+
219
+ rescue => ex
220
+ IDL.error(ex)
221
+ IDL.error(ex.backtrace.join("\n")) unless ex.is_a? IDL::ParseError
222
+ return false
157
223
  end
158
224
  end
159
225
  end
@@ -190,22 +256,28 @@ module IDL
190
256
  _opts = options.dup
191
257
 
192
258
  _opts[:idlfile] = _arg
193
- if _opts[:search_incpath]
194
- _fname = _arg
195
- _fpath = if File.file?(_fname) && File.readable?(_fname)
196
- _fname
197
- else
198
- _fp = _opts[:includepaths].find do |_p|
199
- _f = _p + _fname
200
- File.file?(_f) && File.readable?(_f)
259
+ if _opts[:no_input]
260
+ # do not parse specified file (only used as template for output names)
261
+ # instead push an empty StringIO object
262
+ _arg = StringIO.new('')
263
+ else
264
+ if _opts[:search_incpath]
265
+ _fname = _arg
266
+ _fpath = if File.file?(_fname) && File.readable?(_fname)
267
+ _fname
268
+ else
269
+ _fp = _opts[:includepaths].find do |_p|
270
+ _f = _p + _fname
271
+ File.file?(_f) && File.readable?(_f)
272
+ end
273
+ _opts[:outputdir] = _fp unless _fp.nil? || !_opts[:outputdir].nil?
274
+ _fp += '/' + _fname unless _fp.nil?
275
+ _fp
201
276
  end
202
- _opts[:outputdir] = _fp unless _fp.nil? || !_opts[:outputdir].nil?
203
- _fp += '/' + _fname unless _fp.nil?
204
- _fp
205
- end
206
- _arg = _fpath unless _fpath.nil?
277
+ _arg = _fpath unless _fpath.nil?
278
+ end
279
+ _opts[:xincludepaths] << (File.dirname(_arg)+'/')
207
280
  end
208
- _opts[:xincludepaths] << (File.dirname(_arg)+'/')
209
281
 
210
282
  _opts[:outputdir] ||= '.'
211
283
 
@@ -232,35 +304,47 @@ module IDL
232
304
  " backend\t\tSpecifies the IDL language mapping backend to use.\n"+
233
305
  " \t\tDefault = :null\n\n"+
234
306
  " Active language mapping = :#{backend.name}"
235
- opts.separator ""
236
- opts.on("-I PATH", "--include=PATH", String,
237
- "Adds include searchpath.",
238
- "Default: none") { |v| @options[:includepaths] << (v.end_with?('\\','/') ? v : v+'/') }
307
+ opts.separator ''
308
+ opts.on('-I PATH', '--include=PATH', String,
309
+ 'Adds include searchpath.',
310
+ 'Default: none') { |v|
311
+ self.options[:includepaths] << (v.end_with?('\\','/') ? v : v+'/')
312
+ }
239
313
  opts.on('-Dmacro=[value]', String, 'defines preprocessor macro') { |v|
240
314
  name, value = v.split('=')
241
- @options[:macros][name] = (value ? value : true)
315
+ self.options[:macros][name] = (value ? value : true)
316
+ }
317
+ opts.on('-n NAMESPACE', '--namespace=NAMESPACE', String,
318
+ 'Defines rootlevel enclosing namespace.',
319
+ 'Default: nil') { |v|
320
+ self.options[:namespace] = v
321
+ }
322
+ opts.on('-v', '--verbose',
323
+ 'Set verbosity level. Repeat to increment.',
324
+ 'Default: 0') { |_|
325
+ self.options[:verbose] += 1
326
+ }
327
+ opts.on('--debug',
328
+ 'Set parser debug mode. Do NOT do this at home!',
329
+ 'Default: off') { |_|
330
+ self.options[:debug] = true
242
331
  }
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'))+'/')
332
+ opts.on('--search-includepath',
333
+ 'Use include paths to find main IDL source.',
334
+ 'Default: off') { |_|
335
+ self.options[:search_incpath] = true
336
+ }
337
+ opts.on('--no-input',
338
+ 'Do not parse specified file(s) as input IDL.',
339
+ 'Default: off') { |_|
340
+ self.options[:no_input] = true
256
341
  }
257
- opts.on("--search-includepath",
258
- "Use include paths to find main IDL source.",
259
- "Default: off") { |v| @options[:search_incpath]=v }
260
342
  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 }
343
+ opts.on('--output=FILE', String,
344
+ 'Specifies filename to generate output in.',
345
+ 'Default: basename(idlfile)-\'.idl\'+<postfix>+<ext>') { |v|
346
+ self.options[:output] = v
347
+ }
264
348
  end
265
349
 
266
350
  # setup language mapping specific options
@@ -270,7 +354,7 @@ module IDL
270
354
 
271
355
  opts.on('-V', '--version',
272
356
  'Show version information and exit.') {
273
- puts "RIDL compiler #{@options[:macros][:__RIDL__]}"
357
+ puts "RIDL compiler #{RIDL_VERSION}"
274
358
  puts RIDL_COPYRIGHT
275
359
  puts '---'
276
360
  @backend.print_version
@@ -287,24 +371,57 @@ module IDL
287
371
 
288
372
  end
289
373
 
374
+ def IDL.engine?
375
+ !Thread.current[:ridl_engine].nil?
376
+ end
377
+
290
378
  def IDL.backend
291
379
  Thread.current[:ridl_engine] ? Thread.current[:ridl_engine].backend : nil
292
380
  end
293
381
 
294
382
  def IDL.push_input(idlfile, opts)
295
- Thread.current[:ridl_engine].push_input(idlfile, opts) if Thread.current[:ridl_engine]
383
+ Thread.current[:ridl_engine].push_input(idlfile, opts) if engine?
296
384
  end
297
385
 
298
386
  def IDL.pop_input
299
- Thread.current[:ridl_engine].pop_input if Thread.current[:ridl_engine]
387
+ return nil unless engine?
388
+ Thread.current[:ridl_engine].pop_input
300
389
  end
301
390
 
302
391
  def IDL.peek_input
303
- Thread.current[:ridl_engine].peek_input if Thread.current[:ridl_engine]
392
+ return nil unless engine?
393
+ Thread.current[:ridl_engine].peek_input
304
394
  end
305
395
 
306
396
  def IDL.has_input?
307
- Thread.current[:ridl_engine].has_input? if Thread.current[:ridl_engine]
397
+ engine? && Thread.current[:ridl_engine].has_input?
398
+ end
399
+
400
+ def IDL.push_production(id, producer)
401
+ Thread.current[:ridl_engine].push_production(id, producer) if engine?
402
+ end
403
+
404
+ def IDL.pop_production
405
+ return nil unless engine?
406
+ Thread.current[:ridl_engine].pop_production
407
+ end
408
+
409
+ def IDL.remove_production(id)
410
+ return nil unless engine?
411
+ Thread.current[:ridl_engine].remove_production(id)
412
+ end
413
+
414
+ def IDL.has_productions?
415
+ engine? && Thread.current[:ridl_engine].has_productions?
416
+ end
417
+
418
+ def IDL.has_production?(id)
419
+ engine? && Thread.current[:ridl_engine].has_production?(id)
420
+ end
421
+
422
+ def IDL.production(id)
423
+ return nil unless engine?
424
+ Thread.current[:ridl_engine].production(id)
308
425
  end
309
426
 
310
427
  def IDL.verbose_level
@@ -327,19 +444,34 @@ module IDL
327
444
  STDERR.puts(message)
328
445
  end
329
446
 
447
+ def IDL.fatal(message)
448
+ STDERR.puts(message, 'Exiting.')
449
+ exit 1
450
+ end
451
+
330
452
  def IDL.init(argv = ARGV)
331
453
  options = OPTIONS.dup
332
454
 
333
455
  unless @@embedded
456
+ # load config file(s) if any
457
+ Options.load_config(options)
458
+
459
+ IDL.log(2, "Configuration [#{options}]")
460
+
334
461
  # check commandline args for explicit language mapping backend
335
462
  if argv.first =~ /^:\S+/
336
463
  @@be_name = argv.shift.reverse.chop.reverse.to_sym
337
464
  elsif ENV['RIDL_BE_SELECT'] # or from environment
338
465
  @@be_name = ENV['RIDL_BE_SELECT'].to_sym
466
+ elsif options[:backend] # or from configuration
467
+ @@be_name = options[:backend].to_sym
339
468
  end
340
469
 
341
470
  # add optional search paths for RIDL backends
342
- $:.concat(ENV['RIDL_BE_PATH'].split(/:|;/)) if ENV['RIDL_BE_PATH']
471
+ options[:be_path] ||= []
472
+ options[:be_path].unshift(*ENV['RIDL_BE_PATH'].split(/#{File::PATH_SEPARATOR}/)) if ENV['RIDL_BE_PATH']
473
+ options[:be_path].collect! {|p| p.gsub('\\', '/') } # cleanup to prevent mixed path separators
474
+ $:.concat(options[:be_path]) unless options[:be_path].empty?
343
475
 
344
476
  # check for special bootstrapping switches
345
477
  if argv.first == '--preprocess'