Visit a npropdef and:

  • Identify variables and labels
  • Associate each break and continue to its escapemark
  • Transform ACallFormExpr that access a variable into AVarFormExpr

    FIXME: Should the class be private?

Introduced properties

private var _propdef: APropdef

nitc :: ScopeVisitor :: _propdef

The analysed property
private var _scopes: List[Scope]

nitc :: ScopeVisitor :: _scopes

All stacked scope. scopes.first is the current scope
private var _toolcontext: ToolContext

nitc :: ScopeVisitor :: _toolcontext

The tool context used to display errors
init defaultinit(toolcontext: ToolContext, propdef: APropdef)

nitc :: ScopeVisitor :: defaultinit

private fun enter_visit_block(node: nullable AExpr, escapemark: nullable EscapeMark)

nitc :: ScopeVisitor :: enter_visit_block

Enter in a statement block node as inside a new scope.
private fun error(node: ANode, message: String)

nitc :: ScopeVisitor :: error

Display an error
private fun get_escapemark(node: ANode, nlabel: nullable ALabel): nullable EscapeMark

nitc :: ScopeVisitor :: get_escapemark

Look for an escape mark optionally associated with a label.
private fun make_escape_mark(nlabel: nullable ALabel, for_loop: Bool): EscapeMark

nitc :: ScopeVisitor :: make_escape_mark

Create a new escape mark (possibly with a label)
private fun propdef: APropdef

nitc :: ScopeVisitor :: propdef

The analysed property
private fun propdef=(propdef: APropdef)

nitc :: ScopeVisitor :: propdef=

The analysed property
private fun register_variable(node: ANode, variable: Variable): Bool

nitc :: ScopeVisitor :: register_variable

Register a local variable.
private fun scopes: List[Scope]

nitc :: ScopeVisitor :: scopes

All stacked scope. scopes.first is the current scope
private fun scopes=(scopes: List[Scope])

nitc :: ScopeVisitor :: scopes=

All stacked scope. scopes.first is the current scope
private fun search_label(name: String): nullable EscapeMark

nitc :: ScopeVisitor :: search_label

Look for a label name.
private fun search_variable(name: String): nullable Variable

nitc :: ScopeVisitor :: search_variable

Look for a variable named name.
private fun selfvariable=(selfvariable: Variable)

nitc :: ScopeVisitor :: selfvariable=

private fun shift_scope

nitc :: ScopeVisitor :: shift_scope

Shift and check the last scope
private fun toolcontext: ToolContext

nitc :: ScopeVisitor :: toolcontext

The tool context used to display errors
private fun toolcontext=(toolcontext: ToolContext)

nitc :: ScopeVisitor :: toolcontext=

The tool context used to display errors

Redefined properties

redef type SELF: ScopeVisitor

nitc $ ScopeVisitor :: SELF

Type of this instance, automatically specialized in every class
redef init init

nitc $ ScopeVisitor :: init

redef fun visit(n: ANode)

nitc $ ScopeVisitor :: visit

What the visitor do when a node is visited

All properties

fun !=(other: nullable Object): Bool

core :: Object :: !=

Have self and other different values?
fun ==(other: nullable Object): Bool

core :: Object :: ==

Have self and other the same value?
type CLASS: Class[SELF]

core :: Object :: CLASS

The type of the class of self.
type SELF: Object

core :: Object :: SELF

Type of this instance, automatically specialized in every class
private var _current_node: nullable ANode

nitc :: Visitor :: _current_node

The current visited node
private var _propdef: APropdef

nitc :: ScopeVisitor :: _propdef

The analysed property
private var _scopes: List[Scope]

nitc :: ScopeVisitor :: _scopes

All stacked scope. scopes.first is the current scope
private var _toolcontext: ToolContext

nitc :: ScopeVisitor :: _toolcontext

The tool context used to display errors
protected fun class_factory(name: String): CLASS

core :: Object :: class_factory

