X-Git-Url: http://nitlanguage.org diff --git a/src/scope.nit b/src/scope.nit index 8914b31..83c5fe4 100644 --- a/src/scope.nit +++ b/src/scope.nit @@ -17,30 +17,34 @@ # Identification and scping of local variables and labels. module scope -import parser -import toolcontext +import phase + +redef class ToolContext + var scope_phase: Phase = new ScopePhase(self, null) +end + +private class ScopePhase + super Phase + redef fun process_npropdef(npropdef) do npropdef.do_scope(toolcontext) +end + # A local variable (including parameters, automatic variables and self) class Variable # The name of the variable (as used in the program) var name: String - # Alias of `name' + # Alias of `name` redef fun to_s do return self.name end -# A local variable associated to a closure definition -class ClosureVariable - super Variable -end - # Mark where break and continue will branch. -# marks are either associated with a label of with a for_loop structure +# Marks are either associated with a label of with a for_loop structure class EscapeMark # The name of the label (unless the mark is an anonymous loop mark) var name: nullable String - # Is the mark atached to a loop (loop, while, for, closure) + # Is the mark atached to a loop (loop, while, for) # Such a mark is a candidate to a labelless 'continue' or 'break' var for_loop: Bool @@ -52,10 +56,9 @@ class EscapeMark end # Visit a npropdef and: -# * Identify variables, closures and labels +# * Identify variables and labels # * Associate each break and continue to its escapemark -# * Transform ACallFormExpr that access a variable into AVarFormExpr -# * Transform ACallFormExpr that call a closure into AClosureCallExpr +# * Transform `ACallFormExpr` that access a variable into `AVarFormExpr` # FIXME: Should the class be private? private class ScopeVisitor super Visitor @@ -63,13 +66,15 @@ private class ScopeVisitor # The tool context used to display errors var toolcontext: ToolContext + var selfvariable: Variable = new Variable("self") + init(toolcontext: ToolContext) do self.toolcontext = toolcontext scopes.add(new Scope) end - # All stacked scope. `scopes.first' is the current scope + # All stacked scope. `scopes.first` is the current scope private var scopes: List[Scope] = new List[Scope] # Regiter a local variable. @@ -86,7 +91,7 @@ private class ScopeVisitor return true end - # Look for a variable named `name'. + # Look for a variable named `name`. # Return null if no such a variable is found. fun search_variable(name: String): nullable Variable do @@ -99,13 +104,13 @@ private class ScopeVisitor return null end - redef fun visit(n: nullable ANode) + redef fun visit(n) do n.accept_scope_visitor(self) end - # Enter in a statement block `node' as inside a new scope. - # The block can be optionally attached to an `escapemark'. + # Enter in a statement block `node` as inside a new scope. + # The block can be optionally attached to an `escapemark`. private fun enter_visit_block(node: nullable AExpr, escapemark: nullable EscapeMark) do if node == null then return @@ -116,7 +121,7 @@ private class ScopeVisitor scopes.shift end - # Look for a label `name'. + # Look for a label `name`. # Return nulll if no such a label is found. private fun search_label(name: String): nullable EscapeMark do @@ -133,13 +138,21 @@ private class ScopeVisitor # Display an error on toolcontext if a label with the same name is masked. private fun make_escape_mark(nlabel: nullable ALabel, for_loop: Bool): EscapeMark do - assert named_or_for_loop: nlabel != null or for_loop var name: nullable String if nlabel != null then - name = nlabel.n_id.text - var found = self.search_label(name) - if found != null then - self.error(nlabel, "Syntax error: label {name} already defined.") + var nid = nlabel.n_id + if nid == null then + var res = search_label("") + if res != null then + self.error(nlabel, "Syntax error: anonymous label already defined.") + end + name = "" + else + name = nid.text + var found = self.search_label(name) + if found != null then + self.error(nlabel, "Syntax error: label {name} already defined.") + end end else name = null @@ -150,13 +163,22 @@ private class ScopeVisitor # Look for an escape mark optionally associated with a label. # If a label is given, the the escapemark of this label is returned. - # If there is no label, the nearest escapemark that is `for loop' ir returned. + # If there is no label, the nearest escapemark that is `for loop` is returned. # If there is no valid escapemark, then an error is displayed ans null is returned. # Return nulll if no such a label is found. private fun get_escapemark(node: ANode, nlabel: nullable ALabel): nullable EscapeMark do if nlabel != null then - var name = nlabel.n_id.text + var nid = nlabel.n_id + if nid == null then + var res = search_label("") + if res == null then + self.error(nlabel, "Syntax error: invalid anonymous label.") + return null + end + return res + end + var name = nid.text var res = search_label(name) if res == null then self.error(nlabel, "Syntax error: invalid label {name}.") @@ -166,7 +188,7 @@ private class ScopeVisitor else for scope in scopes do var res = scope.escapemark - if res != null and res.for_loop then + if res != null then return res end end @@ -226,28 +248,26 @@ redef class AParam end end -redef class AClosureDecl - # The variable associated with the closure declaration - var variable: nullable ClosureVariable +redef class AVardeclExpr + # The variable associated with the variable declaration + var variable: nullable Variable redef fun accept_scope_visitor(v) do + super var nid = self.n_id - var variable = new ClosureVariable(nid.text) + var variable = new Variable(nid.text) v.register_variable(nid, variable) self.variable = variable end end -redef class AVardeclExpr - # The variable associated with the variable declaration +redef class ASelfExpr + # The variable associated with the self reciever var variable: nullable Variable redef fun accept_scope_visitor(v) do super - var nid = self.n_id - var variable = new Variable(nid.text) - v.register_variable(nid, variable) - self.variable = variable + self.variable = v.selfvariable end end @@ -286,9 +306,7 @@ redef class ADoExpr var escapemark: nullable EscapeMark redef fun accept_scope_visitor(v) do - if n_label != null then - self.escapemark = v.make_escape_mark(n_label, false) - end + self.escapemark = v.make_escape_mark(n_label, false) v.enter_visit_block(n_block, self.escapemark) end end @@ -369,17 +387,12 @@ redef class ACallFormExpr var variable = v.search_variable(name) if variable != null then var n: AExpr - if variable isa ClosureVariable then - n = new AClosureCallExpr.init_aclosurecallexpr(n_id, n_args, n_closure_defs) - n.variable = variable - else - if not n_args.n_exprs.is_empty or n_args isa AParExprs then - v.error(self, "Error: {name} is variable, not a function.") - return - end - n = variable_create(variable) - n.variable = variable + if not n_args.n_exprs.is_empty or n_args isa AParExprs then + v.error(self, "Error: {name} is variable, not a function.") + return end + n = variable_create(variable) + n.variable = variable replace_with(n) n.accept_scope_visitor(v) return @@ -413,36 +426,3 @@ redef class ACallReassignExpr return new AVarReassignExpr.init_avarreassignexpr(n_id, n_assign_op, n_value) end end - -redef class AClosureCallExpr - # the associate closure variable - var variable: nullable ClosureVariable -end - -redef class AClosureDef - # The automatic variables in order - var variables: nullable Array[Variable] - - # The escape mark used with the closure - var escapemark: nullable EscapeMark - - redef fun accept_scope_visitor(v) - do - v.scopes.unshift(new Scope) - - var variables = new Array[Variable] - self.variables = variables - - for nid in self.n_ids do - var va = new Variable(nid.text) - v.register_variable(nid, va) - variables.add(va) - end - - var escapemark = v.make_escape_mark(n_label, true) - self.escapemark = escapemark - v.enter_visit_block(self.n_expr, escapemark) - - v.scopes.shift - end -end