class String {

method substring { }

method length { }

method value { }

method print { }

}

class Name {

var last : String

var first : String

method getLast { invoke last value }

method getFirst { invoke first value }

method print {

invoke last print

invoke first print

}

}

var name1 : Name

var string1 : String

invoke name1 getLast

invoke string1 value

invoke name1 print

end

classString{

methodsubstring{}

methodlength{}

methodvalue{}

methodprint{}

}

className{

varlast:String

varfirst:String

methodgetLast{invokelastvalue}

methodgetFirst{invokefirstvalue}

methodprint{

invokelastprint

invokefirstprint

}

}

varname1:Name

varstring1:String

invokename1getLast

invokestring1value

invokename1print

end

class String {
method substring { }
method length { }
method value { }
method print { }
}
class Name {
var last : String
var first : String
method getLast {invoke last value}
method getFirst {invoke first value }
method print {
invoke last print
invoke first print
}
}
var name1 : Name
var string1 : String
! / invoke name1 getLast
! / invoke string1 value
! / invoke name1 print
end

Handling the Invocation of invoke name1 print

  • Resolve the receiver variable name name1
  • Lookup "name1" in ‘global’variable table, retrieving Varname1(VarTable.get)
  • Resolve method name print
  • Get name of the receiver variable’s class ("Name") from Varname1(Var.getClassName)
  • Look up "Name" in the ‘global’ class table, retrieving ClassName(ClassTable.get)
  • Using the name "print", retrieve MethodName.printfrom ClassName(Class.getMethod)
  • (Print a message invoking print method of class Name on receiver name1)
  • Interpret MethodName.print
  • Iterate though the message table of MethodName.printinvoking each of the messages in turn
  • Handling the invocation of first message:invoke last print
  • Resolve the receiver variable namelast
  • Look up "last" in ClassName’s variable table, retrieving VarName.last
  • Resolve the method nameprint
  • Get the name of the receiver variable’s class (String) from VarName.last
  • Look up "String" in the ‘global’ class table, retrieving ClassString
  • Using the name "print", retrieve MethodString.print from ClassString
  • (Print a message invoking print method of class String on receiver last)
  • Handling the invocation of second message:invoke first print
  • Resolve the receiver variable namefirst
  • Look up "first" in ClassName’s variable table, retrieving VarName.first
  • Resolve the method name print
  • Get the name of the receiver variable’s class (String) from VarName.first
  • Look up "String" in the ‘global’ class table, retrieving ClassString
  • Using the name "print", retrieve MethodString.print from ClassString
  • (Print a message invoking print method of class String on receiver first)

Maintaining Correct Context

Class Table Context

  • The context of the class table is always‘global’, since all class definitions occur at top-level.

Method Table Context

  • The method table used to resolve a method name is always the method table of the class of the receiver variable. (You are invoking the method on the receiver variable; that method had better be one belonging to the class of the receiver). Since we first resolve the receiver variable (and the resolution of the receiver is immediately followed by the resolution of the method), solving this problem is straightforward:
  • Once you have the identity (i.e., the particular Var object) corresponding to the receiver variable, you can get its class.
  • Once you have the class, you can retrieve the proper Method object given the name (using the getMethod method of Class; an alternative implementation would have allowed you to retrieve the methodTable instance variable of the Class object and retrieve the Method object directly from the MethodTable object. In this second scenario, the context is more visible; i.e., you actually search the method table, rather than have the class do it for you).

Variable Table Context

  • This is the only table that is context-sensitive (i.e., changes depending on the location of the message being invoked).
  • We use the variable table to resolve the receiver variable of a message.
  • The question of maintaining correct context thus boils down to one question: when resolving the receiver variable, how do we know which is the correct variable table?
  • To begin with, we should first examine WHAT the proper context is in the general case. There are two places messages can occur:
  • Top-level messages: variables here are resolved using the top-level/global variable table
  • Method-level messages (i.e., messages within a method definition/body): variables here are resolved using the variable table of the class containing the method in which the message appears.
  • So what this means if we have to know which of the above two situations hold; and in the second case, also know which is the containing class.

Below is being worked on—read at your own risk

  • Interpretation of a method (performed in interpret(Method method, VarTable varTable)entails invoking each of its contained messages (in sequence).
  • The receiver variables of these messages (within the method) are resolved using the variable table of the class of the receiver
  • However, unlike variables, methods do not contain references to their containing class (probably a mistake on my part, but it allows this discussion, which is educational once you understand it. Feel free, BTW, to add the class name to the Method class, if you prefer to do it that way).
  • So, we must pass the proper variable table to the interpret(Method method, VarTable varTable)method.
  • If you look at the code, this method is only called from interpret(Message message, VarTable varTable), i.e., a method is only interpreted once it’s been resolved as <em>the</em> method of a message invocation.
  • So we have to make certain that interpret(Method method, VarTable varTable) calls interpret(Method method, VarTable varTable) with the proper variable table (which may or may not be the same as the former’s own VarTable parameter).
  • Interpretation of a message (performed in interpret(Messagemessage, VarTable varTable) entails resolving the receiver variable and then the method. This method is called from two places (and in fact that is part of the reason we have this problem):
  • From a global/top-level invocationas mentioned in the 2nd bullet
  • As mentioned above we pass the global variable table to the VarTableparameter in this case.
  • From within the interpret(Method method, VarTable varTable) (remember, this method iterates through the method’s message table, invoking each message in turn).
  • The receiver variables of messages within a method are instance variables of the method’s class and are thus resolved using the same variable table (i.e., the one of the class containing the method) as the method itself.
  • In fact, all the interpret(Method method, VarTable varTable)has to do is pass along it’s VarTable parameter when it calls interpret(Messagemessage, VarTable varTable)
  • Within the interpret(Messagemessage, VarTable varTable), the receiver variable is resolved using it’s VarTable parameter, and then the class of that receiver variable is retrieved (in order to resolve the method name), and it is the variable table of THIS class that is then passed along to the method(since that is the variable table of the class containing the method about to be interpreted, which is exactly the situation we want).