From: Jean Privat Date: Sat, 11 Oct 2014 02:33:38 +0000 (-0400) Subject: scope: create two escapemaks in loops X-Git-Tag: v0.6.10~30^2~4 X-Git-Url: http://nitlanguage.org scope: create two escapemaks in loops Signed-off-by: Jean Privat --- diff --git a/src/astbuilder.nit b/src/astbuilder.nit index 8e17b4e..f0e0c95 100644 --- a/src/astbuilder.nit +++ b/src/astbuilder.nit @@ -176,7 +176,7 @@ redef class ADoExpr private init make do _n_kwdo = new TKwdo - escapemark = new EscapeMark(null, false) + escapemark = new EscapeMark(null) end # Make a new break expression of the given do @@ -184,7 +184,7 @@ redef class ADoExpr do var escapemark = self.escapemark if escapemark == null then - escapemark = new EscapeMark(null, false) + escapemark = new EscapeMark(null) self.escapemark = escapemark end return new ABreakExpr.make(escapemark) diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index a6f6afa..58cb346 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -1266,6 +1266,14 @@ abstract class AbstractCompilerVisitor return name end + # Insert a C label for associated with an escapemark + fun add_escape_label(e: nullable EscapeMark) + do + if e == null then return + if e.escapes.is_empty then return + add("BREAK_{escapemark_name(e)}: (void)0;") + end + private var escapemark_names = new HashMap[EscapeMark, String] # Return a "const char*" variable associated to the classname of the dynamic type of an object @@ -2430,11 +2438,7 @@ redef class ASelfExpr redef fun expr(v) do return v.frame.arguments.first end -redef class AContinueExpr - redef fun stmt(v) do v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};") -end - -redef class ABreakExpr +redef class AEscapeExpr redef fun stmt(v) do v.add("goto BREAK_{v.escapemark_name(self.escapemark)};") end @@ -2497,10 +2501,7 @@ redef class ADoExpr redef fun stmt(v) do v.stmt(self.n_block) - var escapemark = self.escapemark - if escapemark != null then - v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;") - end + v.add_escape_label(break_mark) end end @@ -2511,9 +2512,9 @@ redef class AWhileExpr var cond = v.expr_bool(self.n_expr) v.add("if (!{cond}) break;") v.stmt(self.n_block) - v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;") + v.add_escape_label(continue_mark) v.add("\}") - v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;") + v.add_escape_label(break_mark) end end @@ -2522,9 +2523,9 @@ redef class ALoopExpr do v.add("for(;;) \{") v.stmt(self.n_block) - v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;") + v.add_escape_label(continue_mark) v.add("\}") - v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;") + v.add_escape_label(break_mark) end end @@ -2554,12 +2555,12 @@ redef class AForExpr v.stmt(self.n_block) - v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;") + v.add_escape_label(continue_mark) var succ = v.send(v.get_property("successor", variable.mtype), [variable, one]) assert succ != null v.assign(variable, succ) v.add("\}") - v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;") + v.add_escape_label(break_mark) return end @@ -2595,12 +2596,12 @@ redef class AForExpr abort end v.stmt(self.n_block) - v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;") + v.add_escape_label(continue_mark) var next_meth = self.method_next assert next_meth != null v.compile_callsite(next_meth, [it]) v.add("\}") - v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;") + v.add_escape_label(break_mark) var method_finish = self.method_finish if method_finish != null then diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index 92b658d..f557227 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -112,43 +112,26 @@ class NaiveInterpreter # Set this mark to skip the evaluation until the end of the specified method frame var returnmark: nullable Frame = null - # Is a break executed? - # Set this mark to skip the evaluation until a labeled statement catch it with `is_break` - var breakmark: nullable EscapeMark = null - - # Is a continue executed? - # Set this mark to skip the evaluation until a labeled statement catch it with `is_continue` - var continuemark: nullable EscapeMark = null + # Is a break or a continue executed? + # Set this mark to skip the evaluation until a labeled statement catch it with `is_escape` + var escapemark: nullable EscapeMark = null # Is a return or a break or a continue executed? # Use this function to know if you must skip the evaluation of statements - fun is_escaping: Bool do return returnmark != null or breakmark != null or continuemark != null + fun is_escaping: Bool do return returnmark != null or escapemark != null # The value associated with the current return/break/continue, if any. # Set the value when you set a escapemark. # Read the value when you catch a mark or reach the end of a method var escapevalue: nullable Instance = null - # If there is a break and is associated with `escapemark`, then return true an clear the mark. - # If there is no break or if `escapemark` is null then return false. - # Use this function to catch a potential break. - fun is_break(escapemark: nullable EscapeMark): Bool - do - if escapemark != null and self.breakmark == escapemark then - self.breakmark = null - return true - else - return false - end - end - - # If there is a continue and is associated with `escapemark`, then return true an clear the mark. - # If there is no continue or if `escapemark` is null then return false. - # Use this function to catch a potential continue. - fun is_continue(escapemark: nullable EscapeMark): Bool + # If there is a break/continue and is associated with `escapemark`, then return true and clear the mark. + # If there is no break/continue or if `escapemark` is null then return false. + # Use this function to catch a potential break/continue. + fun is_escape(escapemark: nullable EscapeMark): Bool do - if escapemark != null and self.continuemark == escapemark then - self.continuemark = null + if escapemark != null and self.escapemark == escapemark then + self.escapemark = null return true else return false @@ -1199,20 +1182,7 @@ redef class ASelfExpr end end -redef class AContinueExpr - redef fun stmt(v) - do - var ne = self.n_expr - if ne != null then - var i = v.expr(ne) - if i == null then return - v.escapevalue = i - end - v.continuemark = self.escapemark - end -end - -redef class ABreakExpr +redef class AEscapeExpr redef fun stmt(v) do var ne = self.n_expr @@ -1221,7 +1191,7 @@ redef class ABreakExpr if i == null then return v.escapevalue = i end - v.breakmark = self.escapemark + v.escapemark = self.escapemark end end @@ -1287,7 +1257,7 @@ redef class ADoExpr redef fun stmt(v) do v.stmt(self.n_block) - v.is_break(self.escapemark) # Clear the break (if any) + v.is_escape(self.break_mark) # Clear the break (if any) end end @@ -1299,8 +1269,8 @@ redef class AWhileExpr if cond == null then return if not cond.is_true then return v.stmt(self.n_block) - if v.is_break(self.escapemark) then return - v.is_continue(self.escapemark) # Clear the break + if v.is_escape(self.break_mark) then return + v.is_escape(self.continue_mark) # Clear the break if v.is_escaping then return end end @@ -1311,8 +1281,8 @@ redef class ALoopExpr do loop v.stmt(self.n_block) - if v.is_break(self.escapemark) then return - v.is_continue(self.escapemark) # Clear the break + if v.is_escape(self.break_mark) then return + v.is_escape(self.continue_mark) # Clear the break if v.is_escaping then return end end @@ -1344,8 +1314,8 @@ redef class AForExpr abort end v.stmt(self.n_block) - if v.is_break(self.escapemark) then break - v.is_continue(self.escapemark) # Clear the break + if v.is_escape(self.break_mark) then break + v.is_escape(self.continue_mark) # Clear the break if v.is_escaping then break v.callsite(method_next, [iter]) end diff --git a/src/semantize/flow.nit b/src/semantize/flow.nit index 65f5c7b..733e3d3 100644 --- a/src/semantize/flow.nit +++ b/src/semantize/flow.nit @@ -165,7 +165,7 @@ private class FlowVisitor fun merge_continues_to(before_loop: FlowContext, escapemark: nullable EscapeMark) do if escapemark == null then return - for b in escapemark.continues do + for b in escapemark.escapes do var before = b.before_flow_context if before == null then continue # Forward error before_loop.add_loop(before) @@ -175,7 +175,7 @@ private class FlowVisitor fun merge_breaks(escapemark: nullable EscapeMark) do if escapemark == null then return - for b in escapemark.breaks do + for b in escapemark.escapes do var before = b.before_flow_context if before == null then continue # Forward error self.make_merge_flow(self.current_flow_context, before) @@ -346,7 +346,7 @@ redef class ADoExpr redef fun accept_flow_visitor(v) do super - v.merge_breaks(self.escapemark) + v.merge_breaks(self.break_mark) end end @@ -396,10 +396,10 @@ redef class AWhileExpr var after_block = v.current_flow_context before_loop.add_loop(after_block) - v.merge_continues_to(after_block, self.escapemark) + v.merge_continues_to(after_block, self.continue_mark) v.current_flow_context = after_expr.when_false - v.merge_breaks(self.escapemark) + v.merge_breaks(self.break_mark) end end @@ -413,10 +413,10 @@ redef class ALoopExpr var after_block = v.current_flow_context before_loop.add_loop(after_block) - v.merge_continues_to(after_block, self.escapemark) + v.merge_continues_to(after_block, self.continue_mark) v.make_unreachable_flow - v.merge_breaks(self.escapemark) + v.merge_breaks(self.break_mark) end end @@ -432,10 +432,10 @@ redef class AForExpr var after_block = v.current_flow_context before_loop.add_loop(after_block) - v.merge_continues_to(after_block, self.escapemark) + v.merge_continues_to(after_block, self.continue_mark) v.make_merge_flow(v.current_flow_context, before_loop) - v.merge_breaks(self.escapemark) + v.merge_breaks(self.break_mark) end end diff --git a/src/semantize/scope.nit b/src/semantize/scope.nit index 30aade4..00702d0 100644 --- a/src/semantize/scope.nit +++ b/src/semantize/scope.nit @@ -50,15 +50,12 @@ class EscapeMark # The name of the label (unless the mark is an anonymous loop mark) var name: nullable String - # Is the mark attached to a loop (loop, while, for) - # Such a mark is a candidate to a labelless 'continue' or 'break' - var for_loop: Bool + # The associated `continue` mark, if any. + # If the mark attached to a loop (loop, while, for), a distinct mark is used. + private var continue_mark: nullable EscapeMark = null - # Each 'continue' attached to the mark - var continues = new Array[AContinueExpr] - - # Each 'break' attached to the mark - var breaks = new Array[ABreakExpr] + # Each break/continue attached to the mark + var escapes = new Array[AEscapeExpr] end # Visit a npropdef and: @@ -81,7 +78,7 @@ private class ScopeVisitor end # All stacked scope. `scopes.first` is the current scope - private var scopes = new List[Scope] + var scopes = new List[Scope] # Shift and check the last scope fun shift_scope @@ -176,7 +173,8 @@ private class ScopeVisitor else name = null end - var res = new EscapeMark(name, for_loop) + var res = new EscapeMark(name) + if for_loop then res.continue_mark = new EscapeMark(name) return res end @@ -303,10 +301,12 @@ redef class AContinueExpr super var escapemark = v.get_escapemark(self, self.n_label) if escapemark == null then return # Skip error - if not escapemark.for_loop then + escapemark = escapemark.continue_mark + if escapemark == null then v.error(self, "Error: cannot 'continue', only 'break'.") + return end - escapemark.continues.add(self) + escapemark.escapes.add(self) self.escapemark = escapemark end end @@ -317,19 +317,20 @@ redef class ABreakExpr super var escapemark = v.get_escapemark(self, self.n_label) if escapemark == null then return # Skip error - escapemark.breaks.add(self) + escapemark.escapes.add(self) self.escapemark = escapemark end end redef class ADoExpr - # The escape mark associated with the 'do' block - var escapemark: nullable EscapeMark + # The break escape mark associated with the 'do' block + var break_mark: nullable EscapeMark + redef fun accept_scope_visitor(v) do - self.escapemark = v.make_escape_mark(n_label, false) - v.enter_visit_block(n_block, self.escapemark) + self.break_mark = v.make_escape_mark(n_label, false) + v.enter_visit_block(n_block, self.break_mark) end end @@ -343,24 +344,34 @@ redef class AIfExpr end redef class AWhileExpr - # The escape mark associated with the 'while' - var escapemark: nullable EscapeMark + # The break escape mark associated with the 'while' + var break_mark: nullable EscapeMark + + # The continue escape mark associated with the 'while' + var continue_mark: nullable EscapeMark + redef fun accept_scope_visitor(v) do var escapemark = v.make_escape_mark(n_label, true) - self.escapemark = escapemark + self.break_mark = escapemark + self.continue_mark = escapemark.continue_mark v.enter_visit(n_expr) v.enter_visit_block(n_block, escapemark) end end redef class ALoopExpr - # The escape mark associated with the 'loop' - var escapemark: nullable EscapeMark + # The break escape mark associated with the 'loop' + var break_mark: nullable EscapeMark + + # The continue escape mark associated with the 'loop' + var continue_mark: nullable EscapeMark + redef fun accept_scope_visitor(v) do var escapemark = v.make_escape_mark(n_label, true) - self.escapemark = escapemark + self.break_mark = escapemark + self.continue_mark = escapemark.continue_mark v.enter_visit_block(n_block, escapemark) end end @@ -369,8 +380,11 @@ redef class AForExpr # The automatic variables in order var variables: nullable Array[Variable] - # The escape mark associated with the 'for' - var escapemark: nullable EscapeMark + # The break escape mark associated with the 'for' + var break_mark: nullable EscapeMark + + # The continue escape mark associated with the 'for' + var continue_mark: nullable EscapeMark redef fun accept_scope_visitor(v) do @@ -389,7 +403,8 @@ redef class AForExpr end var escapemark = v.make_escape_mark(n_label, true) - self.escapemark = escapemark + self.break_mark = escapemark + self.continue_mark = escapemark.continue_mark v.enter_visit_block(n_block, escapemark) v.shift_scope