// Copyright (c) 2003-2005 The University of Wroclaw. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // 3. The name of the University may not be used to endorse or promote // products derived from this software without specific prior // written permission. // // THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY ``AS IS'' AND ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN // NO EVENT SHALL THE UNIVERSITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // using Nemerle.Collections; namespace Nemerle.CSharp { /** * C# wrapper for STree class */ public class StatementTree { public this () { s_tree = STree.TokS ("") } public this (t : antlr.IToken) { s_tree = STree.Tok (t) } public this (s : string) { s_tree = STree.TokS (s) } public this (s : string,ch : LinkedList[StatementTree]) { mutable l = []; def get_stree (t : StatementTree) { l = t.s_tree :: l; } ch.Iter (get_stree); s_tree = STree.Statement(s,l) } public ToString (tp : string) : string { STree.set_type(tp); s_tree. Transform (); } public override ToString () : string { ToString (""); } public PlainString : string { get { match (s_tree) { | STree.TokS (s) => s | _ => null } } } private s_tree : STree; } /** * Description of jump */ public variant Jump { | ReturnBreak | Return | Continue | Break | Goto {label : string;} | All } /** * STree class, representing single statement */ public partial variant STree { | TokS { s : string; } | Tok { t : antlr.IToken; } | Statement { s_name : string; children : list[STree] ; } public Transform () : string { // // schedule of transformatting tree of a method body // def st = this.eliminate_goto () // we are eliminating gotos from method body .translate_switch() // we are translating every switch to match . eliminate_continues () // we are eliminating continues from loops .eliminate_jump_2 (Jump.ReturnBreak ()); // we are eliminating returns and breaks from loops (match (st) { | [tree2] => if (tree2.jump_inside (Jump.Return ())) tree2.eliminate_jump (Jump.Return ()) // we are eliminating returns from method body else tree2 | _ => assert (false); }).ToString (); } #region ToString method override public ToString () : string { match(this) { | Tok (t) => t.getText () | TokS (s) => s | Statement ( "RETURN" , [Tok (t), expr, s]) => ExtendedToken.getWhitespaces (t) + expr.ToString () + s.ToString () | Statement ( "RETURN" , [Tok (t), s]) => ExtendedToken.getWhitespaces (t) + "()" + s.ToString () | Statement ( "CONTINUE" , [Tok (t), s]) => ExtendedToken.getWhitespaces (t) + "/*" + ExtendedToken.getTextOnly (t)+ "*/()" +s.ToString () | Statement ("WHILE",children) => def new_while = Statement("WHILE_",children); match(children) { | [_,_,_,_,Statement("BLOCK",_)] => new_while.ToString () + ";"; | _ => new_while.ToString (); } | Statement ("SWITCH",[Tok(s),lp,exp,rp,switch_block]) => ExtendedToken.getWhitespaces(s) + "match" + lp.ToString () + exp.ToString () + rp.ToString () + switch_block.ToString () | Statement ("SWITCH_BLOCK",xs) => def print_all (secions) : string { | [] => "" | head :: tail => head.ToString () + print_all (tail) } def print (sections) : string { | [] => "" | (Statement("SWITCH_SECTION",[Statement("SWITCH_SECTION_LABELS",Statement ("SWITCH_LABEL",[Tok(c),_,_]) :: _),_]) as head) :: [] => if(get_default_label(head)) head.ToString () else head.ToString () + Statement("SWITCH_SECTION", [ Statement("SWITCH_SECTION_LABELS",[Statement ("SWITCH_LABEL",[Tok(c),TokS(" _ "),Tok(ExtendedToken("",":"))]) ]) , Statement("SWITCH_SECTION_STATEMENTS",[TokS("()")]) ]).ToString () | head :: tail => if(get_default_label(head)) print_all (tail) + head.ToString () else head.ToString () + print (tail) } def (lbrace,sections,rbrace) = cut_off_braces(xs); lbrace.ToString () + print (sections) + rbrace.ToString () | Statement ("SWITCH_SECTION",[Statement("SWITCH_SECTION_LABELS",lbs),Statement("SWITCH_SECTION_STATEMENTS",sts)]) => def print_labels (labels) : string { | [] => "" | head :: tail => head.ToString () + print_labels(tail) } def print_statements(statements) : string { | [] => "" | head :: tail => head.ToString () + print_statements(tail) } print_labels(lbs) + "=> " + print_statements(sts) | Statement ("SWITCH_LABEL",[Tok(c),ce,Tok(colon)]) => ExtendedToken.getWhitespaces(c) + "|" + ce.ToString () + ExtendedToken.getWhitespaces (colon) | Statement ("SWITCH_DEFAULT",[Tok(d),Tok(colon)]) => ExtendedToken.getWhitespaces(d) + "|" + " _ " + ExtendedToken.getWhitespaces (colon) | Statement("CATCH_CLAUSES", (head :: _) as lst) => def sb = System.Text.StringBuilder (); foreach (x in lst) ignore (sb.Append (x.ToString ())); def first_whitespace = get_first_whitespace (head); first_whitespace + "catch { " + sb.ToString () + first_whitespace + "}" | Statement ("SPECIFIC_CATCH", [Tok(c),_,ty,id,_,block]) => ExtendedToken.getWhitespaces (c) + "| " + id.ToString () + " is " + ty.ToString () + " => " + block.ToString () | Statement ("SPECIFIC_CATCH", [Tok(c),_,ty,_,block]) => ExtendedToken.getWhitespaces (c) + "| _ is " + ty.ToString () + " => " + block.ToString () | Statement ("GENERAL_CATCH", [Tok(c),block]) => ExtendedToken.getWhitespaces (c) + "| _ => " + block.ToString () | Statement("FOREACH", children) => if ( Options.NemerlishForeach ) { def sb = System.Text.StringBuilder (); ignore (sb.Append (List.Nth (children ,0))); ignore (sb.Append (List.Nth (children ,1))); ignore (sb.Append (List.Nth (children ,2))); // here we do not insert ':> type' ignore (sb.Append (List.Nth (children ,5))); ignore (sb.Append (List.Nth (children ,6))); ignore (sb.Append (List.Nth (children ,7))); ignore (sb.Append (List.Nth (children ,8))); sb.ToString () } else { def sb = System.Text.StringBuilder (); foreach (x in children) ignore (sb.Append (x.ToString ())); sb.ToString () } | Statement ("LABEL", [Tok(id), _ , st ] ) => def ws = ExtendedToken.getWhitespaces (id); match ( label_symbols.Get ( ExtendedToken.getTextOnly (id) ) ) { | None => ws + st.ToString (); | Some (symbol) => ws + st.ToString () + ws + symbol + " = false;"; } | Statement ("BREAK",[Tok(b),s]) => ExtendedToken.getWhitespaces(b) + "()" + s.ToString () | Statement ( _ , children) => def sb = System.Text.StringBuilder (); foreach (x in children) ignore (sb.Append (x.ToString ())); sb.ToString () } } #endregion /* -- SWITCH TRANSLATION ----------------------------------------- */ #region switch translation private is_default (label : STree) : bool { | Statement ("SWITCH_DEFAULT",_) => true | _ => false } private get_default_label (section : STree) : bool { | Statement ("SWITCH_SECTION",[Statement("SWITCH_SECTION_LABELS",lbs),_]) => List.Exists (lbs, is_default) | _ => false } /** * main switch translation function */ protected translate_switch () : STree { match(this) { | Statement("SWITCH",[s,lp,exp,rp,switch_block]) => def (lbrace,sections,rbrace) = cut_off_braces (switch_block); def translated_switch_block = Statement("SWITCH_BLOCK",lbrace :: translate_switch_sections (sections) + [rbrace]); Statement("SWITCH",[s,lp,exp,rp, translated_switch_block]) | x => def loop (trees,acc) { match(trees) { | (Statement(_,_) as statement) :: tail => loop (tail, statement.translate_switch () :: acc) | head :: tail => loop (tail, head :: acc) | [] => List.Rev (acc) } } match(x) { | Statement(name,trees) => Statement(name,loop(trees,[])) | _ => x } } } /** * method used to translate a list of switch sections */ private translate_switch_sections (sections : list [STree]) : list [STree] { def switch_block = Statement("SWITCH_BLOCK",TokS("{") :: sections + [TokS("}")]); def (_,statements,_) = cut_off_braces(switch_block.eliminate_jump( Jump.Break ())); statements } // FIXME: what about 'goto case'? #endregion /* -- JUMP ELIMINATION ------------------------------------------- */ private cut_off_braces (lst : list [STree]) : STree * list [STree] * STree { def st = Statement("BLOCK",lst); cut_off_braces (st) } private cut_off_braces (t : STree) : STree * list [STree] * STree { | Statement("SWITCH_BLOCK",x::xs) | Statement("BLOCK",x::xs) => def (sx,end) = List.DivideLast (xs); (x, sx, end) | _ => assert(false); } /** * gets whitespaces before statement */ private get_first_whitespace (tree : STree) : string { | TokS (_) => " "; | Tok (t) => ExtendedToken.getWhitespaces(t) | Statement(_,x :: _) => get_first_whitespace(x) | _ => assert(false); } private get_first_whitespace (tree_list : list[STree]) : string { | [] => "" | head :: _ => get_first_whitespace (head) } /** * retrieves list of catch clauses and finally clause(if it exists) from try statement */ private get_catch_clauses (clauses : list [STree]) : list [STree] * list [STree] { match(clauses) { | [Statement("CATCH_CLAUSES",xs) , Statement("FINALLY", [Tok(f),block] ) ] => def finally_ = match(block.eliminate_jump_2 (Jump.ReturnBreak ())) { | [x] => [Statement("FINALLY",[Tok(f), x])] | y => Message.Error ("Can't jump out of finally block" , f);y } (xs , finally_) | [Statement("CATCH_CLAUSES",xs)] => (xs , []) | [Statement("FINALLY", [Tok(f),block] )] => def finally_ = match(block.eliminate_jump_2 (Jump.ReturnBreak ())) { | [x] => [Statement("FINALLY",[Tok(f), x])] | y => Message.Error ("Can't jump out of finally block" , f) ; y } ([] , finally_) | _ => assert (false); } } /** * walks a list of catch clauses, transforming loops in them, * returns also information wheter there was jump in them */ private walk_through_catches (catches : list [STree] , acc1 : bool , acc2 : list[STree * bool], jump : Jump) : list[STree * bool] * bool { def eliminate_block(block : STree, w : antlr.IToken) : STree { match(block.eliminate_jump_2 (Jump.ReturnBreak ())) { | [x] => x | xs => def whitespaces = ExtendedToken.getWhitespaces (w); Statement("BLOCK", Tok(ExtendedToken(whitespaces, "{")) :: List.Rev(xs) + [Tok(ExtendedToken(whitespaces, "}"))]); } } match(catches) { | [] => (List.Rev(acc2),acc1) | Statement("GENERAL_CATCH",[Tok(c),block]) :: tail => def block_eliminated = eliminate_block(block,c); def jumps = block_eliminated.jump_inside ( jump ); walk_through_catches(tail , jumps || acc1, (Statement("GENERAL_CATCH",[Tok(c), block_eliminated ]) , jumps) :: acc2 ,jump) | Statement ("SPECIFIC_CATCH", [Tok(c),lb,ty,id,rb,block]) :: tail => def block_eliminated = eliminate_block(block,c); def jumps = block_eliminated.jump_inside ( jump ); walk_through_catches(tail , jumps || acc1, (Statement("SPECIFIC_CATCH",[Tok(c), lb, ty , id, rb , block_eliminated ]) , jumps):: acc2 ,jump) | Statement ("SPECIFIC_CATCH", [Tok(c),lb,ty,rb,block]) :: tail=> def block_eliminated = eliminate_block(block,c); def jumps = block_eliminated.jump_inside ( jump ); walk_through_catches(tail , jumps || acc1, (Statement("SPECIFIC_CATCH",[Tok(c), lb, ty , rb , block_eliminated ]) , jumps ):: acc2 ,jump) | _=> assert (false) } } private divide_switch_sections (sections : list [STree],jump : Jump) : list [STree] * list [STree] { def contains (tree : STree) { match (jump) { | Jump.Continue | Jump.Return => tree.jump_inside (jump) | _ => false } } List.Partition (sections, contains) } /* -- CONTINUE ELIMINATION ----------------------------------------- */ #region eliminate continues /** * Main 'continue' elimination function. Returns tree made by 'continue' elimnation. * Function first searchs for loop, then transforms it. */ protected eliminate_continues () : STree { def eliminate_block (block) : STree { | Statement("BLOCK",_) => def (lbrace,body_eliminated,rbrace) = cut_off_braces(block.eliminate_jump ( Jump.Continue ())); Statement("BLOCK",lbrace :: body_eliminated + [rbrace]); | _ => def body = Statement ("BLOCK",[TokS("{"),block,TokS("}")]); def (_,body_eliminated,_) = cut_off_braces(body.eliminate_jump ( Jump.Continue ())); match(body_eliminated) { | [block_eliminated] => block_eliminated | _ => assert(false); } } match (this) { // WHILE loop | Statement("WHILE",[w,lp,be,rp,block]) => if (block.jump_inside ( Jump.Continue () )) Statement("WHILE",[w,lp,be,rp,eliminate_block(block)]) else Statement("WHILE",[w,lp,be,rp,block.eliminate_continues ()]) // DO ... WHILE loop | Statement("DO",[d,block,w,lp,be,rp,s]) => if (block.jump_inside ( Jump.Continue ())) Statement("DO",[d,eliminate_block(block),w,lp,be,rp,s]) else Statement("DO",[d,block.eliminate_continues() ,w,lp,be,rp,s]) // FOR loop | Statement("FOR",[f,lp,finit,s1,fc,s2,fiter,rp,block]) => if (block.jump_inside ( Jump.Continue ())) Statement("FOR",[f,lp,finit,s1,fc,s2,fiter,rp,eliminate_block(block)]) else Statement("FOR",[f,lp,finit,s1,fc,s2,fiter,rp,block.eliminate_continues()]) // FOREACH loop | Statement("FOREACH",[f,lp,id,c,t,i,col,rp,block]) => if (block.jump_inside ( Jump.Continue ())) Statement("FOREACH",[f,lp,id,c,t,i,col,rp,eliminate_block(block)]) else Statement("FOREACH",[f,lp,id,c,t,i,col,rp,block.eliminate_continues()]) | x => def loop (trees,acc) { match(trees) { | (Statement(_,_) as statement) :: tail => loop (tail, statement.eliminate_continues () :: acc) | head :: tail => loop (tail, head :: acc) | [] => List.Rev (acc) } } match(x) { | Statement("SWITCH_SECTION",[lbs,Statement("SWITCH_SECTION_STATEMENTS",xs)]) => Statement("SWITCH_SECTION",[lbs,Statement("SWITCH_SECTION_STATEMENTS",loop(xs,[]))]) | Statement(name,trees) => Statement(name,loop(trees,[])) | _ => x } } } #endregion /* -- JUMP ELIMINATION --------------------------------------------- */ #region eliminate_jump /** * Function used to eliminate jumps from function bodies, loop bodies, switch sections.. * It doesn't add new variables, only transform trees */ protected eliminate_jump (jump : Jump) : STree { def (lbrace,statements,rbrace) = cut_off_braces (this); def loop (sts : list [STree],acc : list [STree]) : list [STree] { match(sts) { | (Statement("IF", _) as if_st) :: tail | (Statement("WHEN", _) as if_st) :: tail => def block_statement = Statement("BLOCK",(lbrace :: tail) + [rbrace]); def est_block = block_statement.eliminate_jump (jump); def est_if = if_st.eliminate_jump_if (est_block,jump); def last_el = if (est_if is Statement ("BLOCK", _ )) { def (_ , sts , _ ) = cut_off_braces (est_if); List.Rev(sts) } else [est_if]; List.Rev(last_el + acc) | (Statement ("SWITCH",_) as switch) :: tail => match(jump) { | Jump.Continue //FIXME: maybe goto | Jump.Return => def block_statement = Statement("BLOCK",(lbrace :: tail) + [rbrace]); def est_block = block_statement.eliminate_jump (jump); List.Rev( switch.eliminate_jump_if(est_block,jump) :: acc) | _ => loop (tail, switch :: acc ) } | Statement("BLOCK",xs) :: tail => def (lb,ys,rb) = cut_off_braces (xs); def block_statement = Statement("BLOCK",lb :: ys + tail + [rb]); def est_block = block_statement.eliminate_jump (jump); List.Rev(est_block :: acc) | (Statement("SWITCH_SECTION",[lbs,Statement("SWITCH_SECTION_STATEMENTS",xs)]) as switch_section) :: tail => match(jump) { | Jump.Break => def block = Statement("BLOCK",TokS("{") :: xs + [TokS("}")]); def (_,statements,_) = cut_off_braces(block.eliminate_jump(jump)); loop (tail, Statement("SWITCH_SECTION",[lbs,Statement("SWITCH_SECTION_STATEMENTS",statements)]) :: acc) | _ => loop (tail, switch_section :: acc ) } | (Statement("BREAK",_) as break_statement) :: tail => match(jump) { | Jump.Break => List.Rev (break_statement :: acc) | _ => loop (tail, break_statement :: acc ) } | (Statement("RETURN", _) as ret_st) :: tail => match(jump) { | Jump.Return => List.Rev (ret_st :: acc) | _ => loop (tail, ret_st :: acc ) } | (Statement("CONTINUE", _) as con_st) :: tail => match(jump) { | Jump.Continue => List.Rev (con_st :: acc) | _ => loop (tail, con_st :: acc ) } | (Statement("FOREACH", _) as while_st) :: tail | (Statement("FOR", _) as while_st) :: tail | (Statement("DO", _) as while_st) :: tail | (Statement("WHILE", _) as while_st) :: tail => match(jump) { | Jump.Continue => loop (tail, while_st.eliminate_continues () :: acc ) | _ => loop (tail, while_st :: acc ) } | head :: tail => loop (tail, head :: acc ) | _ => List.Rev(acc) } } match(this) { | Statement("SWITCH_BLOCK",_) => Statement("SWITCH_BLOCK",lbrace :: loop(statements,[]) + [rbrace]) | _ => Statement("BLOCK",lbrace :: loop(statements,[]) + [rbrace]) } } #endregion #region eliminate jump in if /** * Function used to transform 'if' trees containing jumps */ protected eliminate_jump_if (return_st : STree,jump : Jump) : STree { def(lb,sts,rb) = cut_off_braces (return_st); match(this) { | Statement("IF",[Tok(i),lp,exp,rp,st1,Tok(e),st2]) => def ws_if = ExtendedToken.getWhitespaces(i); def ws_else = ExtendedToken.getWhitespaces(e); // checking "if" def transform_if () : STree { def s1 = Statement("BLOCK",[Tok(ExtendedToken(ws_if,"{")),st1] + sts +[Tok(ExtendedToken(ws_if,"}"))]); def es1 = s1.eliminate_jump (jump); def s2 = Statement("BLOCK",[Tok(ExtendedToken(ws_else,"{")),st2] + sts + [Tok(ExtendedToken(ws_else,"}"))]); def es2 = s2.eliminate_jump (jump); Statement("IF",[Tok(i),lp,exp,rp,es1,Tok(e),es2]) } if (st1.jump_inside(jump) || st2.jump_inside(jump)) transform_if() else Statement("BLOCK", lb :: this :: sts + [rb]) // checking "when" | Statement("WHEN",[Tok(i),lp,exp,rp,st1]) => def whitespaces = ExtendedToken.getWhitespaces(i); def transform_when (whitespaces) : STree { def s1 = Statement("BLOCK",[Tok(ExtendedToken(whitespaces : string,"{")),st1] + sts +[Tok(ExtendedToken(whitespaces,"}"))]); def es1 = s1.eliminate_jump (jump); def rs = Statement("BLOCK",lb :: ( if(sts is [] && !(jump is Jump.Continue)) // when RETURN is in loop, and loop is last statement in block Statement("RETURN", [Tok (ExtendedToken (ExtendedToken.getWhitespaces (i), "return")), TokS("Nemerle.Extensions.DefaultValue(" + tp + ")"),TokS(";")]); else return_st ) :: [rb]); Statement("IF", [Tok(ExtendedToken(whitespaces,"if")), lp, exp, rp, es1, Tok(ExtendedToken(whitespaces , "else")), rs]) } if(st1.jump_inside (jump)) transform_when (whitespaces) else Statement("BLOCK", lb :: (this :: sts) + [rb]) | Statement("IF", _) | Statement("WHEN", _) => assert(false); // checking SWITCH | Statement("SWITCH",[s,lp,ce,rp,Statement("SWITCH_BLOCK",xs)]) as switch => def loop (sections,acc) { match(sections) { | [] => List.Rev (acc) | Statement ("SWITCH_SECTION",[lbs ,Statement("SWITCH_SECTION_STATEMENTS",statements)]) :: tail => def s = Statement("BLOCK",[TokS("{")] + statements + sts +[TokS("}")]); def es = s.eliminate_jump(jump); def (_,sts,_) = cut_off_braces(es); loop( tail , Statement ("SWITCH_SECTION", [ lbs , Statement("SWITCH_SECTION_STATEMENTS", sts ) ] ) :: acc) | _ => assert(false) } }; match(jump) { | Jump.Continue | Jump.Return => def (lb,sections,rb) = cut_off_braces (xs); def (jmp,_non_jmp) = divide_switch_sections(sections,jump); match(jmp) { | [] => Statement("BLOCK",lb :: (this :: sts) + [rb]); //switch | _ => Statement("SWITCH",[s,lp,ce,rp,Statement("SWITCH_BLOCK",lb :: loop(sections,[]) + [rb] )]) } | _ => switch } | x => x } } #endregion /* -- BREAK ELIMINATION -------------------------------------------- */ /** * Another elimination function. Used for break elimination mainly. * Returns list of trees. * Function first searchs for loop, then transforms it. * Adds new variables. */ protected eliminate_jump_2 (jump : Jump) : list [STree] { def loop (trees,acc) { match(trees) { | (Statement(_,_) as statement) :: tail => def eliminated_st = statement.eliminate_jump_2 (jump); match(eliminated_st) { | [] => assert(false) | [el_st] => loop (tail, el_st :: acc) | (head :: _) as lst => def whitespaces = get_first_whitespace(head); def block = Statement("BLOCK", TokS(whitespaces + "{") :: List.Rev(lst) + [TokS(whitespaces + "}")]); loop (tail, block :: acc) } | head :: tail => loop (tail, head :: acc) | [] => List.Rev (acc) } } def eliminate_block2(block : STree, w : string) : STree { match(block.eliminate_jump_2 (jump)) { | [x] => x | xs => Statement("BLOCK", Tok(ExtendedToken(w, "{")) :: List.Rev(xs) + [Tok(ExtendedToken(w, "}"))]); } } def eliminate_block(block : STree, w : antlr.IToken) : STree { eliminate_block2 ( block , ExtendedToken.getWhitespaces (w)); } // propagate RETURN out of a loop def make_when_statement_return (w : antlr.IToken, ns , rs ) : STree { def return_statement = Statement("RETURN",[Tok (ExtendedToken (ExtendedToken.getWhitespaces (w), "return")),TokS(" " + rs),TokS(";")]); Statement("WHEN", [Tok (ExtendedToken (ExtendedToken.getWhitespaces (w),"when")), TokS("( "),TokS(ns),TokS(" )"),return_statement]); } def make_when_statement_goto2 (w : string, ns , label ) : STree { def goto_statement = Statement("GOTO",[make_token (w , "goto"),make_token(" " , label),TokS(";")]); Statement("WHEN", [Tok (ExtendedToken (w,"when")), TokS("( "),make_token("",ns),TokS(" )"),goto_statement]); } def make_when_statement_goto (w : antlr.IToken, ns , label ) : STree { make_when_statement_goto2 (ExtendedToken.getWhitespaces (w) , ns , label); } match((this,jump)) { // -------------- // IF (for gotos) // -------------- | (Statement("IF", [Tok(if_tok) , lp , cond , rp , b1 , else_tok , b2]) , Jump.Goto (l)) => def b1_eliminated = eliminate_block(b1,if_tok); def b2_eliminated = eliminate_block(b2,if_tok); if(b1_eliminated.jump_inside ( jump )) { def ns = Option.UnSome (label_symbols.Get (l)); def (b1_eliminated2, _ , _ , _ , goto) = b1_eliminated.eliminate_jump_in_loop (ns,"","",jump); if (goto) [make_when_statement_goto (if_tok , ns, l), Statement("IF", [Tok(if_tok) , lp , cond , rp , b1_eliminated2 , else_tok , b2])] else assert (false); } else if(b2_eliminated.jump_inside ( jump )) { def ns = Option.UnSome (label_symbols.Get (l)); def (b2_eliminated2, _ , _ , _ , goto) = b2_eliminated.eliminate_jump_in_loop (ns,"","",jump); if (goto) [make_when_statement_goto (if_tok , ns, l), Statement ("IF", [Tok(if_tok) , lp , cond , rp , b1 , else_tok , b2_eliminated2])] else assert (false); } else [ Statement ("IF", [Tok(if_tok) , lp , cond , rp , b1 , else_tok , b2] ) ] // -------- // TRY // -------- | (Statement("TRY", Tok(w) :: block :: rest) , Jump.ReturnBreak ) => def (catch_clauses,finally_clause) = get_catch_clauses (rest); def (catches_modified , jump_in_catch) = walk_through_catches (catch_clauses , false , [] , Jump.ReturnBreak ()); def block_eliminated = eliminate_block(block,w); if(block_eliminated.jump_inside ( Jump.Return ()) || jump_in_catch) { def ns = new_break_loop_symbol (); def rs = new_return_symbol (); def transform_catches (catches : list [STree * bool] , acc : list[STree]) { match(catches) { | [] => List.Rev(acc) | (Statement("GENERAL_CATCH",[Tok(c),block]) , true) :: tail => def (block_eliminated, _ , _ , _ , _) = block.eliminate_jump_in_loop (ns,rs,ns,Jump.Return ()); //assert(ret == true); transform_catches(tail , Statement("GENERAL_CATCH",[Tok(c), block_eliminated ]) :: acc) | (Statement ("SPECIFIC_CATCH", [Tok(c),lb,ty,id,rb,block]), true):: tail => def (block_eliminated, _ , _ , _ , _) = block.eliminate_jump_in_loop (ns,rs,ns,Jump.Return ()); //assert(ret == true); transform_catches(tail , Statement("SPECIFIC_CATCH",[Tok(c), lb, ty , id, rb , block_eliminated ]) :: acc) | (Statement ("SPECIFIC_CATCH", [Tok(c),lb,ty,rb,block]) ,true):: tail=> def (block_eliminated, _ , _ , _ , _) = block.eliminate_jump_in_loop (ns,rs,ns,Jump.Return ()); //assert(ret == true); transform_catches(tail , Statement("SPECIFIC_CATCH",[Tok(c), lb, ty , rb , block_eliminated ]) :: acc) | (Statement("GENERAL_CATCH", _ ) as catch_, false) :: tail | (Statement ("SPECIFIC_CATCH", _ ) as catch_, false) :: tail => transform_catches (tail, catch_ :: acc) | _ => assert (false) } } def (block_eliminated2, ret , con , brk, _) = block_eliminated.eliminate_jump_in_loop (ns,rs,ns,jump); def when_statement = make_when_statement_return (w,ns,rs); def catches_ = Statement("CATCH_CLAUSES",transform_catches(catches_modified,[])); match((ret,con,brk)) { | (true,false,false) => [when_statement, Statement("TRY", Tok(w) :: block_eliminated2 :: [catches_] + finally_clause), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + ns + " = false;"), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + rs + " = Nemerle.Extensions.DefaultValue("+ tp +");")]; | _ => if ( jump_in_catch ) [when_statement, Statement("TRY", Tok(w) :: block_eliminated :: [catches_] + finally_clause), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + ns + " = false;"), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + rs + " = Nemerle.Extensions.DefaultValue("+ tp +");")]; else assert(false) } } else [Statement("TRY", Tok(w) :: block_eliminated :: rest)] // ------------- // LOCK // USING // ------------- | (Statement("LOCK" as name,[Tok(w),lp,expr,rp,block]) , Jump.ReturnBreak) | (Statement("USING" as name,[Tok(w),lp,expr,rp,block]) , Jump.ReturnBreak) => def block_eliminated = eliminate_block(block,w); if(block_eliminated.jump_inside ( jump )) { def ns = new_break_loop_symbol (); def rs = new_return_symbol (); def (block_eliminated2, ret , con , brk, _) = block_eliminated.eliminate_jump_in_loop (ns,rs,ns,jump); match((ret,con,brk)) { | (true,false,false) => def when_statement = make_when_statement_return (w,ns,rs); [when_statement, Statement(name,[Tok(w),lp,expr,rp,block_eliminated2]), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + ns + " = false;"), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + rs + " = Nemerle.Extensions.DefaultValue("+ tp +");")]; | _ => assert(false) } } else [Statement(name,[Tok(w),lp,expr,rp,block_eliminated])] // ------------- // CHECKED // UNCHECKED // ------------- | (Statement("UNCHECKED" as name,[Tok(w),block]), Jump.ReturnBreak) | (Statement("CHECKED" as name,[Tok(w),block]), Jump.ReturnBreak) => def block_eliminated = eliminate_block(block,w); if(block_eliminated.jump_inside ( jump )) { def ns = new_break_loop_symbol (); def rs = new_return_symbol (); def (block_eliminated2, ret , con , brk , _ ) = block_eliminated.eliminate_jump_in_loop (ns,rs,ns,jump); match((ret,con,brk)) { | (true,false,false) => def when_statement = make_when_statement_return (w,ns,rs); [when_statement, Statement(name,[Tok(w),block_eliminated2]), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + ns + " = false;"), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + rs + " = Nemerle.Extensions.DefaultValue("+ tp +");")]; | _ => assert(false) } } else [Statement(name,[Tok(w),block_eliminated])] // ---------------------- // FOREACH loop // FOR loop // DO .. WHILE loop // WHILE loop // ---------------------- | (Statement("FOREACH" as name, Tok(w) :: rest ) , j) when (j is Jump.ReturnBreak) || (j is Jump.Goto (_)) | (Statement("FOR" as name, Tok(w) :: rest ) , j) when (j is Jump.ReturnBreak) || (j is Jump.Goto (_)) | (Statement("WHILE" as name, Tok(w) :: rest ) , j) when (j is Jump.ReturnBreak) || (j is Jump.Goto (_)) | (Statement("DO" as name , Tok(w) :: rest ) , j) when (j is Jump.ReturnBreak) || (j is Jump.Goto (_)) => def get_block (xs) { | [] => None () | Statement(_,_) as block :: _ => Some (block) | _ :: rest => get_block (rest) } def block = match(get_block (rest)) { | None => assert(false) | Some(b) => b } def block_eliminated = eliminate_block(block,w); if(block_eliminated.jump_inside ( jump )) { def ns = match (jump) { | Jump.Goto (l) => Option.UnSome (label_symbols.Get (l)) | _=> new_break_loop_symbol (); } def rs = new_return_symbol (); def cs = new_continue_symbol (); def (block_eliminated2, ret , con , brk, goto) = block_eliminated.eliminate_jump_in_loop (ns,rs,cs,jump); def (loop_modified , loop_unmodified) = match((name,rest)) { | ("WHILE",[lp,TokS(be),rp,_]) => ( Statement("WHILE",[Tok(w),lp,TokS(be + " && !" + ns),rp,block_eliminated2]), Statement("WHILE",[Tok(w),lp,TokS(be),rp,block_eliminated2]) ) | ("DO" ,[_,while_tok,lp,TokS(be),rp,s]) => (Statement("DO",[Tok(w),block_eliminated2,while_tok,lp,TokS(be + " && !" + ns),rp,s]), Statement("DO",[Tok(w),block_eliminated2,while_tok,lp,TokS(be),rp,s]) ) | ("FOR" ,[lp,finit,s1,TokS(fc),s2,fiter,rp,_]) => def new_fc = if (fc == "") "!" + ns; else fc + " && !" + ns; (Statement("FOR" ,[Tok(w),lp,finit,s1,TokS(new_fc),s2,fiter,rp,block_eliminated2]), Statement("FOR" ,[Tok(w),lp,finit,s1,TokS(fc),s2,fiter,rp,block_eliminated2])) | ("FOREACH" , [lp,id,c,t,i,col,rp,_]) => def when_eliminated = Statement ("WHEN",[Tok(ExtendedToken(ExtendedToken.getWhitespaces (w), "when")), TokS(" ("),TokS("!" + ns),TokS(" )"),block_eliminated2]); Message.Warning ("jumps out of foreach are translated to very uneffective code",w); ( Statement("FOREACH",[Tok(w),lp,id,c,t,i,col,rp,when_eliminated]), Statement("FOREACH",[Tok(w),lp,id,c,t,i,col,rp,block_eliminated2])) | _ => assert(false) } if (goto) { def l = match (jump) { | Jump.Goto (lab) => lab | _ => assert (false) } [make_when_statement_goto (w , ns, l), loop_modified]; } else match((ret,con,brk)) { | (false,false,true) => [loop_modified, TokS (ExtendedToken.getWhitespaces (w) + "mutable " + ns + " = false;")]; | (true,false,_) => def when_statement = make_when_statement_return (w,ns,rs); [when_statement, loop_modified, TokS (ExtendedToken.getWhitespaces (w) + "mutable " + ns + " = false;"), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + rs + " = Nemerle.Extensions.DefaultValue("+ tp +");")]; | (false, true ,false) => [loop_unmodified, TokS (ExtendedToken.getWhitespaces (w) + "mutable " + cs + " = false;")] | (true,true,_) => def when_statement = make_when_statement_return (w,ns,rs); [when_statement, loop_unmodified, TokS (ExtendedToken.getWhitespaces (w) + "mutable " + ns + " = false;"), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + cs + " = false;"), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + rs + " = Nemerle.Extensions.DefaultValue("+ tp +");")]; | (false,true,true) => [loop_modified, TokS (ExtendedToken.getWhitespaces (w) + "mutable " + ns + " = false;"), TokS (ExtendedToken.getWhitespaces (w) + "mutable " + cs + " = false;")] | x => System.Console.WriteLine(x); System.Console.WriteLine(goto); assert(false) } } else match((name,rest)) { | ("WHILE",[lp,expr,rp,_]) => [Statement("WHILE",[Tok(w),lp,expr,rp,block_eliminated]) ] | ("DO" ,[_,while_tok,lp,expr,rp,s]) => [Statement("DO",[Tok(w),block_eliminated,while_tok,lp,expr,rp,s]) ] | ("FOR" ,[lp,finit,s1,TokS(fc),s2,fiter,rp,_]) => [Statement("FOR",[Tok(w),lp,finit,s1,TokS(fc),s2,fiter,rp,block_eliminated])] | ("FOREACH" , [lp,id,c,t,i,col,rp,_]) => [Statement("FOREACH",[Tok(w),lp,id,c,t,i,col,rp,block_eliminated])] | _ => System.Console.WriteLine(name); assert(false) } //----------------------------- // BLOCK \ // CHECKED - all for gotos // UNCHECKED / //----------------------------- | (Statement ("CHECKED" as name, [ w , Statement ("BLOCK" , xs)]), Jump.Goto (l) ) | (Statement ("UNCHECKED" as name, [ w , Statement ("BLOCK" , xs)]), Jump.Goto (l) ) | (Statement ("BLOCK" as name, (w :: _) as xs ) , Jump.Goto (l)) => def ( _ , sts , _ ) = cut_off_braces (xs); def ns = Option.UnSome (label_symbols.Get (l)); def block_eliminated = Statement("BLOCK",loop(xs,[])); def (block_eliminated2 , _ ,_ ,_ , goto) = block_eliminated.eliminate_jump_in_loop ( ns , "" , "" , jump); if (goto) if( name == "BLOCK") [make_when_statement_goto2 (get_first_whitespace (sts) , ns, l), block_eliminated2] else [make_when_statement_goto2 (get_first_whitespace (sts) , ns, l), Statement ( name, [ w , block_eliminated2 ])] else if( name == "BLOCK") [block_eliminated] else [Statement ( name, [ w , block_eliminated ])] //----------------------------- // USING \ // LOCK - all for gotos // WHEN / //----------------------------- | (Statement("USING" as name, [Tok(w), lp, expr, rp, Statement ("BLOCK" , xs)]) , Jump.Goto (l)) | (Statement("LOCK" as name, [Tok(w), lp, expr, rp, Statement ("BLOCK" , xs)]) , Jump.Goto (l)) | (Statement("WHEN" as name, [Tok(w), lp, expr, rp, Statement ("BLOCK" , xs)]) , Jump.Goto (l)) => def ( _ , sts , _ ) = cut_off_braces (xs); def ns = Option.UnSome (label_symbols.Get (l)); def block_eliminated = Statement("BLOCK",loop(xs,[])); def (block_eliminated2 , _ ,_ ,_ , goto) = block_eliminated.eliminate_jump_in_loop ( ns , "" , "" , jump); if (goto) [make_when_statement_goto2 (get_first_whitespace (sts) , ns, l), Statement(name, [Tok(w), lp, expr, rp, block_eliminated2])] else [Statement(name, [Tok(w), lp, expr, rp, block_eliminated])] //------------------- // REST //------------------- | (x,_) => match(x) { | Statement(name,trees) => [Statement(name,loop(trees,[]))] | _ => [x] } } } /** * Function used to transform loops containig jump statements * Returns transformed tree and boolean - information, if loop returns a value */ protected eliminate_jump_in_loop (ns : string,rs : string,cs : string, jump : Jump) : STree * bool * bool * bool * bool { // elimnates jumps in CHECKED, UNCHECKED, TRY, USING, LOCK def eliminate_jumps_in_embedded_statement (block_st : STree,tail,c) { def (block_eliminated, ret1 , con1 , brk1 , goto1) = block_st.eliminate_jump_in_loop (ns,rs,cs,Jump.All ()); def whitespaces = ExtendedToken.getWhitespaces (c); def tail_block = Statement("BLOCK", TokS(whitespaces + "{") :: tail + [TokS(whitespaces + "}")]); def (block_el, ret2 , con2 , brk2 , goto2) = tail_block.eliminate_jump_in_loop (ns,rs,cs,Jump.All ()); def when_st = match((ret1,con1,brk1)) { | (true,true,_) | (_,true,true) => Statement("WHEN", [Tok( ExtendedToken (whitespaces ,"when")), TokS("( "),TokS("!" + ns + " && " + "!"+ cs),TokS(" )"),block_el]); | (false,true,false) => Statement("WHEN", [Tok( ExtendedToken (whitespaces ,"when")), TokS("( "),TokS( "!"+ cs),TokS(" )"),block_el]); | (true,false,_) | (_,false,true) => Statement("WHEN", [Tok( ExtendedToken (whitespaces ,"when")), TokS("( "),TokS( "!"+ ns),TokS(" )"),block_el]); | _ => assert(false); } (when_st , block_eliminated , ret1 || ret2 , con1 || con2 , brk1 || brk2 , goto1 || goto2) } // acc2 is for checking, if loop contains return // acc3 is for checking, if loop contains continue // acc4 is for checking, if loop contains break // acc4 is for checking, if loop contains goto def loop (sts : list [STree], acc : list [STree],acc2 : bool,acc3 : bool,acc4 : bool , acc5) : list [STree] * bool * bool * bool * bool { match (sts) { | [] => (List.Rev (acc), acc2 , acc3 , acc4 ,acc5) | Statement ( "WHEN", [ Tok(when_tok) , lp , cond , rp , Statement ("GOTO" , [ _ , Tok(id) , s]) ] ) :: _=> def ws = ExtendedToken.getWhitespaces(when_tok); def l = ExtendedToken.getTextOnly(id); def es = Statement("EXPRESSION_STATEMENT",[make_token (ws , Option.UnSome(label_symbols.Get(l)) + " = true"),s]); (List.Rev ( Statement ( "WHEN", [ Tok(when_tok) , lp , cond , rp , es ] ) :: acc), false,false,false,true) | (Statement ("WHEN",_) as if_st) :: [] | (Statement ("IF",_) as if_st) :: [] => def (if_st_el , ret , con , brk , goto) = if_st.eliminate_jump_in_loop (ns,rs,cs,jump); (List.Rev (if_st_el :: acc),ret || acc2, con || acc3 , brk || acc4 , goto || acc5) | (Statement ("WHEN",[Tok(i),_,_,_,_]) as if_st) :: tail | (Statement ("IF",[Tok(i),_,_,_,_,_,_]) as if_st) :: tail => if (if_st.jump_inside (jump)) { def whitespaces = ExtendedToken.getWhitespaces (i); def (if_st_el, ret1 ,con1 , brk1 , goto1) = if_st.eliminate_jump_in_loop (ns,rs,cs,jump); def block = Statement("BLOCK", TokS(whitespaces + "{") :: tail + [TokS(whitespaces + "}")]); def (block_el,ret2 , con2 , brk2, goto2) = block.eliminate_jump_in_loop (ns,rs,cs,jump); def when_st = Statement("WHEN", [Tok( ExtendedToken (whitespaces ,"when")), TokS("( "),TokS("!"+ ns),TokS(" )"),block_el]); (List.Rev (when_st :: if_st_el :: acc), ret1 || ret2 || acc2 , con1 || con2 || acc3 , brk1 || brk2 || acc4 , goto1 || goto2 || acc5) } else (loop (tail , if_st :: acc, acc2 , acc3 , acc4 , acc5)) | Statement("RETURN",[Tok(b),TokS(expr),s]) :: _ => def new_block = Statement("BLOCK",TokS(ExtendedToken.getWhitespaces(b) + "{") :: [Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + ns + " = true"),s]), Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + rs + " = " + expr),s])] + [TokS(ExtendedToken.getWhitespaces(b) + "}")]); // oh, this is ugly (List.Rev(new_block :: acc),true,false,false,false) | Statement("RETURN",[Tok(b),s]) :: _ => def new_block = Statement("BLOCK",TokS(ExtendedToken.getWhitespaces(b) + "{") :: [Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + ns + " = true"),s]), Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + rs + " = ()"),s])] + [TokS(ExtendedToken.getWhitespaces(b) + "}")]); (List.Rev(new_block :: acc),true,false,false,false) | Statement("BREAK",[Tok(b),s]) :: _ => (List.Rev (Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + ns + " = true"),s]) :: acc) , false , false , true , false) | (Statement("CONTINUE",[Tok(b),s]) as con_st) :: _ => match(jump) { | Jump.All | Jump.Continue => (List.Rev(Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + cs + " = true"),s]) :: acc), false , true , false, false) | _ => (List.Rev(con_st : STree :: acc),false, true , false , false) } | (Statement("BLOCK",_) as block_st) :: tail=> if(block_st.jump_inside(jump)) { def (block_eliminated , ret1 , con1 , brk1 , goto1) = block_st.eliminate_jump_in_loop (ns,rs,cs,jump); def whitespaces = get_first_whitespace (block_eliminated); def tail_block = Statement("BLOCK", TokS(whitespaces + "{") :: tail + [TokS(whitespaces + "}")]); def (block_el, ret2 , con2 , brk2 , goto2) = tail_block.eliminate_jump_in_loop (ns,rs,cs,jump); def when_st = Statement("WHEN", [Tok( ExtendedToken (whitespaces ,"when")), TokS("( "),TokS("!"+ ns),TokS(" )"),block_el]); (List.Rev (when_st :: block_eliminated :: acc), ret1 || ret2 || acc2 , con1 || con2 || acc3 , brk1 || brk2 || acc4 , goto1 || goto2 || acc5) } else (loop (tail , block_st :: acc, acc2 , acc3 , acc4 , acc5)) // --------------------- // CHECKED and UNCHECKED // --------------------- | (Statement(name,[Tok(c),block_st]) as ch_st) :: tail => if(block_st.jump_inside(Jump.All ())) { def (when_st,block_eliminated , ret, con , brk ,goto) = eliminate_jumps_in_embedded_statement(block_st,tail,c); (List.Rev (when_st :: Statement(name,[Tok(c),block_eliminated]):: acc),ret || acc2 , con || acc3 , brk || acc4 , goto || acc5) } else (loop (tail , ch_st :: acc, acc2 , acc3 , acc4 , acc5)) // --- // TRY // --- | (Statement("TRY", Tok(t) :: block_st :: rest) as try_st) :: tail => def (catch_clauses,finally_clause) = get_catch_clauses (rest); mutable ret1 = false; mutable con1 = false; mutable brk1 = false; mutable goto1 = false; def transform_catches (catches : list [STree * bool] , acc : list[STree]) { match(catches) { | [] => List.Rev(acc) | (Statement("GENERAL_CATCH",[Tok(c),block]) , true) :: tail => def (block_eliminated, ret , con , brk , goto) = block.eliminate_jump_in_loop (ns,rs,ns,Jump.All ()); ret1 = ret || ret1; con1 = con || con1; brk1 = brk || brk1; goto1 = goto || goto1; transform_catches(tail , Statement("GENERAL_CATCH",[Tok(c), block_eliminated ]) :: acc) | (Statement ("SPECIFIC_CATCH", [Tok(c),lb,ty,id,rb,block]), true):: tail => def (block_eliminated, ret , con , brk , goto) = block.eliminate_jump_in_loop (ns,rs,ns,Jump.All ()); ret1 = ret || ret1; con1 = con || con1; brk1 = brk || brk1; goto1 = goto || goto1; transform_catches(tail , Statement("SPECIFIC_CATCH",[Tok(c), lb, ty , id, rb , block_eliminated ]) :: acc) | (Statement ("SPECIFIC_CATCH", [Tok(c),lb,ty,rb,block]) ,true):: tail=> def (block_eliminated, ret , con , brk , goto) = block.eliminate_jump_in_loop (ns,rs,ns,Jump.All ()); ret1 = ret || ret1; con1 = con || con1; brk1 = brk || brk1; goto1 = goto || goto1; transform_catches(tail , Statement("SPECIFIC_CATCH",[Tok(c), lb, ty , rb , block_eliminated ]) :: acc) | (Statement("GENERAL_CATCH", _ ) as catch_, false) :: tail | (Statement ("SPECIFIC_CATCH", _ ) as catch_, false) :: tail => transform_catches (tail, catch_ :: acc) | _ => assert (false) } } def (catches_modified , jump_in_catch) = walk_through_catches (catch_clauses , false , [] , Jump.All ()); def catches_ = Statement("CATCH_CLAUSES",transform_catches(catches_modified,[])); if(block_st.jump_inside(Jump.All ())) { def (when_st,block_eliminated , ret, con , brk, goto) = eliminate_jumps_in_embedded_statement(block_st,tail,t); (List.Rev (when_st :: (Statement("TRY",Tok(t) :: block_eliminated :: rest) ) :: acc), ret || acc2 || ret1, con || acc3 || con1, brk || acc4 || brk1, goto || acc5 || goto1) } else if(jump_in_catch) { def (when_st, _ , _ , _ , _ , _) = eliminate_jumps_in_embedded_statement(block_st,tail,t); (List.Rev (when_st :: (Statement("TRY",Tok(t) :: block_st :: [catches_] + finally_clause) ) :: acc), acc2 || ret1, acc3 || con1, acc4 || brk1, acc5 || goto1) } else (loop (tail , try_st :: acc, acc2 , acc3 , acc4 , acc5)) // -------------- // LOCK and USING // -------------- | (Statement(name,[Tok(c),lp,expr,rp,block_st]) as st) :: tail => if(block_st.jump_inside(Jump.All ())) { def (when_st,block_eliminated , ret, con , brk, goto) = eliminate_jumps_in_embedded_statement(block_st,tail,c); (List.Rev (when_st :: Statement(name,[Tok(c),lp,expr,rp,block_eliminated]):: acc), ret || acc2 , con || acc3 , brk || acc4 , goto || acc5) } else (loop (tail , st :: acc, acc2 , acc3 , acc4 , acc5)) | head :: tail => (loop (tail , head :: acc, acc2 , acc3 , acc4 , acc5)) } } match(this) { | Statement ( "WHEN", [ Tok(when_tok) , lp , cond , rp , Statement ("GOTO" , [ _ , Tok(id) , s]) ] )=> def ws = ExtendedToken.getWhitespaces(when_tok); def l = ExtendedToken.getTextOnly(id); def es = Statement("EXPRESSION_STATEMENT",[make_token (ws , Option.UnSome(label_symbols.Get(l)) + " = true"),s]); ( Statement ( "WHEN", [ Tok(when_tok) , lp , cond , rp , es ] ), false,false,false,true) | Statement("IF",[i,lp,be,rp,st1,e,st2]) => mutable st1_el = null; mutable st2_el = null; match (st1.eliminate_jump_2 (jump)) { | [tree] => st1_el = tree | _ => assert(false); } match (st2.eliminate_jump_2 (jump)) { | [tree] => st2_el = tree | _ => assert(false); } if (st1.jump_inside (jump) && st2.jump_inside (jump)) { def (st1_el, ret1 , con1 , brk1 , goto1)= st1.eliminate_jump_in_loop (ns,rs,cs,jump); def (st2_el, ret2 , con2 , brk2 , goto2)= st2.eliminate_jump_in_loop (ns,rs,cs,jump); (Statement("IF",[i,lp,be,rp,st1_el,e,st2_el]),ret1 || ret2 , con1 || con2 , brk1 || brk2 , goto1 || goto2) } else if (st1.jump_inside (jump)) { def (st1_el, ret , con , brk, goto)= st1.eliminate_jump_in_loop (ns,rs,cs,jump); (Statement("IF",[i,lp,be,rp,st1_el,e,st2_el]), ret , con , brk , goto) } else if (st2.jump_inside (jump)) { def (st2_el , ret , con , brk, goto)= st2.eliminate_jump_in_loop (ns,rs,cs,jump); (Statement("IF",[i,lp,be,rp,st1_el,e,st2_el]), ret , con , brk, goto) } else (Statement("IF",[i,lp,be,rp,st1_el,e,st2_el]),false,false,false,false) | Statement("WHEN",[w,lp,be,rp,st]) => def (st_el, ret , con , brk, goto)= st.eliminate_jump_in_loop (ns,rs,cs,jump); (Statement("WHEN",[w,lp,be,rp,st_el]), ret , con, brk, goto) | Statement("BREAK",[Tok(b),s]) => (Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + ns + " = true"),s]),false,false,true,false) | Statement("RETURN",[Tok(b),s]) => (Statement("BLOCK",TokS(ExtendedToken.getWhitespaces(b) + "{") :: [Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + ns + " = true"),s]), Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + rs + " = ()"),s])] + [TokS(ExtendedToken.getWhitespaces(b) + "}")]),true, false, false, false) | Statement("RETURN",[Tok(b),TokS(expr),s]) => (Statement("BLOCK",TokS(ExtendedToken.getWhitespaces(b) + "{") :: [Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + ns + " = true"),s]), Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + rs + " = " + expr),s])] + [TokS(ExtendedToken.getWhitespaces(b) + "}")]),true , false , false, false) | Statement ( "CONTINUE" , [Tok(b),s]) as con_st => match(jump) { | Jump.All | Jump.Continue => (Statement("EXPRESSION_STATEMENT",[TokS(ExtendedToken.getWhitespaces(b) + cs + " = true"),s]), false , true , false , false) | _ => (con_st,false, true , false , false) } | Statement("BLOCK",stmts) => def (lbrace,statements,rbrace) = cut_off_braces (stmts); def (block_eliminated, ret , con , brk, goto) = loop (statements,[], false , false , false, false); (Statement("BLOCK",lbrace :: block_eliminated + [rbrace]), ret , con , brk ,goto) | x => match(x.eliminate_jump_2 (jump)) { | [y] => (y,false,false,false,false) | _ => assert(false); } } } /** * Returns true, if statement or one of substatement contains specified jump */ /*protected jump_inside (jump : Jump) : bool { jump_inside ( jump , None ()); }*/ protected jump_inside (jump : Jump) : bool { def loop2(xs : list [STree],j :Jump) : bool { match(xs) { | head :: tail => if(head.jump_inside (j)) true else loop2(tail,j) | _ => false } } def loop(xs : list [STree]) : bool { loop2 (xs,jump); } match(jump) { | Jump.All when (match (this) { | Statement("RETURN",_) | Statement("BREAK",_) | Statement("CONTINUE",_) | Statement ("WHEN",[_,_,_,_, Statement ("GOTO",_) ]) => true | _ => false }) => true | Jump.ReturnBreak when (match (this) { | Statement("RETURN",_) | Statement("BREAK",_) => true | _ => false }) => true | Jump.Return when this is Statement("RETURN",_) => true | Jump.Break when this is Statement("BREAK",_) => true | Jump.Continue when this is Statement("CONTINUE",_) => true | Jump.Goto (label) when this is Statement ("WHEN",[_,_,_,_, Statement ("GOTO", _ ) ]) => match ( this ) { | Statement ("WHEN",[_,_,_,_, Statement ("GOTO", [_ , Tok (id), _] ) ]) => ExtendedToken.getTextOnly (id) == label | _ => false } | _ => match (this) { | Statement("BLOCK",xs) => loop(xs); | Statement("IF",[_,_,_,_,st1,_,st2]) => st1.jump_inside (jump) || st2.jump_inside (jump) | Statement("WHEN",[_,_,_,_,st]) => st.jump_inside (jump) | Statement("SWITCH",[_,_,_,_,Statement("SWITCH_BLOCK",xs)]) => if(jump is Jump.ReturnBreak) loop2(xs , Jump.Return ()) else if(jump is Jump.Break) false else loop(xs) | Statement("SWITCH_SECTION",[_,Statement("SWITCH_SECTION_STATEMENTS",xs)]) => loop(xs) | Statement("TRY",_ :: block :: _) | Statement("USING_STATEMENT",[_,_,_,_,block]) | Statement("LOCK",[_,_,_,_,block]) | Statement("CHECKED",[_,block]) | Statement("UNCHECKED",[_,block]) => block.jump_inside (Jump.All ()) | Statement ("WHILE", [_ , _ , _ , _ , block]) when jump is Jump.Goto (_) | Statement("DO", _ :: block :: _) when jump is Jump.Goto (_) => block.jump_inside (jump) | _ => false } } } /* -- SYMBOL GENERATION ----------------------------------------- */ new_symbol (suffix : string) : string { ++ symbol_count; "temp_" + symbol_count.ToString() + suffix } private new_break_loop_symbol () : string { new_symbol ("_break_loop_") } private new_return_symbol () : string { new_symbol ("_return_") } private new_continue_symbol () : string { new_symbol ("_continue_") } public static set_type (tpe : string) : void { tp = tpe; } private static mutable tp : string = ""; private static mutable symbol_count : int = 0; } }