/[eiffelstudio]/branches/CAT_mono/Src/Eiffel/interface/new_graphical/text_window/text/autocomplete/eb_class_info_analyzer.e
ViewVC logotype

Contents of /branches/CAT_mono/Src/Eiffel/interface/new_graphical/text_window/text/autocomplete/eb_class_info_analyzer.e

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69868 - (show annotations)
Fri Aug 3 22:28:26 2007 UTC (12 years, 4 months ago) by martins
File size: 66609 byte(s)
enabled more types to store monomorph information
1 indexing
2 description: "Objects that analyze class text to make it clickable and allow automatic completion"
3 legal: "See notice at end of class."
4 status: "See notice at end of class."
5 author: "Etienne Amodeo"
6 date: "$Date$"
7 revision: "$Revision$"
8
9 deferred class
10 EB_CLASS_INFO_ANALYZER
11
12 inherit
13 ANY
14
15 COMPILER_EXPORTER
16 export
17 {NONE} all
18 end
19
20 SHARED_WORKBENCH
21 export
22 {NONE} all
23 end
24
25 SHARED_TMP_SERVER
26 export
27 {NONE} all
28 end
29
30 SHARED_INST_CONTEXT
31 export
32 {NONE} all
33 end
34
35 SHARED_STATELESS_VISITOR
36 export
37 {NONE} all
38 end
39
40 PREFIX_INFIX_NAMES
41 export
42 {NONE} all
43 end
44
45 SHARED_ERROR_HANDLER
46 export
47 {NONE} all
48 end
49
50 EB_TOKEN_TOOLKIT
51 export
52 {NONE} all
53 end
54
55 SHARED_NAMES_HEAP
56 export
57 {NONE} all
58 end
59
60 feature -- Access
61
62 group: CONF_GROUP
63 -- Group which contains analyzed class
64
65 content: CLICKABLE_TEXT
66 -- text currently displayed
67
68 current_class_as: CLASS_AS
69 -- CLASS_AS object corresponding to the edited class text
70
71 last_syntax_error: SYNTAX_ERROR
72 -- last syntax error (found by generate_ast)
73
74 feature -- Status report
75
76 can_analyze_current_class: BOOLEAN
77 -- can current class text be analyzed ?
78
79 is_ready: BOOLEAN
80 -- is the analysis completed ?
81
82 feature -- Basic operations
83
84 stone_at_position (cursor: TEXT_CURSOR): STONE is
85 -- Return stone associated with position pointed by `cursor', if any
86 require
87 cursor_not_void: cursor /= Void
88 deferred
89 end
90
91 feature -- Element change
92
93 clear_syntax_error is
94 -- wipe out `last_syntax_error'
95 do
96 last_syntax_error := Void
97 end
98
99 feature -- Analysis preparation
100
101 update is
102 deferred
103 end
104
105 feature -- Reinitialization
106
107 reset is
108 -- set class attributes to default values
109 do
110 current_class_i := Void
111 current_class_c := Void
112 --if Workbench.system_defined then
113 -- System.set_current_class (Void)
114 --end
115 group := Void
116 content := Void
117 is_ready := False
118 pos_in_file := 1
119 end
120
121 reset_after_search is
122 -- set attributes related to search to default values
123 do
124 error := False
125 current_token := Void
126 searched_token := Void
127 current_line := Void
128 searched_line := Void
129 --if Workbench.system_defined then
130 -- System.set_current_class (Void)
131 --end
132 current_feature_as := Void
133 found_class := Void
134 end
135
136 feature {NONE} -- Private Access
137
138 pos_in_file: INTEGER
139 -- position in file of processed_token
140
141 searched_token: EDITOR_TOKEN
142 -- token which was clicked or which is to be completed
143
144 searched_line: EDITOR_LINE
145 -- line containing `searched_token'
146
147 current_feature_as: TUPLE [feat_as: FEATURE_AS; name: FEATURE_NAME]
148 -- `FEATURE_AS/FEATURE_NAME' corresponding to the feature containing `searched_token'
149
150 is_for_feature: BOOLEAN
151 -- Is current type/feature searching for a feature?
152
153 feature {EB_ADDRESS_MANAGER} -- Private Access
154
155 current_token: EDITOR_TOKEN
156 -- token being analyzed
157
158 current_line: EDITOR_LINE
159 -- line containing `current_token'
160
161 feature {NONE} -- Private Status
162
163 error: BOOLEAN
164 -- did an error occur ?
165
166 found_precursor: BOOLEAN
167 -- Was auto-complete called after "Precursor {CLASS}"?
168
169 is_create: BOOLEAN
170 -- was auto-complete called after "create" ?
171
172 feature {NONE} -- Click ast exploration
173
174 clickable_position_list: ARRAY [EB_CLICKABLE_POSITION]
175 -- list of clickable positions
176
177 make_click_list_from_ast is
178 -- build the click list from information in the CLASS_C object.
179 local
180 pos, i, j, pos_in_txt, c: INTEGER
181 a_click_ast: CLICK_AST
182 clickable: CLICKABLE_AST
183 l_precursor: PRECURSOR_AS
184 clickable_position: EB_CLICKABLE_POSITION
185 ast_list: CLICK_LIST
186 a_class: CLASS_I
187 prov_list: LINKED_LIST [EB_CLICKABLE_POSITION]
188 f_name: FEATURE_NAME
189 inherit_clauses: SORTABLE_ARRAY [INTEGER]
190 parents: EIFFEL_LIST [PARENT_AS]
191 class_name: STRING
192 has_parents: BOOLEAN
193 do
194 if is_ok_for_completion then
195 initialize_context
196 if current_class_i /= Void then
197 parents := current_class_as.parents
198 has_parents := parents /= Void
199 if has_parents then
200 create inherit_clauses.make (1, parents.count + 1)
201 from
202 parents.start
203 i := 1
204 until
205 parents.after
206 loop
207 inherit_clauses.put (parents.item.start_position, i)
208 parents.forth
209 i := i + 1
210 end
211 inherit_clauses.put (current_class_as.inherit_clause_insert_position, i)
212 inherit_clauses.sort
213 end
214 ast_list := current_class_as.click_list
215 if ast_list /= Void then
216 c := ast_list.count
217 create prov_list.make
218 from
219 pos := 1
220 until
221 pos > c
222 loop
223 a_click_ast := ast_list.i_th (pos)
224 clickable := a_click_ast.node
225 if clickable.is_class or else clickable.is_precursor then
226 a_class := clickable_info.associated_eiffel_class (current_class_i, clickable)
227 if a_class /= Void then
228 create clickable_position.make (a_click_ast.start_position, a_click_ast.end_position)
229 if clickable.is_class then
230 clickable_position.set_class (clickable.class_name.name)
231 else
232 l_precursor ?= clickable
233 check l_precursor_not_void: l_precursor /= Void end
234 clickable_position.set_class (l_precursor.parent_base_class.class_name.name)
235 end
236 prov_list.extend (clickable_position)
237 end
238 elseif clickable.is_feature then
239 f_name ?= clickable
240 class_name := Void
241 if f_name /= Void and has_parents then
242 pos_in_txt := a_click_ast.start_position
243 if pos_in_txt < inherit_clauses @ i then
244 from
245 j := 1
246 until
247 j = i or else pos_in_txt < inherit_clauses @ j
248 loop
249 j := j + 1
250 end
251 if j /= 1 and then pos_in_txt < inherit_clauses @ j then
252 a_class := clickable_info.
253 associated_eiffel_class (current_class_i, parents.i_th (j - 1).type)
254 if a_class /= Void then
255 class_name := a_class.name
256 else
257 class_name := Void
258 end
259 end
260 end
261 end
262 if class_name = Void then
263 class_name := current_class_i.name
264 end
265 create clickable_position.make (a_click_ast.start_position, a_click_ast.end_position)
266 clickable_position.set_feature (class_name, clickable.feature_name.name)
267 prov_list.extend (clickable_position)
268 end
269 pos := pos + 1
270 end
271 end
272 create clickable_position_list.make (1, prov_list.count)
273 from
274 prov_list.start
275 pos := 1
276 until
277 prov_list.after
278 loop
279 clickable_position_list.put (prov_list.item, pos)
280 pos := pos + 1
281 prov_list.forth
282 end
283 end
284 end
285 end
286
287 generate_ast (c: CLASS_C; after_save: BOOLEAN) is
288 -- Parse the text of the class `c'. Return True if could parse successfully,
289 -- False otherwise
290 require
291 c_not_void: c /= Void
292 local
293 l_eiffel_class: EIFFEL_CLASS_C
294 do
295 if not c.is_precompiled and c.file_is_readable then
296 l_eiffel_class ?= c
297 check l_eiffel_class_not_void: l_eiffel_class /= Void end
298 current_class_as := l_eiffel_class.parsed_ast (after_save)
299 if current_class_as = Void then
300 -- If a syntax error ocurred, we retrieve the old ast.
301 current_class_as := c.ast
302 end
303 else
304 -- Class is precompiled, we should not reparse it since its definition
305 -- is frozen for the compiler.
306 current_class_as := c.ast
307 end
308 end
309
310 feature {NONE}-- Clickable/Editable implementation
311
312 stone_in_click_ast (a_position: INTEGER): STONE is
313 -- search in the click_ast for a stone to associate with `a_position' in text
314 require
315 group_not_void: group /= Void
316 group_is_valid: group.is_valid
317 local
318 index_min, index_max, middle: INTEGER
319 position: INTEGER
320 click_pos: EB_CLICKABLE_POSITION
321 class_i: CLASS_I
322 feat: E_FEATURE
323 do
324 if clickable_position_list /= Void then
325 index_min := 1
326 index_max := clickable_position_list.count
327 if a_position >= (clickable_position_list @ 1).start then
328 -- search in the list
329 if a_position >= (clickable_position_list @ index_max).start then
330 index_min := index_max
331 else
332 from
333
334 until
335 index_min >= index_max - 1
336 loop
337 middle := index_min + (index_max - index_min) // 2
338 position := (clickable_position_list @ middle).start
339 if position > a_position then
340 index_max := middle
341 else
342 index_min := middle
343 end
344 end
345 end
346 click_pos := clickable_position_list @ index_min
347 if a_position <= click_pos.stop then
348 if click_pos.is_feature then
349 class_i := Universe.safe_class_named (click_pos.class_name, group)
350 if class_i /= Void and then class_i.is_compiled and then class_i.compiled_class.has_feature_table then
351 feat := class_i.compiled_class.feature_with_name (click_pos.feature_name)
352 if feat /= Void then
353 create {FEATURE_STONE} Result.make (feat)
354 end
355 end
356 elseif click_pos.is_class then
357 class_i := Universe.safe_class_named (click_pos.class_name, group)
358 if class_i /= Void then
359 if class_i.is_compiled then
360 create {CLASSC_STONE} Result.make (class_i.compiled_class)
361 else
362 create {CLASSI_STONE} Result.make (class_i)
363 end
364 end
365 end
366 end
367 end
368 end
369 end
370
371 described_feature (token: EDITOR_TOKEN; line: EDITOR_LINE; ft: FEATURE_AS): E_FEATURE is
372 -- search in feature represented by `ft' the feature associated with `token' if any
373 require
374 token_not_void: token /= Void
375 line_not_void: line /= Void
376 token_in_line: line.has_token (token)
377 local
378 l_type: TYPE_A
379 do
380 if is_ok_for_completion then
381 initialize_context
382 if current_class_c /= Void then
383 if not token_image_is_in_array (token, unwanted_symbols) then
384 if ft /= Void then
385 current_feature_as := [ft, ft.feature_names.first]
386 else
387 current_feature_as := Void
388 end
389 error := False
390 last_was_constrained := False
391 last_feature := Void
392 is_for_feature := True
393 l_type := type_from (token, line)
394 is_for_feature := False
395 Result := last_feature
396 end
397 end
398 end
399 end
400
401 last_feature: E_FEATURE
402 -- Last feature found for PnD.
403
404 feature {NONE} -- Implementation (`type_from')
405
406 type_from (token: EDITOR_TOKEN; line: EDITOR_LINE): TYPE_A is
407 -- try to analyze class text to find type associated with word represented by `token'
408 require
409 token_not_void: token /= Void
410 line_not_void: line /= Void
411 token_in_line: line.has_token (token)
412 current_class_c_not_void: current_class_c /= Void
413 do
414 current_token := token
415 searched_token := token
416 current_line := line
417 searched_line := line
418 error := False
419 find_expression_start
420 if not error then
421 Result := searched_type
422 end
423 end
424
425 searched_type: TYPE_A is
426 -- analyze class text from `current_token' to find type associated with `searched_token'
427 require
428 current_class_i_not_void: current_class_i /= Void
429 current_class_c_not_void: current_class_c /= Void
430 local
431 exp: LINKED_LIST [EDITOR_TOKEN]
432 name: STRING
433 par_cnt: INTEGER
434 type: TYPE_A
435 feat: E_FEATURE
436 l_current_class_c: CLASS_C
437 l_precursor_from: TYPE_A
438 do
439 from
440 last_constraints := Void
441 last_target_type := Void
442 last_formal := Void
443 last_was_constrained := False
444 last_was_multi_constrained := False
445 l_current_class_c := current_class_c
446 written_class := current_class_c
447 type := l_current_class_c.actual_type
448 if token_image_is_same_as_word (current_token, "create") then
449 go_to_next_token
450 is_create := True
451 error := not token_image_is_same_as_word (current_token, opening_brace)
452 if not error then
453 go_to_next_token
454 error := current_token = Void
455 if not error then
456 type := type_of_class_corresponding_to_current_token
457 skip_parenthesis (opening_brace, closing_brace)
458 end
459 end
460 elseif token_image_is_same_as_word (current_token, opening_brace) then
461 -- Static call {CLASS}.abc.abc
462 go_to_next_token
463 error := error or else current_token = Void
464 if not error then
465 type := type_of_class_corresponding_to_current_token
466 skip_parenthesis (opening_brace, closing_brace)
467 end
468 elseif token_image_is_same_as_word (current_token, opening_parenthesis) then
469 -- if we find a closing parenthesis, we go directly to the corresponding
470 -- opening parenthesis
471 par_cnt:= 1
472 from
473 create exp.make
474 until
475 par_cnt = 0 or else current_token = Void
476 loop
477 go_to_next_token
478 exp.extend (current_token)
479 if token_image_is_same_as_word (current_token, closing_parenthesis) then
480 par_cnt:= par_cnt - 1
481 elseif token_image_is_same_as_word (current_token, opening_parenthesis) then
482 par_cnt:= par_cnt + 1
483 end
484 end
485 if current_token = Void then
486 error := True
487 else
488 if exp.count > 0 then
489 exp.finish
490 exp.remove
491 end
492 type := complete_expression_type (exp)
493 if type /= Void then
494 -- Fixme: some problems here, type is possible multi-constaint.
495 last_target_type := type
496 if type.has_associated_class then
497 written_class := type.associated_class
498 end
499 end
500 end
501 else
502 name := current_token.image.as_lower
503 if name.is_equal ("precursor") then
504 go_to_next_token
505 if token_image_is_same_as_word (current_token, opening_brace) then
506 go_to_next_token
507 error := error or else current_token = Void
508 if not error then
509 l_precursor_from := type_of_class_corresponding_to_current_token
510 skip_parenthesis (opening_brace, closing_brace)
511 if l_precursor_from /= Void then
512 -- Precursor {CLASS}: Result.associated_class /= Void
513 check
514 has_associated_class: l_precursor_from.has_associated_class
515 end
516 written_class := l_precursor_from.associated_class
517 if l_precursor_from.associated_class.has_feature_table then
518 feat := l_precursor_from.associated_class.feature_with_name (current_feature_as.name.internal_name.name)
519 end
520 end
521 end
522 else
523 go_to_previous_token
524 if current_feature_as /= Void and then l_current_class_c.parents /= Void then
525 from
526 l_current_class_c.parents.start
527 until
528 feat /= Void or else l_current_class_c.parents.after
529 loop
530 l_precursor_from := l_current_class_c.parents.item
531 check
532 type_as_associated_class: type.has_associated_class
533 end
534 if type.associated_class.has_feature_table then
535 feat := l_precursor_from.associated_class.feature_with_name (current_feature_as.name.internal_name.name)
536 written_class := l_precursor_from.associated_class
537 end
538 l_current_class_c.parents.forth
539 end
540 end
541 end
542 else
543 if l_current_class_c.has_feature_table then
544 feat := l_current_class_c.feature_with_name (name)
545 end
546 is_create := create_before_position (current_line, current_token)
547 end
548 if feat = Void then
549 -- Could not find feature, may be a local or argument
550 type := type_of_local_entity_named (name)
551 if type = Void then
552 type := type_of_constants_or_reserved_word (current_token)
553 end
554 else
555 -- Found feature
556 error := False
557 type := feat.type
558 end
559 end
560 go_to_next_token
561 if not error and then token_image_is_same_as_word (current_token, opening_parenthesis) then
562 skip_parenthesis (opening_parenthesis, closing_parenthesis)
563 go_to_next_token
564 end
565 -- Here I go away from the `Result' to other variables, they are:
566 -- `last_constraints' and `last_target_type'
567 -- (I think it's better to use variable names with a comment as we somehow split up the paths.
568 -- Using Result for the one case and `last_constraints' for mc is one possiblity. But it is asymetric.
569 -- In each iteration we may meet multi constrained formals, in such a case
570 -- `last_constraints' is used. `last_constraints' does _not_ contain any formals nor other typesets.
571 -- Otherwise `last_target_type' is used.
572 if type /= Void then
573 if last_target_type /= Void then
574 move_to_next_target (type, last_target_type, written_class)
575 elseif last_constraints /= Void then
576 move_to_next_target (type, last_constraints, written_class)
577 else
578 move_to_next_target (type, current_class_c.actual_type, written_class)
579 end
580 end
581 if not error and then token_image_is_same_as_word (current_token, opening_bracket) then
582 skip_parenthesis (opening_bracket, closing_bracket)
583 go_to_next_token
584 type := process_bracket_type
585 if not error and then type /= Void then
586 -- `written_class' has been set when `process_bracket_type'
587 check
588 written_class /= Void
589 end
590 if last_target_type /= Void then
591 move_to_next_target (type, last_target_type, written_class)
592 elseif last_constraints /= Void then
593 move_to_next_target (type, last_constraints, written_class)
594 end
595 end
596 end
597 if not error then
598 if after_searched_token then
599 error := type = Void
600 else
601 error := type = Void or else not token_image_is_in_array (current_token, feature_call_separators)
602 go_to_next_token
603 end
604 end
605 last_feature := feat
606 until
607 error or else after_searched_token
608 loop
609 name := current_token.image.as_lower
610
611 type := internal_type_from_name (name)
612
613 -- Prepare for the next round
614 if type /= Void then
615 -- In case we have a formal type we will:
616 -- * compute the flat version (without formals) of the constraints and store it in `last_constraints'
617 -- In case we have an any other type (including an anchored) we will:
618 -- * instantiate it and make it available in `last_target_type' right away.
619 move_to_next_target (type, last_type, written_class)
620 else
621 error := True
622 end
623
624 go_to_next_token
625 if token_image_is_same_as_word (current_token, opening_parenthesis) then
626 skip_parenthesis (opening_parenthesis, closing_parenthesis)
627 go_to_next_token
628 end
629 if not error and then token_image_is_same_as_word (current_token, opening_bracket) then
630 skip_parenthesis (opening_bracket, closing_bracket)
631 go_to_next_token
632 type := process_bracket_type
633 if not error and then type /= Void then
634 check
635 written_class /= Void
636 end
637 move_to_next_target (type, last_type, written_class)
638 end
639 end
640 error := error or else not (after_searched_token or else token_image_is_same_as_word (current_token, "."))
641 is_create := is_create and then after_searched_token
642 go_to_next_token
643 end
644 if error then
645 Result := Void
646 else
647 if last_target_type /= Void then
648 -- ordinary: one type, one class
649 Result := last_target_type
650 else
651 -- multi constraint: several classes provide features
652 Result := last_constraints
653 end
654 end
655 end
656
657 internal_type_from_name (a_name: STRING): TYPE_A is
658 --
659 require
660 a_name_not_void: a_name /= Void
661 local
662 l_feature_state: TUPLE [feature_item: E_FEATURE; class_type_of_feature: CL_TYPE_A; features_found_count: INTEGER; constraint_position: INTEGER]
663 feat: E_FEATURE
664 type: TYPE_A
665 l_pos: INTEGER
666 l_named_tuple_type: NAMED_TUPLE_TYPE_A
667 l_processed_class: CLASS_C
668 do
669 if last_was_multi_constrained then
670 -- We're in the multi constraint case.
671 -- We have the constraining type set `last_constraints' and a feature name `a_name'.
672 -- The objective is to compute `last_target_type' and to get a `E_FEATURE' instance
673 -- of the feature named `a_name' and store it in `feat'.
674 check last_target_type_not_known: last_target_type = Void end
675 l_feature_state := last_constraints.e_feature_state_by_name (a_name)
676 if l_feature_state.features_found_count = 0 then
677 -- There's no feature with the name `a_name' in the type set.
678 feat := Void
679 elseif l_feature_state.features_found_count = 1 then
680 -- We found exactly one feautre, this is good.
681 -- Let's store the class type to which the feature belongs into `last_target_type'.
682 feat := l_feature_state.feature_item
683 last_target_type := l_feature_state.class_type_of_feature
684 written_class := last_target_type.associated_class
685 else
686 -- We don't provide a list, since the code doesn't compile already.
687 feat := Void
688 end
689 if feat /= Void and then feat.type /= Void then
690 type := feat.type
691 else
692 type := Void
693 end
694 else
695 check
696 Result_has_associated_class: last_target_type.has_associated_class
697 end
698 l_named_tuple_type ?= last_target_type
699 l_processed_class := last_target_type.associated_class
700 written_class := l_processed_class
701 if l_processed_class /= Void and then l_processed_class.has_feature_table or l_named_tuple_type /= Void then
702 type := Void
703 if l_named_tuple_type /= Void then
704 l_pos := l_named_tuple_type.label_position (a_name)
705 if l_pos > 0 then
706 type := l_named_tuple_type.generics.item (l_pos)
707 end
708 if type = Void then
709 feat := l_processed_class.feature_with_name (a_name)
710 if feat /= Void then
711 type := feat.type
712 end
713 end
714 else
715 feat := l_processed_class.feature_with_name (a_name)
716 if feat = Void and then last_was_constrained and then not last_formal.is_single_constraint_without_renaming (current_class_c) then
717 -- Renamed in constaint clause?
718 feat := feature_of_constaint_renamed (last_formal, a_name)
719 end
720 if feat /= Void then
721 type := feat.type
722 end
723 end
724 end
725 end
726 last_feature := feat
727 Result := type
728 end
729
730 move_to_next_target (a_type, a_parent_type: TYPE_A; a_class: CLASS_C) is
731 -- Makes the transition from `a_parent_type' to `a_type'.
732 -- It binds a loose type and computes the proper constraints for formals.
733 -- if you have `l_a.f.g', `l_a's type would be `a_parent type' and `f's type would be `a_type'.
734 --
735 -- `a_type' is a possible loose type (`is_lose')
736 --| Non-loose types are not affected.
737 require
738 a_type_not_void: a_type /= Void
739 a_class_not_void: a_class /= Void
740 local
741 l_class: CLASS_C
742 l_is_named_tuple: BOOLEAN
743 do
744 l_is_named_tuple := a_parent_type.is_named_tuple
745 l_class := current_class_c
746 if a_type.is_loose then
747 if l_is_named_tuple then
748 last_target_type := a_type.actual_type.instantiation_in (a_type, a_class.class_id)
749 else
750 last_target_type := a_type.actual_type.instantiation_in (a_parent_type, a_class.class_id)
751 end
752 last_type := last_target_type
753 if last_target_type /= Void then
754 last_target_type := last_target_type.actual_type
755 last_was_constrained := last_target_type.is_formal
756 last_formal ?= last_target_type
757 if last_was_constrained then
758 last_was_multi_constrained := not last_formal.is_single_constraint_without_renaming (l_class)
759 if last_was_multi_constrained then
760 -- We're in the multi constraint case, let's compute a flat version (without formals) of all constraints.
761 last_constraints := last_formal.constraints (l_class).constraining_types_if_possible (l_class)
762 -- We don't know yet the real target type (it'll be one out of last_constraints)
763 last_target_type := Void
764 else
765 last_target_type := last_formal.constrained_type (l_class)
766 end
767 end
768 error := False
769 end
770 else
771 -- Non formal status.
772 if not a_parent_type.is_tuple then
773 last_target_type := a_type.actual_type.instantiation_in (a_parent_type, a_class.class_id)
774 else
775 last_target_type := a_type
776 end
777
778 last_type := last_target_type
779 last_was_multi_constrained := False
780 last_was_constrained := False
781 error := False
782 end
783 end
784
785 create_before_position (a_line: EDITOR_LINE; a_token: EDITOR_TOKEN): BOOLEAN is
786 -- is "create" preceeding current position ?
787 local
788 line: EDITOR_LINE
789 token: EDITOR_TOKEN
790 par_cnt: INTEGER
791 do
792 line := current_line
793 current_line := a_line
794 token := current_token
795 current_token := a_token
796 if not token_image_is_same_as_word (current_token, closing_brace) then
797 go_to_previous_token
798 end
799 Result := token_image_is_same_as_word (current_token, Create_word)
800 if not Result and then token_image_is_same_as_word (current_token, closing_brace) then
801 from
802 par_cnt := 1
803 until
804 par_cnt = 0 or else current_token = Void
805 loop
806 go_to_previous_token
807 if token_image_is_same_as_word (current_token, Opening_brace) then
808 par_cnt:= par_cnt - 1
809 elseif token_image_is_same_as_word (current_token, Closing_brace) then
810 par_cnt:= par_cnt + 1
811 end
812 end
813 go_to_next_token
814 error := error or else current_token = Void or else type_of_class_corresponding_to_current_token = Void
815 if not error then
816 go_to_previous_token
817 go_to_previous_token
818 Result := token_image_is_same_as_word (current_token, Create_word)
819 end
820 end
821 current_token := token
822 current_line := line
823 end
824
825 process_bracket_type: TYPE_A
826 -- Process when encountering brackets.
827 require
828 a_process_type_not_void: written_class /= Void
829 local
830 type: TYPE_A
831 l_feature: FEATURE_I
832 l_class: CLASS_C
833 l_type_set_a: TYPE_SET_A
834 l_list: LIST [CLASS_C]
835 do
836 if last_was_multi_constrained then
837 -- We're in the multi constraint case.
838 -- We have the constraining type set `last_constraints' and a feature name `a_name'.
839 -- The objective is to compute `last_target_type' and to get a `E_FEATURE' instance
840 -- of the feature named `a_name' and store it in `feat'.
841 check last_target_type_not_known: last_target_type = Void end
842 l_type_set_a := last_constraints.constraining_types (written_class)
843 l_list := l_type_set_a.associated_classes
844 from
845 l_list.start
846 until
847 l_list.after or else l_feature /= Void
848 loop
849 l_class := l_list.item
850 if l_class.has_feature_table then
851 l_feature := l_class.feature_table.alias_item (bracket_str)
852 written_class := l_class
853 end
854 l_list.forth
855 end
856 else
857 check
858 has_associated_class: last_target_type /= Void and then last_target_type.has_associated_class
859 end
860 if last_target_type.associated_class.has_feature_table then
861 l_feature := last_target_type.associated_class.feature_table.alias_item (bracket_str)
862 written_class := last_target_type.associated_class
863 end
864 end
865 if l_feature /= Void then
866 error := error or False
867 type := l_feature.type
868 else
869 error := True
870 written_class := Void
871 end
872 -- Bracket feature is never used by PnD, we ignore it.
873 last_feature := Void
874 Result := type
875 ensure
876 Result_not_void_implies_processed_class_not_void: Result /= Void implies written_class /= Void
877 end
878
879 feature_of_constaint_renamed (a_formal: FORMAL_A; a_new_name: STRING): E_FEATURE is
880 -- Constaint renamed feature of current class.
881 require
882 a_formal_not_void: a_formal /= Void
883 a_new_name_not_void: a_new_name /= Void
884 current_class_c_not_void: current_class_c /= Void
885 local
886 l_renames: ARRAY [RENAMING_A]
887 l_renaming: RENAMING_A
888 i, upper, l_new_name_id, l_old_name_id: INTEGER
889 do
890 l_new_name_id := names_heap.id_of (a_new_name)
891 l_renames := current_class_c.constraint_renaming (current_class_c.generics.i_th (last_formal.position))
892 from
893 i := l_renames.lower
894 upper := l_renames.upper
895 until
896 i > upper or Result /= Void
897 loop
898 l_renaming := l_renames.item (i)
899 if l_renaming /= Void then
900 l_old_name_id := l_renaming.item (l_new_name_id)
901 if l_old_name_id > 0 then
902 Result := current_class_c.feature_with_name_id (l_old_name_id)
903 end
904 end
905 i := i + 1
906 end
907 end
908
909 written_class: CLASS_C
910
911 last_type : TYPE_A
912 -- Last type stores for `searched_type'.
913
914 feature {NONE}-- Implementation
915
916 feature_part_at (a_token: EDITOR_TOKEN; a_line: EDITOR_LINE): INTEGER is
917 -- find in which part of the feature body `a_token' is
918 local
919 found: BOOLEAN
920 token: EDITOR_TOKEN
921 line: EDITOR_LINE
922 do
923 Result := no_interesting_part
924 from
925 token := a_token
926 line := a_line
927 until
928 token = Void or found
929 loop
930 if is_keyword (token) then
931 if token_image_is_in_array (token, feature_body_keywords) then
932 found := True
933 if token_image_is_in_array (token, feature_contract_keywords) then
934 Result := assertion_part
935 elseif token_image_is_in_array (token, feature_executable_keywords) then
936 Result := instruction_part
937 elseif token_image_is_in_array (token, feature_local_keywords) then
938 Result := local_part
939 end
940 end
941 end
942 if token = line.first_token then
943 if line.previous = Void then
944 token := Void
945 else
946 line := line.previous
947 token := line.eol_token
948 end
949 else
950 token := token.previous
951 end
952 end
953 end
954
955 assertion_part: INTEGER is 1
956
957 instruction_part: INTEGER is 2
958
959 local_part: INTEGER is 3
960
961 no_interesting_part: INTEGER is 4
962
963 find_expression_start is
964 -- find where to begin the analysis (set current_token/line)
965 local
966 par_cnt: INTEGER
967 stop: BOOLEAN
968 l_token : EDITOR_TOKEN
969 l_line: EDITOR_LINE
970 do
971 if token_image_is_same_as_word (current_token, closing_bracket) then
972 go_to_previous_token
973 skip_parenthesis_backward (opening_bracket, closing_bracket)
974 go_to_previous_token
975 if token_image_is_same_as_word (current_token, closing_brace) then
976 -- Precursor {CLASS} [i].
977 go_to_previous_token
978 skip_parenthesis_backward (opening_brace, closing_brace)
979 go_to_previous_token
980 end
981 end
982 if found_precursor then
983 -- Precursor {CLASS}.
984 if token_image_is_same_as_word (current_token, closing_brace) then
985 go_to_previous_token
986 skip_parenthesis_backward (opening_brace, closing_brace)
987 go_to_previous_token
988 end
989 end
990 go_to_previous_token
991 if current_token /= Void then
992 if
993 -- not the "~feature" case
994 current_token.image.is_empty
995 or else
996 current_token.image @ 1 /= '%L'
997 or else
998 not is_beginning_of_expression (current_token.previous)
999 then
1000 from
1001 until
1002 error or stop or else not token_image_is_in_array (current_token, feature_call_separators)
1003 loop
1004 go_to_previous_token
1005 stop := False
1006 if token_image_is_same_as_word (current_token, Closing_parenthesis) then
1007 -- if we find a closing parenthesis, we go directly to the corresponding
1008 -- opening parenthesis
1009 go_to_previous_token
1010 skip_parenthesis_backward (opening_parenthesis, closing_parenthesis)
1011 error := current_token = Void
1012 -- we reached the closing parenthesis
1013 -- we go back one token further if parenthesis seem to be arguments
1014 go_to_previous_token
1015 stop := token_image_is_in_array (current_token, closing_separators) or else
1016 token_image_is_in_array (current_token, parenthesis) or else
1017 (is_keyword (current_token) and then not token_image_is_in_array (current_token, special_keywords))
1018 end
1019 if token_image_is_same_as_word (current_token, closing_bracket) then
1020 -- if we find a closing parenthesis, we go directly to the corresponding
1021 -- opening parenthesis
1022 go_to_previous_token
1023 skip_parenthesis_backward (opening_bracket, closing_bracket)
1024 error := current_token = Void
1025 -- we reached the closing parenthesis
1026 -- we go back one token further if parenthesis seem to be arguments
1027 go_to_previous_token
1028 stop := token_image_is_in_array (current_token, closing_separators) or else
1029 token_image_is_in_array (current_token, parenthesis) or else
1030 (is_keyword (current_token) and then not token_image_is_in_array (current_token, special_keywords))
1031 end
1032 if not stop then
1033 -- Try to find create {CLASS}Result.make
1034 go_to_previous_token
1035 if not token_image_is_same_as_word (current_token, Closing_brace) then
1036 go_to_next_token
1037 end
1038 -- special case with "create" and "Precursor"
1039 if token_image_is_same_as_word (current_token, Closing_brace) then
1040 from
1041 par_cnt:= - 1
1042 until
1043 par_cnt = 0 or else current_token = Void
1044 loop
1045 go_to_previous_token
1046 if token_image_is_same_as_word (current_token, Closing_brace) then
1047 par_cnt:= par_cnt - 1
1048 elseif token_image_is_same_as_word (current_token, Opening_brace) then
1049 par_cnt:= par_cnt + 1
1050 end
1051 end
1052 l_token := current_token
1053 l_line := current_line
1054
1055 go_to_previous_token
1056
1057 if current_token = Void then
1058 error := True
1059 else
1060 if not token_image_is_in_array (current_token, special_keywords) then
1061 current_token := l_token
1062 current_line := l_line
1063 end
1064 end
1065 end
1066 go_to_previous_token
1067 end
1068 end
1069 end
1070 -- loop stopped : we went one token too far
1071 go_to_next_token
1072 end
1073 error := current_token = Void or else error
1074 end
1075
1076 complete_expression_type (exp: LINKED_LIST[EDITOR_TOKEN]): TYPE_A is
1077 -- analyze expression represented by list of token `exp'
1078 require
1079 exp_not_void: exp /= Void
1080 current_class_c_not_void: current_class_c /= Void
1081 local
1082 sub_exp: like exp
1083 infix_expected: BOOLEAN
1084 infix_list: ARRAYED_LIST[STRING]
1085 expression_table: ARRAYED_LIST [LINKED_LIST[EDITOR_TOKEN]]
1086 type_list: LINKED_LIST [TYPE_A]
1087 par_cnt: INTEGER
1088 stop: BOOLEAN
1089 do
1090 -- first, we check that the expression can be analyzed, i.e. there is a sequence
1091 -- sub_expression infix sub_expression ...
1092 -- we store those sub_expression in `expression_table'
1093 from
1094 exp.start
1095 create infix_list.make(0)
1096 create expression_table.make(0)
1097 until
1098 exp.after or else error
1099 loop
1100 if infix_expected then
1101 -- the infix must be in our list
1102 -- otherwise, we will not analyze this expression
1103 if is_known_infix (exp.item) then
1104 infix_list.extend (exp.item.image)
1105 else
1106 error := True
1107 end
1108 exp.forth
1109 infix_expected := False
1110 else
1111 from
1112 until
1113 exp.after or else not is_known_prefix (exp.item)
1114 loop
1115 --| FIXME ? -- as for all known prefix the returned type equals to the base type,
1116 -- we forget about them
1117 exp.forth
1118 end
1119 create sub_exp.make
1120 stop := False
1121 error := exp.after
1122 if not error then
1123 if token_image_is_same_as_word (exp.item, Opening_parenthesis) then
1124 -- if there is a parenthesis, we fill the new `sub_exp' with what's inside
1125 from
1126 par_cnt := 1
1127 sub_exp.extend (exp.item)
1128 until
1129 par_cnt = 0 or else exp.after
1130 loop
1131 exp.forth
1132 if not exp.after then
1133 sub_exp.extend (exp.item)
1134 if token_image_is_same_as_word (exp.item, Closing_parenthesis) then
1135 par_cnt := par_cnt - 1
1136 elseif token_image_is_same_as_word (exp.item, Opening_parenthesis) then
1137 par_cnt := par_cnt + 1
1138 end
1139 end
1140 end
1141 if exp.after or else sub_exp.count < 1 then
1142 error := True
1143 else
1144 exp.forth
1145 -- we now look if there is a feature call after closing parenthesis
1146 if not exp.after then
1147 if token_image_is_in_array (exp.item, feature_call_separators) then
1148 sub_exp.extend (exp.item)
1149 exp.forth
1150 if exp.after then
1151 error := True
1152 end
1153 else
1154 stop := True
1155 end
1156 end
1157 end
1158 end
1159 end
1160 from
1161
1162 until
1163 error or else exp.after or else stop
1164 loop
1165 sub_exp.extend (exp.item)
1166 exp.forth
1167 -- if it is a function, we skip the arguments
1168 -- we do not need them to knw the returned type
1169 if not exp.after then
1170 if token_image_is_same_as_word (exp.item, Opening_parenthesis) then
1171 from
1172 par_cnt := 1
1173 until
1174 par_cnt = 0 or else exp.after
1175 loop
1176 exp.forth
1177 if token_image_is_same_as_word (exp.item, Closing_parenthesis) then
1178 par_cnt := par_cnt - 1
1179 elseif token_image_is_same_as_word (exp.item, Opening_parenthesis) then
1180 par_cnt := par_cnt + 1
1181 end
1182 end
1183 if exp.after then
1184 error := True
1185 else
1186 exp.forth
1187 end
1188 end
1189 if not exp.after then
1190 if token_image_is_in_array (exp.item, feature_call_separators) then
1191 sub_exp.extend (exp.item)
1192 exp.forth
1193 if exp.after then
1194 error := True
1195 end
1196 else
1197 stop := True
1198 end
1199 end
1200 end
1201 end
1202 if not error then
1203 expression_table.extend (sub_exp)
1204 infix_expected := True
1205 end
1206 end
1207 end
1208 error := error or else not infix_expected
1209 if not error then
1210 type_list := corresponding_type_list (expression_table)
1211 if type_list /= Void then
1212 if type_list.count = 1 then
1213 Result := type_list.first
1214 elseif type_list.count = infix_list.count + 1 then
1215 Result := expression_type (type_list, infix_list)
1216 end
1217 end
1218 end
1219 end
1220
1221 expression_type (type_list: LINKED_LIST [TYPE_A]; infix_list: ARRAYED_LIST[STRING]): TYPE_A is
1222 -- find type of expression represented by the list of operands type `type_list' and list of operators `infix_list'
1223 require
1224 infix_list_not_void: infix_list /= Void
1225 type_list_not_void: type_list /= Void
1226 current_class_c_not_void: current_class_c /= Void
1227 local
1228 priority: LINKED_LIST[INTEGER]
1229 index: INTEGER
1230 do
1231 create priority.make
1232 from
1233 infix_groups.start
1234 until
1235 infix_groups.after
1236 loop
1237 infix_groups.item.compare_objects
1238 from
1239 infix_list.start
1240 until
1241 infix_list.after
1242 loop
1243 if infix_groups.item.has (infix_list.item) then
1244 priority.extend (infix_list.index)
1245 end
1246 infix_list.forth
1247 end
1248 infix_groups.forth
1249 end
1250 from
1251
1252 until
1253 error or priority.is_empty
1254 loop
1255 priority.start
1256 type_list.start
1257 index := priority.item
1258 priority.remove
1259 from
1260 priority.start
1261 until
1262 priority.after
1263 loop
1264 if priority.item > index then
1265 priority.replace(priority.item - 1)
1266 end
1267 priority.forth
1268 end
1269 type_list.go_i_th (index)
1270 infix_list.go_i_th (index)
1271 Result := type_returned_by_infix (type_list.item, infix_list.item)
1272 if Result = Void then
1273 error := True
1274 else
1275 type_list.remove
1276 type_list.replace (Result)
1277 infix_list.remove
1278 end
1279 end
1280 if error then
1281 Result := Void
1282 end
1283 end
1284
1285 corresponding_type_list (expression_table: ARRAYED_LIST [LINKED_LIST[EDITOR_TOKEN]]): LINKED_LIST [TYPE_A] is
1286 -- create list of type from a list of expression (represented by lists of tokens)
1287 require
1288 expression_table_not_void: expression_table /= Void
1289 current_class_c_not_void: current_class_c /= Void
1290 local
1291 sub_exp, recur_exp: LINKED_LIST[EDITOR_TOKEN]
1292 l_type_set: TYPE_SET_A
1293 type: TYPE_A
1294 par_cnt: INTEGER
1295 name: STRING
1296 l_processed_class: CLASS_C
1297 processed_feature: E_FEATURE
1298 formal: FORMAL_A
1299 l_current_class_c: CLASS_C
1300 do
1301 l_current_class_c := current_class_c
1302 create Result.make
1303 from
1304 expression_table.start
1305 until
1306 error or else expression_table.after
1307 loop
1308 sub_exp := expression_table.item
1309 expression_table.forth
1310 from
1311 sub_exp.start
1312 if token_image_is_same_as_word (sub_exp.item, Opening_parenthesis) then
1313 -- Arguments have not been inserted in this list.
1314 -- If there are parenthesis, it is an independent expression
1315 create recur_exp.make
1316 from
1317 par_cnt := 1
1318 until
1319 par_cnt = 0 or else sub_exp.after
1320 loop
1321 sub_exp.forth
1322 if not sub_exp.after then
1323 recur_exp.extend (sub_exp.item)
1324 if token_image_is_same_as_word (sub_exp.item, Closing_parenthesis) then
1325 par_cnt := par_cnt - 1
1326 elseif token_image_is_same_as_word (sub_exp.item, Opening_parenthesis) then
1327 par_cnt := par_cnt + 1
1328 end
1329 end
1330 end
1331 if sub_exp.after or else recur_exp.count < 1 then
1332 error := True
1333 else
1334 -- recur_exp contains the closing parenthesis. We remove it.
1335 recur_exp.finish
1336 recur_exp.remove
1337 type := complete_expression_type (recur_exp)
1338 end
1339 else
1340 -- type is Void
1341 name := sub_exp.item.image.as_lower
1342 if l_current_class_c.has_feature_table then
1343 processed_feature := l_current_class_c.feature_with_name (name)
1344 end
1345 if processed_feature /= Void then
1346 if processed_feature.type /= Void then
1347 if processed_feature.type.is_formal then
1348 formal ?= processed_feature.type
1349 type := l_current_class_c.actual_type
1350 if
1351 type /= Void and then
1352 type.has_generics and then
1353 type.generics.valid_index (formal.position)
1354 then
1355 type := type.generics @ (formal.position)
1356 error := False
1357 end
1358 else
1359 type := processed_feature.type
1360 end
1361 end
1362 else
1363 type := type_of_local_entity_named (name)
1364 if type = Void then
1365 type := type_of_constants_or_reserved_word (sub_exp.item)
1366 end
1367 end
1368 error := type = Void
1369 end
1370 sub_exp.forth
1371 until
1372 error or else sub_exp.after
1373 loop
1374 if token_image_is_in_array (sub_exp.item, feature_call_separators) then
1375 sub_exp.forth
1376 if sub_exp.after then
1377 error := True
1378 else
1379 name := sub_exp.item.image.as_lower
1380 if type.is_formal then
1381 formal ?= type
1382 if l_current_class_c.is_valid_formal_position (formal.position) then
1383 if formal.is_single_constraint_without_renaming (l_current_class_c) then
1384 type := formal.constrained_type_if_possible (l_current_class_c)
1385 else
1386 l_type_set := formal.constrained_types_if_possible (l_current_class_c)
1387 end
1388 else
1389 -- TODO: Can this case ever occur in a valid system?
1390 end
1391 end
1392 if type.has_associated_class then
1393 -- This case includes the ordinary case and the case were we had
1394 -- a single constrained formal without a renaming (constrained_type has been called).
1395 l_processed_class := type.associated_class
1396 if l_processed_class /= Void and then l_processed_class.has_feature_table then
1397 processed_feature := l_processed_class.feature_with_name (name)
1398 end
1399 else
1400 -- Maybe we computed a type set?
1401 if l_type_set /= Void then
1402 processed_feature := l_type_set.e_feature_state_by_name (name).feature_item
1403 end
1404 end
1405 -- Set to `Void' as we are in a loop.
1406 type := Void
1407 l_type_set := Void
1408 -- If we found a feature continue...
1409 if processed_feature /= Void and then processed_feature.type /= Void then
1410 if processed_feature.type.is_formal then
1411 formal ?= processed_feature.type
1412 if
1413 type /= Void and then
1414 type.has_generics and then
1415 type.generics.valid_index (formal.position)
1416 then
1417 type := type.generics @ (formal.position)
1418 end
1419 else
1420 type := processed_feature.type
1421 end
1422 end
1423 sub_exp.forth
1424 end
1425 else
1426 type := Void
1427 end
1428 error := type = Void
1429 end
1430 if not error then
1431 Result.extend (type)
1432 end
1433 end
1434 if error then
1435 Result := Void
1436 end
1437 end
1438
1439 type_of_class_corresponding_to_current_token: TYPE_A is
1440 require
1441 group_not_void: group /= Void
1442 group_is_valid: group.is_valid
1443 local
1444 cc_stone: CLASSC_STONE
1445 image: STRING
1446 class_i: CLASS_I
1447 l_token: EDITOR_TOKEN
1448 l_feat: E_FEATURE
1449 do
1450 found_class := Void
1451 cc_stone ?= stone_in_click_ast (current_token.pos_in_text)
1452 if cc_stone /= Void and then cc_stone.e_class /= Void then
1453 found_class := cc_stone.e_class
1454 Result := found_class.actual_type
1455 end
1456 if Result = Void then
1457 image := current_token.image.as_upper
1458 class_i := Universe.safe_class_named (image, group)
1459 if class_i /= Void and then class_i.is_compiled then
1460 found_class := class_i.compiled_class
1461 Result := found_class.actual_type
1462 end
1463 end
1464 if Result = Void then
1465 image := current_token.image.as_lower
1466 if image.is_equal ("like") then
1467 if current_token.next /= Void and then current_token.next.next /= Void then
1468 l_token := current_token.next.next
1469 if l_token.is_text then
1470 image := l_token.image.as_lower
1471 if current_class_c /= Void then
1472 l_feat := current_class_c.feature_with_name (image)
1473 if l_feat /= Void then
1474 Result := l_feat.type
1475 end
1476 if Result = Void then
1477 Result := type_of_local_entity_named (image)
1478 end
1479 if Result = Void then
1480 Result := type_of_constants_or_reserved_word (l_token)
1481 end
1482 end
1483 end
1484 end
1485 end
1486 if Result = Void then
1487 Result := type_of_generic (current_token.image)
1488 end
1489 if Result /= Void then
1490 if not Result.is_loose then
1491 found_class := Result.associated_class
1492 end
1493 end
1494 end
1495 end
1496
1497 found_class: CLASS_C
1498
1499 type_returned_by_infix (a_type: TYPE_A; a_name: STRING): TYPE_A is
1500 -- type returned by operator named `name' applied on type `a_type'
1501 require
1502 a_type_not_void: a_type /= Void
1503 a_name_not_void: a_name /= Void
1504 current_class_c_not_void: current_class_c /= Void
1505 local
1506 name: STRING
1507 feat: E_FEATURE
1508 cls_c: CLASS_C
1509 formal: FORMAL_A
1510 do
1511 name := a_name.as_lower
1512 if name.is_equal (Equal_sign) or name.is_equal (Different_sign) then
1513 create {BOOLEAN_A} Result
1514 else
1515 cls_c := a_type.associated_class
1516 if cls_c /= Void and then cls_c.has_feature_table then
1517 written_class := cls_c
1518 feat := cls_c.feature_with_name (infix_feature_name_with_symbol (name))
1519 if feat /= Void and then feat.type /= Void then
1520 Result := feat.type
1521 if Result.is_formal then
1522 formal ?= Result
1523 if formal /= Void and then a_type.has_generics and then a_type.generics.valid_index (formal.position) then
1524 Result := a_type.generics @ (formal.position)
1525 end
1526 end
1527 end
1528 end
1529 end
1530 end
1531
1532 type_of_local_entity_named (name: STRING): TYPE_A is
1533 -- return type of argument or local variable named `name' found in `current_feature_as'
1534 -- Void if there is none
1535 require
1536 current_class_c_not_void: current_class_c /= Void
1537 local
1538 current_feature: FEATURE_I
1539 entities_list: EIFFEL_LIST [TYPE_DEC_AS]
1540 id_list: ARRAYED_LIST [INTEGER]
1541 stop: BOOLEAN
1542 name_id: INTEGER
1543 retried: BOOLEAN
1544 l_current_class_c: CLASS_C
1545 l_class_type_as: CLASS_TYPE_AS
1546 l_class_name_as: ID_AS
1547 l_name: STRING
1548 do
1549 if retried then
1550 Result := Void
1551 else
1552 l_current_class_c := current_class_c
1553 current_feature := current_feature_i
1554
1555 if current_token /= Void and then current_line /= Void then
1556 set_up_local_analyzer (current_line, current_token, l_current_class_c)
1557 entities_list := local_analyzer.found_locals_list
1558
1559 name_id := Names_heap.id_of (name)
1560 if name_id > 0 and not entities_list.is_empty then
1561 -- There is a `name_id' corresponding to `name' so let's
1562 -- look further.
1563 from
1564 entities_list.start
1565 until
1566 entities_list.after or stop
1567 loop
1568 from
1569 id_list := entities_list.item.id_list
1570 id_list.start
1571 until
1572 id_list.after or stop
1573 loop
1574 if name_id = id_list.item then
1575 stop := True
1576 -- Compute actual type for local
1577 Result := local_evaluated_type (entities_list.item.type,
1578 l_current_class_c,
1579 current_feature)
1580 if Result = Void then
1581 l_class_type_as ?= entities_list.item.type
1582 if l_class_type_as /= Void then
1583 l_class_name_as := l_class_type_as.class_name
1584 if l_class_name_as /= Void then
1585 l_name := l_class_name_as.name
1586 if l_name /= Void then
1587 Result := type_of_generic (l_name)
1588 end
1589 end
1590 end
1591 end
1592 end
1593 id_list.forth
1594 end
1595 entities_list.forth
1596 end
1597 end
1598 end
1599 end
1600 rescue
1601 retried := True
1602 retry
1603 end
1604
1605 type_of_constants_or_reserved_word (token: EDITOR_TOKEN): TYPE_A is
1606 -- return type associated with `token' if it represents a constant
1607 -- or a reserved word. If not, return Void
1608 require
1609 current_class_c_not_void: current_class_c /= Void
1610 local
1611 nb: EDITOR_TOKEN_NUMBER
1612 ch: EDITOR_TOKEN_CHARACTER
1613 current_feature: E_FEATURE
1614 l_current_class_c: CLASS_C
1615 do
1616 if is_keyword (token) then
1617 l_current_class_c := current_class_c
1618 if token_image_is_same_as_word (token, Current_word) then
1619 Result := l_current_class_c.actual_type
1620 elseif
1621 token_image_is_same_as_word (token, Result_word) and then
1622 current_feature_as /= Void and then l_current_class_c.has_feature_table
1623 then
1624 current_feature := l_current_class_c.feature_with_name (
1625 current_feature_as.name.internal_name.name)
1626 if current_feature /= Void then
1627 Result := current_feature.type
1628 end
1629 elseif token_image_is_in_array (token, boolean_values) then
1630 create {BOOLEAN_A} Result
1631 end
1632 else
1633 nb ?= token
1634 if nb /= Void then
1635 if nb.image.occurrences('.') > 0 then
1636 create {REAL_64_A} Result
1637 else
1638 create {INTEGER_A} Result.make (8)
1639 end
1640 else
1641 ch ?= token
1642 if ch /= Void then
1643 create {CHARACTER_A} Result.make (False)
1644 end
1645 end
1646 end
1647 --| FIXME: Missing manifest arrays and strings
1648 end
1649
1650 type_of_generic (a_str: STRING): TYPE_A is
1651 -- Type a formal generic
1652 require
1653 a_str_not_void: a_str /= Void
1654 current_class_c_not_void: current_class_c /= Void
1655 local
1656 l_gens: EIFFEL_LIST [FORMAL_DEC_AS]
1657 l_des_as: FORMAL_DEC_AS
1658 end_loop: BOOLEAN
1659 do
1660 l_gens := current_class_c.generics
1661 if l_gens /= Void then
1662 from
1663 l_gens.start
1664 until
1665 l_gens.after or else end_loop
1666 loop
1667 if a_str.is_equal (l_gens.item.name.name) then
1668 end_loop := True
1669 l_des_as := l_gens.item
1670 create {FORMAL_A} Result.make (l_des_as.is_reference, l_des_as.is_expanded, l_des_as.is_monomorph, l_des_as.position)
1671 end
1672 l_gens.forth
1673 end
1674 end
1675 end
1676
1677 feature {NONE}-- Implementation
1678
1679 local_evaluated_type (a_type: TYPE_AS; a_current_class: CLASS_C; a_feature: FEATURE_I): TYPE_A is
1680 -- Given `a_type' from AST resolve its type in `a_current_class' for feature called
1681 -- `a_feature_name'.
1682 require
1683 a_type_not_void: a_type /= Void
1684 a_current_class_not_void: a_current_class /= Void
1685 a_feature_not_void: a_feature /= Void
1686 local
1687 l_feat: FEATURE_I
1688 do
1689 l_feat := a_feature
1690 type_a_checker.init_for_checking (l_feat, a_current_class, Void, Void)
1691 Result := type_a_generator.evaluate_type_if_possible (a_type, a_current_class)
1692 if Result /= Void then
1693 Result := type_a_checker.solved (Result, a_type)
1694 end
1695 end
1696
1697 after_searched_token: BOOLEAN is
1698 -- is `current_token' after `searched_token' ?
1699 -- True if current_token is Void
1700 do
1701 if current_token = Void then
1702 Result := True
1703 else
1704 Result := (current_line.index > searched_line.index) or else
1705 ((current_line.index = searched_line.index) and then (current_token.position > searched_token.position))
1706 end
1707 end
1708
1709 go_to_previous_token is
1710 -- move current token backward if possible
1711 local
1712 found: BOOLEAN
1713 uncomplete_string: BOOLEAN
1714 do
1715 if current_token /= Void then
1716 from
1717 if is_string (current_token) and then not current_token.image.is_empty then
1718 -- we check if there is a string split on several lines
1719 if current_token.image @ 1 = '%%' then
1720 uncomplete_string := True
1721 end
1722 end
1723 -- we move to previous token, if there is one
1724 if current_token /= current_line.first_token then
1725 current_token := current_token.previous
1726 elseif current_line.previous /= Void then
1727 current_line := current_line.previous
1728 current_token := current_line.eol_token
1729 else
1730 current_token := Void
1731 end
1732 -- we will go backward until current_token is text (not comment, string, blank or eol)
1733 until
1734 current_token = Void or found
1735 loop
1736 if current_token.is_text and then not is_comment (current_token) then
1737 -- it is a text token
1738
1739 if uncomplete_string then
1740 -- a string is split on several lines
1741 -- we skip its beginning
1742 if is_string (current_token) then
1743 uncomplete_string := False
1744 end
1745 if current_token /= current_line.first_token then
1746 current_token := current_token.previous
1747 elseif current_line.previous /= Void then
1748 current_line := current_line.previous
1749 current_token := current_line.eol_token
1750 else
1751 current_token := Void
1752 end
1753 else
1754 if is_string (current_token) and then not current_token.image.is_empty then
1755 -- we check if a string is split on several lines
1756 if current_token.image @ 1 = '%%' then
1757 uncomplete_string := True
1758 else
1759 -- if the string is on one lines, we skip it
1760 if current_token /= current_line.first_token then
1761 current_token := current_token.previous
1762 elseif current_line.previous /= Void then
1763 current_line := current_line.previous
1764 current_token := current_line.eol_token
1765 else
1766 current_token := Void
1767 end
1768 end
1769 else
1770 -- if current_token is text but not comment or string, it is interesting
1771 -- we stop
1772 found := true
1773 end
1774 end
1775 else
1776 -- we skip all the token which are not interesting
1777 if current_token /= current_line.first_token then
1778 current_token := current_token.previous
1779 elseif current_line.previous /= Void then
1780 current_line := current_line.previous
1781 current_token := current_line.eol_token
1782 else
1783 current_token := Void
1784 end
1785 end
1786 end
1787 end
1788 if current_token = Void then
1789 current_line := Void
1790 end
1791 end
1792
1793 go_to_next_token is
1794 -- move current token forward if possible
1795 local
1796 found: BOOLEAN
1797 uncomplete_string: BOOLEAN
1798 do
1799 if current_token /= Void then
1800 from
1801 if is_string (current_token) and then not current_token.image.is_empty then
1802 -- we check if there is a string split on several lines
1803 if current_token.image @ current_token.image.count = '%%' then
1804 uncomplete_string := True
1805 end
1806 end
1807 -- we move to previous token, if there is one
1808 if current_token.next /= Void then
1809 current_token := current_token.next
1810 elseif current_line.next /= Void then
1811 current_line := current_line.next
1812 current_token := current_line.first_token
1813 else
1814 current_token := Void
1815 end
1816 -- we will go backward until current_token is text (not comment, string, blank or eol)
1817 until
1818 current_token = Void or found
1819 loop
1820 if current_token.is_text and then not is_comment (current_token) then
1821 -- it is a text token
1822 if uncomplete_string then
1823 -- a string is split on several lines
1824 -- we skip its beginning
1825 if is_string (current_token) then
1826 uncomplete_string := False
1827 end
1828 if current_token.next /= Void then
1829 current_token := current_token.next
1830 elseif current_line.next /= Void then
1831 current_line := current_line.next
1832 current_token := current_line.first_token
1833 else
1834 current_token := Void
1835 end
1836 else
1837 if is_string (current_token) and then not current_token.image.is_empty then
1838 -- we check if a string is split on several lines
1839 if current_token.image @ 1 = '%%' then
1840 uncomplete_string := True
1841 else
1842 -- if the string is on one lines, we skip it
1843 if current_token.next /= Void then
1844 current_token := current_token.next
1845 elseif current_line.next /= Void then
1846 current_line := current_line.next
1847 current_token := current_line.first_token
1848 else
1849 current_token := Void
1850 end
1851 end
1852 else
1853 -- if current_token is text but not comment or string, it is interesting
1854 -- we stop
1855 found := true
1856 end
1857 end
1858 else
1859 -- we skip all tokens which are not interesting
1860 if current_token.next /= Void then
1861 current_token := current_token.next
1862 elseif current_line.next /= Void then
1863 current_line := current_line.next
1864 current_token := current_line.first_token
1865 else
1866 current_token := Void
1867 end
1868 end
1869 end
1870 end
1871 if current_token = Void then
1872 current_line := Void
1873 end
1874 end
1875
1876 skip_parenthesis (opening_char, closing_char: STRING) is
1877 local
1878 op, cl: STRING
1879 par_cnt: INTEGER
1880 do
1881 op := opening_char
1882 cl := closing_char
1883 from
1884 par_cnt:= 1
1885 until
1886 par_cnt = 0 or else current_token = Void
1887 loop
1888 go_to_next_token
1889 if token_image_is_same_as_word (current_token, cl) then
1890 par_cnt:= par_cnt - 1
1891 elseif token_image_is_same_as_word (current_token, op) then
1892 par_cnt:= par_cnt + 1
1893 end
1894 end
1895 error := error or else current_token = Void
1896 end
1897
1898 skip_parenthesis_backward (opening_char, closing_char: STRING) is
1899 local
1900 op, cl: STRING
1901 par_cnt: INTEGER
1902 do
1903 op := opening_char
1904 cl := closing_char
1905 from
1906 par_cnt:= 1
1907 until
1908 par_cnt = 0 or else current_token = Void
1909 loop
1910 go_to_previous_token
1911 if token_image_is_same_as_word (current_token, op) then
1912 par_cnt:= par_cnt - 1
1913 elseif token_image_is_same_as_word (current_token, cl) then
1914 par_cnt:= par_cnt + 1
1915 end
1916 end
1917 error := error or else current_token = Void
1918 end
1919
1920 feature {NONE} -- Implementation
1921
1922 is_ok_for_completion: BOOLEAN is
1923 -- Can we perform completion?
1924 do
1925 Result := group /= Void and then group.is_valid
1926 if Result then
1927 Result := not workbench.is_compiling or else workbench.last_reached_degree < 6
1928 end
1929 end
1930
1931 initialize_context is
1932 -- Initialize `current_class_i'.
1933 require
1934 is_ok_for_completion: is_ok_for_completion
1935 local
1936 class_c: CLASS_C
1937 l_classi: CLASS_I
1938 l_overrides: ARRAYED_LIST [CONF_CLASS]
1939 do
1940 if current_class_i /= Void then
1941 if current_class_i.is_compiled then
1942 -- If current_class_i is an overriden class,
1943 -- we do not try analysing its compiling infomation.
1944 if current_class_i.config_class.is_overriden then
1945 class_c := Void
1946 else
1947 class_c := current_class_i.compiled_class
1948 end
1949 elseif current_class_i.config_class.does_override then
1950 -- If a class is an overriding class, we take its overrides and
1951 -- try analysing one of them compiled.
1952 from
1953 l_overrides := current_class_i.config_class.overrides
1954 l_overrides.start
1955 until
1956 class_c /= Void or l_overrides.after
1957 loop
1958 if l_overrides.item.is_compiled then
1959 l_classi ?= l_overrides.item
1960 check
1961 class_i: l_classi /= Void
1962 end
1963 class_c := l_classi.compiled_class
1964 end
1965 l_overrides.forth
1966 end
1967 else
1968 class_c := Void
1969 end
1970 if class_c /= Void then
1971 current_class_c := class_c
1972 end
1973 end
1974 end
1975
1976 current_class_i: CLASS_I
1977 -- current class
1978
1979 current_class_c: CLASS_C
1980 -- Current class_c
1981 -- Temp class_c, it could be an overriding class_c, while `current_class_i' is not compiled.
1982
1983 current_feature_i: FEATURE_I is
1984 -- Current feature_i
1985 local
1986 l_current_class_c: CLASS_C
1987 do
1988 if current_class_c /= Void then
1989 l_current_class_c := current_class_c
1990 if l_current_class_c.has_feature_table then
1991 if current_feature_as /= Void then
1992 Result := l_current_class_c.feature_named (current_feature_as.name.internal_name.name)
1993 end
1994 end
1995 -- We hack here to avoid current feature void.
1996 -- type_a_checker only need a feature for like_argument checking.
1997 -- So it goes here only when we try to analyse a name within a typed feature
1998 -- which is after a saved but not compiled feature.
1999 -- It 90% works, only fails when we try to find a type that is a like_argument.
2000 if Result = Void then
2001 Result := l_current_class_c.feature_named ("is_equal")
2002 end
2003 end
2004 end
2005
2006 platform_is_windows: BOOLEAN is
2007 -- Is the current platform Windows?
2008 once
2009 Result := (create {PLATFORM_CONSTANTS}).is_windows
2010 end
2011
2012 local_analyzer: EB_LOCAL_ENTITIES_FINDER is
2013 --
2014 do
2015 Result := local_analyzer_cell.item
2016 ensure
2017 local_analyzer_not_void: Result /= Void
2018 end
2019
2020 local_analyzer_cell: CELL [EB_LOCAL_ENTITIES_FINDER] is
2021 local
2022 l_analyzer: EB_LOCAL_ENTITIES_FINDER_FROM_TEXT
2023 once
2024 create Result
2025 create l_analyzer.make
2026 Result.put (l_analyzer)
2027 end
2028
2029 set_up_local_analyzer (a_line: EDITOR_LINE; a_token: EDITOR_TOKEN; a_class_c: CLASS_C) is
2030 -- Set up local analyzer.
2031 local
2032 l_analyzer: EB_LOCAL_ENTITIES_FINDER_FROM_TEXT
2033 do
2034 l_analyzer ?= local_analyzer
2035 if l_analyzer = Void then
2036 create l_analyzer.make
2037 local_analyzer_cell.put (l_analyzer)
2038 end
2039 l_analyzer.build_entities_list (a_line, a_token, a_class_c)
2040 end
2041
2042 feature {NONE} -- Implementation
2043
2044 is_sorted (positions: ARRAY [EB_CLICKABLE_POSITION]): BOOLEAN is
2045 -- is `positions' sorted ?
2046 -- for check purpose only
2047 local
2048 i: INTEGER
2049 count: INTEGER
2050 do
2051 from
2052 i := 2
2053 count := positions.count
2054 Result := True
2055 until
2056 (not Result) or else i > positions.count
2057 loop
2058 Result := positions.item (i - 1) < positions.item (i)
2059 i := i + 1
2060 end
2061 end
2062
2063 item_greater_than (i: INTEGER; table: ARRAY[INTEGER]): INTEGER is
2064 -- search in `table', which has to be sorted, the index of the first
2065 -- item greater than `i'
2066 -- returns 0 if there is none
2067 local
2068 index_min, index_max, middle: INTEGER
2069 position: INTEGER
2070 do
2071 index_min := 1
2072 index_max := table.count
2073 if i >= table @ 1 then
2074 -- search in the list
2075 if i >= table @ index_max then
2076 index_min := index_max
2077 else
2078 from
2079
2080 until
2081 index_min >= index_max - 1
2082 loop
2083 middle := index_min + (index_max - index_min) // 2
2084 position := table @ middle
2085 if position > i then
2086 index_max := middle
2087 else
2088 index_min := middle
2089 end
2090 end
2091 end
2092 Result := index_min
2093 end
2094 end
2095
2096 last_was_constrained: BOOLEAN
2097 -- Last type of class name was constrained?
2098
2099 last_was_multi_constrained: BOOLEAN
2100 -- Last type of class name was multi constrained?
2101
2102 last_formal: FORMAL_A
2103
2104 last_target_type: TYPE_A
2105 -- Type of last target.
2106 -- It is `Void' for multi constraints until it gets selected by a single found feature.
2107
2108 last_constraints: TYPE_SET_A
2109 -- Constraints of last_formal for the multi constraint case.
2110 -- This is Void for the single constraint case.
2111 -- If not Void `last_target_type' will be computed by using the supplied feature name and `last_constraints'
2112 -- So `last_target_type' is actually a member of the `last_constraints' type set.
2113 -- does _not_ contain any formals nor other typesets.
2114
2115 feature {EB_COMPLETION_POSSIBILITIES_PROVIDER} -- Constants
2116
2117 boolean_values: ARRAY [STRING] is
2118 once
2119 Result := <<"True", "False">>
2120 end
2121
2122 feature_call_separators: ARRAY [STRING] is
2123 once
2124 Result := <<".", "~">>
2125 end
2126
2127 unwanted_symbols: ARRAY [STRING] is
2128 once
2129 Result := <<".", "(", "{", "[", "]", "}", ")", "$">>
2130 end
2131
2132 feature_body_keywords: ARRAY [STRING] is
2133 once
2134 Result := <<"obsolete", "require", "local", "do", "once", "deferred", "ensure", "recue", "unique", "is", "assign">>
2135 end
2136
2137 feature_contract_keywords: ARRAY [STRING] is
2138 once
2139 Result := <<"require", "ensure">>
2140 end
2141
2142 feature_executable_keywords: ARRAY [STRING] is
2143 once
2144 -- We treat assgin as fake executable.
2145 Result := <<"do", "once", "rescue", "assign">>
2146 end
2147
2148 feature_local_keywords: ARRAY [STRING] is
2149 once
2150 Result := <<"local">>
2151 end
2152
2153 special_keywords: ARRAY [STRING] is
2154 once
2155 Result := <<"create", "precursor", "result">>
2156 end
2157
2158 parenthesis: ARRAY [STRING] is
2159 once
2160 Result := <<"(", ")">>
2161 end
2162
2163 closing_separators: ARRAY [STRING] is
2164 once
2165 Result := <<":=", "?=", ";", ",">>
2166 end
2167
2168 infix_groups: LINKED_LIST[ARRAY[STRING]] is
2169 -- list of operators groups, sorted by priority
2170 once
2171 create Result.make
2172 Result.extend (<<"@">>)
2173 Result.extend (<<"^">>)
2174 Result.extend (<<"*", "/", "//", "\\">>)
2175 Result.extend (<<"+", "-">>)
2176 Result.extend (<<"/=", "=", ">", ">=", "<", "<=">>)
2177 Result.extend (<<"and">>)
2178 Result.extend (<<"xor">>)
2179 Result.extend (<<"or">>)
2180 Result.extend (<<"implies">>)
2181 end
2182
2183 invariant
2184
2185 current_token_in_current_line: (current_line = Void and current_token = Void) or else (current_line /= Void and then current_line.has_token (current_token))
2186
2187 indexing
2188 copyright: "Copyright (c) 1984-2006, Eiffel Software"
2189 license: "GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)"
2190 licensing_options: "http://www.eiffel.com/licensing"
2191 copying: "[
2192 This file is part of Eiffel Software's Eiffel Development Environment.
2193
2194 Eiffel Software's Eiffel Development Environment is free
2195 software; you can redistribute it and/or modify it under
2196 the terms of the GNU General Public License as published
2197 by the Free Software Foundation, version 2 of the License
2198 (available at the URL listed under "license" above).
2199
2200 Eiffel Software's Eiffel Development Environment is
2201 distributed in the hope that it will be useful, but
2202 WITHOUT ANY WARRANTY; without even the implied warranty
2203 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2204 See the GNU General Public License for more details.
2205
2206 You should have received a copy of the GNU General Public
2207 License along with Eiffel Software's Eiffel Development
2208 Environment; if not, write to the Free Software Foundation,
2209 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2210 ]"
2211 source: "[
2212 Eiffel Software
2213 356 Storke Road, Goleta, CA 93117 USA
2214 Telephone 805-685-1006, Fax 805-685-6869
2215 Website http://www.eiffel.com
2216 Customer support http://support.eiffel.com
2217 ]"
2218
2219 end -- class EB_CLASS_INFO_ANALYZER

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.23