-- This file is part of SmartEiffel The GNU Eiffel Compiler. -- Copyright (C) 1994-2002 LORIA - INRIA - U.H.P. Nancy 1 - FRANCE -- Dominique COLNET and Suzanne COLLIN - SmartEiffel@loria.fr -- http://SmartEiffel.loria.fr -- 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. -- class E_WHEN -- -- To store a when clause of an inspect instruction. -- inherit GLOBALS creation {EIFFEL_PARSER} make creation {E_WHEN,WHEN_LIST} from_e_when feature start_position: POSITION -- Of the first character of keyword "when". header_comment: COMMENT -- Of the when clause. compound: COMPOUND -- Of the when clause if any. when_list: WHEN_LIST -- Corresponding one when checked. feature {WHEN_LIST} verify_scoop(allowed: FORMAL_ARG_LIST) is local i: INTEGER do if compound /= Void then compound.verify_scoop(allowed) end from i := list.upper until i < list.lower loop list.item(i).verify_scoop(allowed) i := i - 1 end end feature {NONE} values: ARRAY[INTEGER] -- To store pairs of range values. feature {E_WHEN} list: ARRAY[WHEN_ITEM] feature {NONE} points1: FIXED_ARRAY[INTEGER] is -- To reach the `compound'. once !!Result.with_capacity(12) end point2: INTEGER -- To go outside the E_INSPECT. feature {EIFFEL_PARSER} make(sp: like start_position; hc: like header_comment) is require not sp.is_unknown do start_position := sp header_comment := hc ensure start_position = sp end feature {WHEN_LIST} afd_check is do if compound /= Void then compound.afd_check end end safety_check is do if compound /= Void then compound.safety_check end end feature {NONE} from_e_when(other: like Current) is local i: INTEGER when_item: WHEN_ITEM do start_position := other.start_position list := other.list.twin from i := list.lower until i > list.upper loop when_item := list.item(i).twin when_item.clear_e_when list.put(when_item,i) i := i + 1 end header_comment := other.header_comment compound := other.compound end feature use_current: BOOLEAN is do if compound /= Void then Result := compound.use_current end end stupid_switch(run_time_set: RUN_TIME_SET): BOOLEAN is do Result := (compound = Void or else compound.stupid_switch(run_time_set)) end e_inspect: E_INSPECT is do Result := when_list.e_inspect end feature {WHEN_LIST} compile_to_jvm(else_position: POSITION; remainder: INTEGER) is -- Where `remainder' is the number of E_WHEN after Current. local point3, point4, bi: INTEGER must_test: BOOLEAN ca: like code_attribute do ca := code_attribute if remainder > 0 then must_test := true elseif ace.no_check then must_test := true else -- boost : must_test := not else_position.is_unknown end points1.clear if must_test then from bi := values.lower until bi > values.upper loop if values.item(bi) = values.item(bi+1) then ca.opcode_dup ca.opcode_push_integer(values.item(bi)) points1.add_last(ca.opcode_if_icmpeq) else ca.opcode_dup ca.opcode_push_integer(values.item(bi)) point3 := ca.opcode_if_icmplt ca.opcode_dup ca.opcode_push_integer(values.item(bi+1)) points1.add_last(ca.opcode_if_icmple) ca.resolve_u2_branch(point3) end bi := bi + 2 end point4 := ca.opcode_goto end ca.resolve_with(points1) if compound /= Void then compound.compile_to_jvm end point2 := ca.opcode_goto if must_test then ca.resolve_u2_branch(point4) end end compile_to_jvm_resolve_branch is do code_attribute.resolve_u2_branch(point2) end compile_to_c is local bi: INTEGER do cpp.put_string(once "%Nif(") from bi := values.lower until bi > values.upper loop cpp.put_character('(') if values.item(bi) = values.item(bi+1) then cpp.put_integer(values.item(bi)) cpp.put_string(once "==") cpp.put_inspect else cpp.put_character('(') cpp.put_integer(values.item(bi)) cpp.put_string(once "<=") cpp.put_inspect cpp.put_string(fz_39) cpp.put_inspect cpp.put_string(once "<=") cpp.put_integer(values.item(bi+1)) cpp.put_character(')') end cpp.put_character(')') -- bi := bi + 2 if bi < values.upper then cpp.put_string(once "||") end end cpp.put_string(once "){%N") if compound /= Void then compound.compile_to_c end cpp.put_string(fz_12) end compile_to_c_switch is local bi, v: INTEGER do from bi := values.lower until bi > values.upper loop from v := values.item(bi) until v > values.item(bi+1) loop cpp.put_string(once "case ") cpp.put_integer(v) cpp.put_string(once ":%N") v := v + 1 end bi := bi + 2 end if compound /= Void then compound.compile_to_c end cpp.put_string(once "break;%N") end pretty_print is local i: INTEGER do pretty_printer.keyword(fz_when) pretty_printer.level_incr if header_comment /= Void then header_comment.pretty_print end if list /= Void then from i := list.lower until i > list.upper loop list.item(i).pretty_print i := i + 1 if i <= list.upper then pretty_printer.put_character(',') end end end pretty_printer.level_decr pretty_printer.keyword(fz_then) if compound /= Void then compound.pretty_print end end includes_integer(v: INTEGER): BOOLEAN is local i: INTEGER do if values /= Void and then v >= values.item(values.lower) and then v <= values.item(values.upper) then from i := values.lower until Result or else i > values.upper loop Result := values.item(i) <= v and v <= values.item(i+1) i := i + 2 end end end includes_integer_between(l,u: INTEGER): BOOLEAN is require invalid_range: l < u local i: INTEGER do if values /= Void and then u >= values.item(values.lower) and then l <= values.item(values.upper) then from i := values.lower until Result or else i > values.upper loop Result := values.item(i) <= u and l <= values.item(i+1) i := i + 2 end end end largest_range_of_values: INTEGER is -- The largest number of consecutive values - returns 0 if none local i, range: INTEGER do if values /= Void then from i := values.lower until i > values.upper loop range := values.item(i+1) - values.item(i) + 1 if range > Result then Result := range end i := i + 2 end end end feature {WHEN_LIST,E_WHEN} to_runnable_integer(wl: like when_list): like Current is require wl /= Void local ct: E_TYPE ne, i: INTEGER when_item: WHEN_ITEM do if when_list = Void then ne := nb_errors when_list := wl if list = Void then error_handler.add_position(e_inspect.start_position) error(start_position,em2) else from i := list.lower until i > list.upper or else nb_errors - ne > 0 loop when_item := list.item(i).to_runnable_integer(Current) if when_item = Void then error(start_position,em1) else list.put(when_item,i) end i := i + 1 end end if compound /= Void then ct := smart_eiffel.top_rf.current_type compound := compound.to_runnable(ct) if compound = Void then error(start_position,em1) end end Result := Current else !!Result.from_e_when(Current) Result := Result.to_runnable_integer(wl) end ensure Result.when_list = wl end to_runnable_character(wl: like when_list): like Current is require wl /= Void local ct: E_TYPE ne, i: INTEGER when_item: WHEN_ITEM do if when_list = Void then ne := nb_errors when_list := wl if list = Void then error_handler.add_position(e_inspect.start_position) error(start_position,em2) else from i := list.lower until i > list.upper or else nb_errors - ne > 0 loop when_item := list.item(i).to_runnable_character(Current) if when_item = Void then error(start_position,em1) else list.put(when_item,i) end i := i + 1 end end if compound /= Void then ct := smart_eiffel.top_rf.current_type compound := compound.to_runnable(ct) if compound = Void then error(start_position,em1) end end Result := Current else !!Result.from_e_when(Current) Result := Result.to_runnable_character(wl) end ensure Result.when_list = wl end feature {WHEN_ITEM_1} add_when_item_1(wi1: WHEN_ITEM_1) is require wi1 /= Void local i, v: INTEGER do v := wi1.expression_value if e_inspect.includes(v) then err_occ(v,wi1.start_position) elseif values = Void then !!values.make(501,502) values.put(v,values.lower) values.put(v,values.upper) else i := locate_in_values(v) if i = values.lower then -- v is lower than lowest value if v = values.item(i) - 1 then -- just change lower values.put(v,i) else values.resize(values.lower-2, values.upper) values.put(v,values.lower) values.put(v,values.lower+1) end elseif i > values.upper then -- v is higher than highest value if v = values.item(i-1) + 1 then -- just change upper values.put(v,i-1) else values.resize(values.lower, values.upper+2) values.put(v,values.upper-1) values.put(v,values.upper) end else if v = values.item(i-1) + 1 and v = values.item(i) - 1 then values.put(values.item(i+1),i-1) from until i > values.upper-2 loop values.put(values.item(i+2),i) values.put(values.item(i+3),i+1) i := i + 2 end values.resize(values.lower, values.upper-2) elseif v = values.item(i-1) + 1 then -- just change upper values.put(v,i-1) elseif v = values.item(i) - 1 then -- just change lower values.put(v,i) else values.resize(values.lower, values.upper+2) from i := values.upper - 1 until v > values.item(i-1) loop values.put(values.item(i-2),i) values.put(values.item(i-1),i+1) i := i - 2 end values.put(v,i) values.put(v,i+1) end end end ensure e_inspect.includes(wi1.expression_value) end feature {WHEN_ITEM_2} add_when_item_2(wi2: WHEN_ITEM_2) is require wi2 /= Void local l, u, i: INTEGER do l := wi2.lower_value u := wi2.upper_value if l >= u then error(wi2.start_position,"Not a good slice.") elseif e_inspect.includes_between(l,u) then from i := l until e_inspect.includes(i) -- try to locate the exact problem loop if i = l then l := l + 1 i := u else u := u - 1 i := l end end err_occ(i,wi2.start_position) elseif values = Void then !!values.make(501,502) values.put(l,values.lower) values.put(u,values.upper) else i := locate_in_values(l) if i = values.lower then -- l and u are lower than lowest value if u = values.item(i) - 1 then -- just change lower values.put(l,i) else values.resize(values.lower-2, values.upper) values.put(l,values.lower) values.put(u,values.lower+1) end elseif i > values.upper then -- l and u are higher than highest if l = values.item(i-1) + 1 then -- just change upper values.put(u,i-1) else values.resize(values.lower, values.upper+2) values.put(l,values.upper-1) values.put(u,values.upper) end else if l = values.item(i-1) + 1 and u = values.item(i) - 1 then values.put(values.item(i+1),i-1) from until i > values.upper-2 loop values.put(values.item(i+2),i) values.put(values.item(i+3),i+1) i := i + 2 end values.resize(values.lower, values.upper-2) elseif l = values.item(i-1) + 1 then -- just change upper values.put(u,i-1) elseif u = values.item(i) - 1 then -- just change lower values.put(l,i) else values.resize(values.lower, values.upper+2) from i := values.upper - 1 until l > values.item(i-1) loop values.put(values.item(i-2),i) values.put(values.item(i-1),i+1) i := i - 2 end values.put(l,i) values.put(u,i+1) end end end end feature {EIFFEL_PARSER} add_value(v: EXPRESSION) is require v /= Void local element: WHEN_ITEM do !WHEN_ITEM_1!element.make(v) if list = Void then !!list.with_capacity(4,1) end list.add_last(element) end add_slice(min, max: EXPRESSION) is require min /= Void max /= Void local element: WHEN_ITEM do !WHEN_ITEM_2!element.make(min,max) if list = Void then !!list.with_capacity(4,1) end list.add_last(element) end set_compound(c: like compound) is do compound := c ensure compound = c end feature {NONE} err_occ(v: INTEGER; p: POSITION) is do error_handler.add_position(e_inspect.start_position) error_handler.append("Second occurrence for this value (") error_handler.append(v.to_string) error(p,") in the same inspect.") end locate_in_values(v: INTEGER): INTEGER is -- returns index in values table where v would be inserted require values /= Void do from Result := values.lower until Result > values.upper or else v < values.item(Result) loop Result := Result + 2 end ensure (Result - values.lower) \\ 2 = 0 Result < values.upper implies v < values.item(Result) Result > values.upper implies v > values.item(Result-1) end feature {NONE} em1: STRING is "Bad when clause." em2: STRING is "Empty when clause in inspect." end -- E_WHEN