Implementation used by get_class to create the specific class.
fun class_name: String

core :: Object :: class_name

The class name of the object.
fun current_node: nullable ANode

nitc :: Visitor :: current_node

The current visited node
fun current_node=(current_node: nullable ANode)

nitc :: Visitor :: current_node=

The current visited node
init defaultinit(toolcontext: ToolContext, propdef: APropdef)

nitc :: ScopeVisitor :: defaultinit

fun enter_visit(e: nullable ANode)

nitc :: Visitor :: enter_visit

Ask the visitor to visit a given node.
private fun enter_visit_block(node: nullable AExpr, escapemark: nullable EscapeMark)

nitc :: ScopeVisitor :: enter_visit_block

Enter in a statement block node as inside a new scope.
private fun error(node: ANode, message: String)

nitc :: ScopeVisitor :: error

Display an error
fun get_class: CLASS

core :: Object :: get_class

The meta-object representing the dynamic type of self.
private fun get_escapemark(node: ANode, nlabel: nullable ALabel): nullable EscapeMark

nitc :: ScopeVisitor :: get_escapemark

Look for an escape mark optionally associated with a label.
fun hash: Int

core :: Object :: hash

The hash code of the object.
init init

core :: Object :: init

fun inspect: String

core :: Object :: inspect

Developer readable representation of self.
protected fun inspect_head: String

core :: Object :: inspect_head

Return "CLASSNAME:#OBJECTID".
intern fun is_same_instance(other: nullable Object): Bool

core :: Object :: is_same_instance

Return true if self and other are the same instance (i.e. same identity).
fun is_same_serialized(other: nullable Object): Bool

core :: Object :: is_same_serialized

Is self the same as other in a serialization context?
intern fun is_same_type(other: Object): Bool

core :: Object :: is_same_type

Return true if self and other have the same dynamic type.
private fun make_escape_mark(nlabel: nullable ALabel, for_loop: Bool): EscapeMark

nitc :: ScopeVisitor :: make_escape_mark

Create a new escape mark (possibly with a label)
private intern fun native_class_name: CString

core :: Object :: native_class_name

The class name of the object in CString format.
intern fun object_id: Int

core :: Object :: object_id

An internal hash code for the object based on its identity.
fun output

core :: Object :: output

Display self on stdout (debug only).
intern fun output_class_name

core :: Object :: output_class_name

Display class name on stdout (debug only).
private fun propdef: APropdef

nitc :: ScopeVisitor :: propdef

The analysed property
private fun propdef=(propdef: APropdef)

nitc :: ScopeVisitor :: propdef=

The analysed property
private fun register_variable(node: ANode, variable: Variable): Bool

nitc :: ScopeVisitor :: register_variable

Register a local variable.
private fun scopes: List[Scope]

nitc :: ScopeVisitor :: scopes

All stacked scope. scopes.first is the current scope
private fun scopes=(scopes: List[Scope])

nitc :: ScopeVisitor :: scopes=

All stacked scope. scopes.first is the current scope
private fun search_label(name: String): nullable EscapeMark

nitc :: ScopeVisitor :: search_label

Look for a label name.
private fun search_variable(name: String): nullable Variable

nitc :: ScopeVisitor :: search_variable

Look for a variable named name.
private fun selfvariable=(selfvariable: Variable)

nitc :: ScopeVisitor :: selfvariable=

fun serialization_hash: Int

core :: Object :: serialization_hash

Hash value use for serialization
private fun shift_scope

nitc :: ScopeVisitor :: shift_scope

Shift and check the last scope
intern fun sys: Sys

core :: Object :: sys

Return the global sys object, the only instance of the Sys class.
abstract fun to_jvalue(env: JniEnv): JValue

core :: Object :: to_jvalue

fun to_s: String

core :: Object :: to_s

User readable representation of self.
private fun toolcontext: ToolContext

nitc :: ScopeVisitor :: toolcontext

The tool context used to display errors
private fun toolcontext=(toolcontext: ToolContext)

