File: cluster.e

package info (click to toggle)
smarteiffel 1.1-11
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 12,288 kB
  • ctags: 40,785
  • sloc: ansic: 35,791; lisp: 4,036; sh: 1,783; java: 895; ruby: 613; python: 209; makefile: 115; csh: 78; cpp: 50
file content (667 lines) | stat: -rw-r--r-- 17,272 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
-- This file is part of SmartEiffel The GNU Eiffel Compiler Tools and Libraries
--
-- SmartEiffel is  free software;  you can redistribute it and/or  modify it
-- under  the terms of the  GNU General Public License, as published by  the
-- Free Software Foundation; either version 2, or (at your option) any later
-- version.
-- SmartEiffel is distributed in the hope that it will be useful but WITHOUT 
-- ANY WARRANTY;  without  even the implied warranty  of MERCHANTABILITY  or
-- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-- more details.  You should have received a copy of  the GNU General Public
-- License along with SmartEiffel;  see the file COPYING.  If not,  write to
-- the Free Software Foundation,  Inc., 59 Temple Place - Suite 330,  Boston, 
-- MA 02111-1307, USA.
--
-- Copyright(C) 1994-2002: INRIA - LORIA (INRIA Lorraine) - ESIAL U.H.P.
--			   - University of Nancy 1 - FRANCE
-- Copyright(C) 2003:      INRIA - LORIA (INRIA Lorraine) - I.U.T. Charlemagne
--			   - University of Nancy 2 - FRANCE
--
--		 Dominique COLNET, Suzanne COLLIN, Olivier ZENDRA,
--			   Philippe RIBET, Cyril ADRIAN
--
-- http://SmartEiffel.loria.fr - SmartEiffel@loria.fr
--
class CLUSTER
   --
   -- A CLUSTER description. Such an object is created for each cluster
   -- entry of the ACE file in ACE file mode, but also for each directory of
   -- the loading path for the ordinary command line mode.
   --

inherit
   GLOBALS
   VISITABLE
   ASSERTION_LEVEL_NUMBERING

creation {ACE} compute_directory_path_using

feature {CLUSTER_VISITOR}

   accept(visitor: CLUSTER_VISITOR) is
      do
         visitor.visit_cluster(Current)
      end

