feat: make this the implicit receiver for method calls inside class bodies

In the compiler, when a bare name is encountered inside a class definition and it does not resolve to a local variable or global, emit an implicit `this.` load before the call, enabling getter, setter, and method calls without explicit receiver. Update all benchmark, builtin, and test files to remove redundant `this.` qualifiers, and add comprehensive test suites for implicit receiver behavior across instance, inherited, static, nested, and shadowing scenarios.
This commit is contained in:
Bob Nystrom
2014-02-13 01:33:35 +00:00
parent c04865df2e
commit e3b3fef0fb
13 changed files with 217 additions and 51 deletions
+20 -5
View File
@@ -1434,13 +1434,12 @@ static void methodCall(Compiler* compiler, Code instruction,
methodSymbol(compiler, name, length));
}
// Compiles an expression that starts with ".name". That includes getters,
// method calls with arguments, and setter calls.
// Compiles a call whose name is the previously consumed token. This includes
// getters, method calls with arguments, and setter calls.
static void namedCall(Compiler* compiler, bool allowAssignment,
Code instruction)
{
// Build the method name.
consume(compiler, TOKEN_NAME, "Expect method name after '.'.");
char name[MAX_METHOD_SIGNATURE];
int length = copyName(compiler, name);
@@ -1703,9 +1702,23 @@ static void name(Compiler* compiler, bool allowAssignment)
Code loadInstruction;
int index = resolveName(compiler, token->start, token->length,
&loadInstruction);
if (index == -1) error(compiler, "Undefined variable.");
if (index != -1)
{
variable(compiler, allowAssignment, index, loadInstruction);
return;
}
variable(compiler, allowAssignment, index, loadInstruction);
// Otherwise, if we are inside a class, it's a getter call with an implicit
// receiver.
ClassCompiler* classCompiler = getEnclosingClass(compiler);
if (classCompiler == NULL)
{
error(compiler, "Undefined variable.");
return;
}
loadThis(compiler);
namedCall(compiler, allowAssignment, CODE_CALL_0);
}
static void null(Compiler* compiler, bool allowAssignment)
@@ -1781,6 +1794,7 @@ static void super_(Compiler* compiler, bool allowAssignment)
if (match(compiler, TOKEN_DOT))
{
// Compile the superclass call.
consume(compiler, TOKEN_NAME, "Expect method name after 'super.'.");
namedCall(compiler, allowAssignment, CODE_SUPER_0);
}
else
@@ -1851,6 +1865,7 @@ static void subscript(Compiler* compiler, bool allowAssignment)
void call(Compiler* compiler, bool allowAssignment)
{
consume(compiler, TOKEN_NAME, "Expect method name after '.'.");
namedCall(compiler, allowAssignment, CODE_CALL_0);
}
+1 -1
View File
@@ -44,7 +44,7 @@ static const char* libSource =
"class List {\n"
" toString {\n"
" var result = \"[\"\n"
" for (i in 0...this.count) {\n"
" for (i in 0...count) {\n"
" if (i > 0) result = result + \", \"\n"
" result = result + this[i].toString\n"
" }\n"