nitc :: ScopeVisitor :: toolcontext=

The tool context used to display errors
protected abstract fun visit(e: ANode)

nitc :: Visitor :: visit

What the visitor do when a node is visited
package_diagram nitc::scope::ScopeVisitor ScopeVisitor nitc::Visitor Visitor nitc::scope::ScopeVisitor->nitc::Visitor core::Object Object nitc::Visitor->core::Object ...core::Object ... ...core::Object->core::Object

Ancestors

interface Object

core :: Object

The root of the class hierarchy.

Parents

abstract class Visitor

nitc :: Visitor

Abstract standard visitor on the AST

Class definitions

nitc $ ScopeVisitor
# Visit a npropdef and:
#  * Identify variables and labels
#  * Associate each break and continue to its escapemark
#  * Transform `ACallFormExpr` that access a variable into `AVarFormExpr`
# FIXME: Should the class be private?
private class ScopeVisitor
	super Visitor

	# The tool context used to display errors
	var toolcontext: ToolContext

	# The analysed property
	var propdef: APropdef

	var selfvariable = new Variable("self")

	init
	do
		scopes.add(new Scope)
	end

	# All stacked scope. `scopes.first` is the current scope
	var scopes = new List[Scope]

	# Shift and check the last scope
	fun shift_scope
	do
		assert not scopes.is_empty
		var scope = scopes.shift
		for v in scope.variables.values do
			if v.warn_unread then
				toolcontext.advice(v.location, "unread-variable", "Warning: local variable {v.name} is never read.")
			end
		end
	end

	# Register a local variable.
	# Display an error on toolcontext if a variable with the same name is masked.
	fun register_variable(node: ANode, variable: Variable): Bool
	do
		var name = variable.name
		var found = search_variable(name)
		if found != null then
			self.error(node, "Error: a variable named `{name}` already exists.")
			return false
		end
		scopes.first.variables[name] = variable
		variable.location = node.location
		return true
	end

	# Look for a variable named `name`.
	# Return null if no such a variable is found.
	fun search_variable(name: String): nullable Variable
	do
		for scope in scopes do
			var res = scope.get_variable(name)
			if res != null then
				return res
			end
		end
		return null
	end

	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`.
	fun enter_visit_block(node: nullable AExpr, escapemark: nullable EscapeMark)
	do
		if node == null then return
		var scope = new Scope
		scope.escapemark = escapemark
		scopes.unshift(scope)
		enter_visit(node)
		shift_scope
	end

	# Look for a label `name`.
	# Return null if no such a label is found.
	fun search_label(name: String): nullable EscapeMark
	do
		for scope in scopes do
			var res = scope.escapemark
			if res != null and res.name == name then
				return res
			end
		end
		return null
	end

	# Create a new escape mark (possibly with a label)
	# Display an error on toolcontext if a label with the same name is masked.
	fun make_escape_mark(nlabel: nullable ALabel, for_loop: Bool): EscapeMark
	do
		var name: nullable String
		if nlabel != null then
			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
		end
		var res = new EscapeMark(name)
		if for_loop then res.continue_mark = new EscapeMark(name)
		return res
	end

	# Look for an escape mark optionally associated with a label.
	# If a label is given, the escapemark of this label is 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 null if no such a label is found.
	fun get_escapemark(node: ANode, nlabel: nullable ALabel): nullable EscapeMark
	do
		if nlabel != null then
			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.")
					node.is_broken = true
					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}`.")
				node.is_broken = true
				return null
			end
			return res
		else
			for scope in scopes do
				var res = scope.escapemark
				if res != null then
					return res
				end
			end
			self.error(node, "Syntax Error: `break` statement outside block.")
			return null
		end
	end

	# Display an error
	fun error(node: ANode, message: String)
	do
		self.toolcontext.error(node.hot_location, message)
		node.is_broken = true
	end
end
src/semantize/scope.nit:63,1--229,3