feature {ACE}

   parser_buffer_for(class_name: STRING): BOOLEAN is
	 -- Try to prepare the `parser_buffer' assuming `class_name' is the
	 -- classic Eiffel notation for a class name (actually the aliased
	 -- one using only upper case letters).
      require
	 class_name = string_aliaser.item(class_name)
      local
	 i, count: INTEGER; excluded: BOOLEAN
      do
	 -- Update the `file_name_buffer':
	 from
	    file_name_buffer.clear
	    i := 1
	    count := class_name.count
	 until
	    i > count
	 loop
	    file_name_buffer.extend(class_name.item(i).to_lower)
	    i := i + 1
	 end
	 file_name_buffer.extend('.')
	 file_name_buffer.extend('e')
	 if exclude_list /= Void then
	    excluded := exclude_list.has(file_name_buffer)
	 end
	 if excluded then
	 elseif parser_buffer_load then
	    -- Try the most common case first. (The name of the file uses
	    -- lower case letters only.)
	    Result := True
	 else
	    -- All in upper cases (strange but not so uncommon):
	    file_name_buffer.to_upper
	    if parser_buffer_load then
	       Result := True
	    else
	       -- May happens:
	       file_name_buffer.to_upper
	       file_name_buffer.put('e',file_name_buffer.count)
	       Result := parser_buffer_load
	    end
	 end
      end

   rename_se_parser_buffer_for(class_name: STRING): BOOLEAN is
	 -- To handle old "rename.se" files.
      require
	 class_name = string_aliaser.item(class_name)
      local
	 i, count: INTEGER
      do
	 -- Update the `file_name_buffer':
	 from
	    file_name_buffer.clear
	    i := 1
	    count := class_name.count
	 until
	    i > count
	 loop
	    file_name_buffer.extend(class_name.item(i).to_lower)
	    i := i + 1
	 end
	 file_name_buffer.extend('.')
	 file_name_buffer.extend('e')
	 if rename_se /= Void then
	    -- To handle old "rename.se" files.
	    if rename_se.has(file_name_buffer) then
	       file_name_buffer.copy(rename_se.at(file_name_buffer))
	       Result := parser_buffer_load
	    end
	 end
      end

   pretty_in(txt: STRING) is
	 -- Performs the `ace_check' and also prepare in `txt' a pretty version
	 -- of the Ace file as it is memorized (can be also used to pretty
	 -- one's ACE file).
      require
	 ace.file_path /= Void
      local
	 i, l: INTEGER; basic_directory: BASIC_DIRECTORY
	 cn: CLASS_NAME
      do
	 txt.append("   ")
	 if name /= Void then
	    txt.append(name)
	    txt.append(": ")
	 end
	 txt.extend('%"')
	 txt.append(directory_path)
	 txt.extend('%"')
	 basic_directory.connect_to(directory_path)
	 txt.extend('%N')
	 if basic_directory.is_connected then
	    basic_directory.disconnect
	 else
	    txt.append(" -- *** ERROR: directory %"")
	    txt.append(directory_path)
	    txt.append("%" not found or not readable ***%N")
	 end
	 if include_list /= Void then
	    txt.append("      include ")
	    from
	       i := include_list.lower
	    until
	       i > include_list.upper
	    loop
	       txt.extend('%"')
	       txt.append(include_list.item(i))
	       txt.extend('%"')
	       i := i + 1
	       if i <= include_list.upper then
		  txt.extend(';')
	       end
	    end
	    txt.extend('%N')
	 end
	 if exclude_list /= Void then
	    txt.append("      exclude ")
	    from
	       i := exclude_list.lower
	    until
	       i > exclude_list.upper
	    loop
	       txt.extend('%"')
	       txt.append(exclude_list.item(i))
	       txt.extend('%"')
	       i := i + 1
	       if i <= exclude_list.upper then
		  txt.extend(';')
	       end
	    end
	    txt.extend('%N')
	 end
	 txt.append("      default%N")
	 txt.append("         assertion (")
	 txt.append(level_name(default_assertion_level))
	 txt.append(")%N")
	 if default_trace /= '%U' then
	    txt.append("         trace (")
	    inspect
	       default_trace
	    when 'n' then
	       txt.append("no")
	    when 'y' then
	       txt.append("yes")
	    end
	    txt.append(")%N")
	 end
	 if option_assertion_level /= Void then
	    txt.append("      option%N")
	 end
	 if option_assertion_level /= Void then
	    from
	       i := option_assertion_level.lower
	    until
	       i > option_assertion_level.upper
	    loop
	       l := option_assertion_level.item(i)
	       cn := option_assertion_level.key(i)
	       txt.append("         assertion (")
	       txt.append(level_name(l))
	       txt.append("): ")
	       txt.append(cn.to_string)
	       txt.append("%N")
	       if not parser_buffer_for(cn.to_string) then
		  error_handler.add_position(cn.start_position)
		  error_handler.append("No such class in this cluster.")
		  error_handler.print_as_error
	       else
		  parser_buffer.release
	       end
	       i := i + 1
	    end
	 end
	 txt.append("      end")
	 if name /= Void then
	    txt.append(" -- ")
	    txt.append(name)
	 end
	 txt.extend('%N')
      end

   view_in(no: INTEGER; msg: STRING) is
      local
	 i: INTEGER
      do
	 msg.append("cluster ")
	 no.append_in(msg)
	 msg.append(":%N   ")
	 if name /= Void then
	    msg.append(name)
	    msg.extend(':')
	 end
	 msg.extend('%"')
	 msg.append(directory_path)
	 msg.extend('%"')
	 msg.extend('%N')
	 if ace.file_path /= Void then
	    if include_list /= Void then
	       msg.append("   include ")
	       from
		  i := include_list.lower
	       until
		  i > include_list.upper
	       loop
		  msg.extend('%"')
		  msg.append(include_list.item(i))
		  msg.extend('%"')
		  msg.extend(';')
		  i := i + 1
	       end
	       msg.extend('%N')
	    end
	    if exclude_list /= Void then
	       msg.append("   exclude ")
	       from
		  i := exclude_list.lower
	       until
		  i > exclude_list.upper
	       loop
		  msg.extend('%"')
		  msg.append(exclude_list.item(i))
		  msg.extend('%"')
		  msg.extend(';')
		  i := i + 1
	       end
	       msg.extend('%N')
	    end
	    msg.append("   default assertion (")
	    msg.append(level_name(default_assertion_level))
	    msg.extend(')')
	 end
	 msg.extend('%N')
      end

   set_name(n: like name) is
      require
	 string_aliaser.item(n) = n
      do
	 name := n
      ensure
	 name = n
      end

   set_default_trace(flag: BOOLEAN) is
      do
	 if flag then
	    default_trace := 'y'
	 else
	    default_trace := 'n'
	 end
      end

   set_default_assertion_level(level: INTEGER) is
      require
	 level.in_range(level_boost,level_debug)
      do
	 default_assertion_level := level
      ensure
	 default_assertion_level = level
      end

   add_default_debug_key(key: STRING) is
      require
	 key /= Void
      do
	 if default_debug_keys = Void then
	    !!default_debug_keys.make(4)
	 end
	 default_debug_keys.add_last(key)
      ensure
	 default_debug_keys.has(key)
      end

   get_started is
	 -- Should be called to set some default values at the end of
	 -- command line parsing or at the end of the ACE file parsing.
      do
	 if default_assertion_level = level_unknown then
	    default_assertion_level := ace.default_assertion_level
	 elseif default_assertion_level = level_boost then
	    if ace.highest_level > level_boost then
	       default_assertion_level := level_no
	    end
	 end
      end

   include_parsing is
      local
	 i: INTEGER; fn: STRING
      do
	 if include_list /= Void then
	    from
	       i := include_list.lower
	    until
	       i > include_list.upper
	    loop
	       fn := include_list.item(i)
	       file_name_buffer.copy(fn)
	       if not parser_buffer_load then
		  error_handler.append("Cannot find include %"")
		  error_handler.append(fn)
		  error_handler.append("%" in cluster %"")
		  error_handler.append(directory_path)
		  error_handler.append("%" (check your ACE file).")
		  error_handler.print_as_fatal_error
	       end
	       smart_eiffel.parse_include(fn)
	       i := i + 1
	    end
	 end
      end

   set_option_assertion_level(class_name: CLASS_NAME; level: INTEGER) is
      require
	 class_name /= Void
	 level.in_range(level_boost,level_debug)
      local
	 cn: CLASS_NAME
      do
	 if option_assertion_level = Void then
	    !!option_assertion_level.make
	 end
	 if option_assertion_level.has(class_name) then
	    error_handler.add_position(class_name.start_position)
	    cn := option_assertion_level.internal_key(class_name)
	    error_handler.add_position(cn.start_position)
	    error_handler.append("Same class name appears twice.")
	    error_handler.print_as_fatal_error
	 end
	 option_assertion_level.put(level,class_name)
      end

   assertion_level_of(class_name: CLASS_NAME): INTEGER is
      require
	 class_name /= Void
      do
	 check Result = level_unknown end
	 if option_assertion_level /= Void then
	    if option_assertion_level.has(class_name) then
	       Result := option_assertion_level.at(class_name)
	    else
	       check
		  Result = level_unknown
	       end
	    end
	 end
	 if Result = level_unknown then
	    Result := default_assertion_level
	    check Result /= level_unknown end
	 end
      ensure
	 Result.in_range(level_boost,level_debug)
      end

   add_option_debug_key(class_name: CLASS_NAME; key: STRING) is
      require
	 class_name /= Void
	 not key.is_empty
      local
	 fas: FIXED_ARRAY[STRING]
      do
	 if option_debug_keys = Void then
	    create option_debug_keys.make
	 end
	 fas := option_debug_keys.reference_at(class_name)
	 if fas = Void then
	    create fas.make(4)
	    option_debug_keys.add(fas,class_name)
	 end
	 fas.add_last(key)
      end

   debug_check(class_name: CLASS_NAME; e_debug: E_DEBUG): BOOLEAN is
      local
	 fas: FIXED_ARRAY[STRING]
      do
	 if option_debug_keys = Void then
	    if default_debug_keys = Void then
	       Result := ace.default_debug(e_debug)
	    else
	       Result := match_debug_keys(e_debug,default_debug_keys)
	    end
	 else
	    fas := option_debug_keys.reference_at(class_name)
	    if fas /= Void then
	       Result := match_debug_keys(e_debug,fas)
	    elseif default_debug_keys = Void then
	       Result := ace.default_debug(e_debug)
	    else
	       Result := match_debug_keys(e_debug,default_debug_keys)
	    end
	 end
      end

   add_option_trace(class_name: CLASS_NAME) is
      require
	 class_name /= Void
      do
	 if option_trace = Void then
	    !!option_trace.make
	 end
	 option_trace.add(class_name)
      end

   trace(class_name: CLASS_NAME): BOOLEAN is
      do
	 if option_trace = Void then
	    Result := default_trace_or_ace_default_trace
	 elseif option_trace.has(class_name) then
	    Result := True
	 else
	    Result := default_trace_or_ace_default_trace
	 end
      end

   include_add_last(file_name: STRING) is
      require
	 file_name /= Void
      do
	 if include_list = Void then
	    !!include_list.with_capacity(16)
	 end
	 include_list.add_last(file_name)
      end

   exclude_add_last(file_name: STRING) is
      require
	 file_name /= Void
      do
	 if exclude_list = Void then
	    !!exclude_list.with_capacity(16)
	 end
	 exclude_list.add_last(file_name)
      end

   rename_se_clash(full_name: STRING): STRING is
	 -- To handle old "rename.se" files.
      require
	 ace.file_path = Void
      do
	 if rename_se /= Void then
	    if rename_se.has(full_name) then
	       create Result.make(256)
	       Result.append(directory_path)
	       system_tools.file_path(Result,rename_se.at(full_name))
	    end
	 end
      end

   rename_se_read is
         -- Load the "rename.se" file.
      require
	 ace.file_path = Void
      local
         full_name, short_name, clash, rename_extension: STRING
      do
	 tmp_path.copy(directory_path)
	 rename_extension := once "rename.se"
	 if tmp_path.is_empty then
	    tmp_path.append(rename_extension)
	 else
	    system_tools.file_path(tmp_path,rename_extension)
	 end
	 echo.tfr_connect(tmp_file_read,tmp_path)
	 if tmp_file_read.is_connected then
	    error_handler.append("Old style %"rename.se%" file used (%"")
	    error_handler.append(tmp_file_read.path)
	    error_handler.append("%"). The %"rename.se%" mechanism may become obsolete %
	              %in the near futur. You should consider to use an ACE %
	              %file right now.")
	    error_handler.print_as_warning
	    from
	       !!rename_se.make
	    until
	       tmp_file_read.end_of_input
	    loop
	       tmp_file_read.read_word
	       full_name := tmp_file_read.last_string.twin
	       tmp_file_read.read_word
	       short_name := tmp_file_read.last_string.twin
	       if short_name.is_empty then
		  echo.w_put_string("Each line in %"rename.se%" files %
				     %need exactly two names.%N")
		  die_with_code(exit_failure_code)
	       end
	       clash := ace.rename_se_clash(full_name)
	       if clash /= Void  then
		  echo.w_put_string("Multiple entry for %"")
		  echo.w_put_string(full_name)
		  echo.w_put_string("%" in %"rename.se%" files.%N%
				    %Clash for %N%"")
		  echo.w_put_string(short_name)
		  echo.w_put_string("%" and %N%"")
		  echo.w_put_string(clash)
		  echo.w_put_string(".%N")
		  die_with_code(exit_failure_code)
	       end
	       rename_se.put(short_name,full_name)
	       tmp_file_read.skip_separators
	    end
	    tmp_file_read.disconnect
	 end
      end

feature {CLUSTER_VISITOR}

   name: STRING

   directory_path: STRING

   is_from_config: BOOLEAN

feature {NONE}

   rename_se: DICTIONARY[STRING,STRING]
	 -- To handle the old "rename.se" files style.

   default_assertion_level: INTEGER
	 -- The default one for this cluster.

   default_trace: CHARACTER
	 -- The default trace selection for this cluster ('%U'|'y'|'n').

   default_trace_or_ace_default_trace: BOOLEAN is
	 -- If any, gives the default trace of this `Current' cluster
	 -- otherwise the `default_trace' of `ace'.
      do
	 inspect
	    default_trace
	 when '%U' then
	    Result := ace.default_trace
	 when 'y' then
	    Result := True
	 when 'n' then
	 end
      end

   default_debug_keys: FIXED_ARRAY[STRING]
	 -- The default(s) one for this cluster.

   option_assertion_level: DICTIONARY[INTEGER,CLASS_NAME]

   option_debug_keys: DICTIONARY[FIXED_ARRAY[STRING],CLASS_NAME]

   option_trace: SET[CLASS_NAME]

   compute_directory_path_using(path: STRING; from_config: BOOLEAN) is
      require
	 path /= Void
      local
	 buffer: STRING
      do
	 --check -- To save the `string_aliaser' memory:
	 --   path /= string_aliaser.item(path)
	 --end
	 buffer := path_buffer
	 buffer.copy(path)
	 system_tools.cluster_path(buffer)
	 directory_path := string_aliaser.item(buffer)
         is_from_config := from_config
      ensure
	 directory_path = string_aliaser.item(directory_path)
      end

   parser_buffer_load: BOOLEAN is
      do
	 if directory_path.is_empty then
	    path_buffer.copy(file_name_buffer)
	 else
	    path_buffer.copy(directory_path)
	    system_tools.file_path(path_buffer,file_name_buffer)
	 end
	 parser_buffer.load_file(path_buffer)
	 Result := parser_buffer.is_ready
	 if Result then
	    parser_buffer.set_cluster(Current)
	 end
      end

   match_debug_keys(e_debug: E_DEBUG; list: FIXED_ARRAY[STRING]): BOOLEAN is
      local
	 key: STRING; i: INTEGER
      do
	 from
	    i := list.upper
	 until
	    Result or else i < list.lower
	 loop
	    key := list.item(i)
	    if key = fz_yes then
	       Result := True
	    elseif key = fz_no then
	       i := list.lower
	    else
	       Result := e_debug.match_debug_key(key)
	    end
	    i := i - 1
	 end
      end

   file_name_buffer: STRING is
	 -- Temporary buffer to store some file name like eg. "array.e".
      once
	 !!Result.make(64)
      end

   path_buffer: STRING is
	 -- Temporary buffer to store some file path like eg.
	 -- "../lib/kernel/array.e".
      once
         !!Result.make(256)
      end

   include_list: FIXED_ARRAY[STRING]

   exclude_list: FIXED_ARRAY[STRING]

end -- CLUSTER