From 6f1c37dc2dc1fba055b08c29f8373618e9bf0613 Mon Sep 17 00:00:00 2001 From: XiaoBaiYun <71159641+littlewhitecloud@users.noreply.github.com> Date: Thu, 23 Mar 2023 23:44:23 +0800 Subject: [PATCH] Improve missing self error (#345) Co-authored-by: Akuli --- self_hosted/parser.jou | 7 +++++++ src/parse.c | 14 +++++++++++--- tests/syntax_error/missing_self.jou | 8 ++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 tests/syntax_error/missing_self.jou diff --git a/self_hosted/parser.jou b/self_hosted/parser.jou index abf5859a..802883e7 100644 --- a/self_hosted/parser.jou +++ b/self_hosted/parser.jou @@ -78,6 +78,7 @@ def parse_name_type_value(tokens: Token**, expected_what_for_name: byte*) -> Ast def parse_function_or_method_signature(tokens: Token**, is_method: bool) -> AstSignature: # TODO: change error messages to say method, when it is a method (#243) + used_self: bool = False if (*tokens)->kind != TokenKind::Name: (*tokens)->fail_expected_got("a function name") @@ -108,6 +109,7 @@ def parse_function_or_method_signature(tokens: Token**, is_method: bool) -> AstS name_location = (*tokens)->location, } ++*tokens + used_self = True else: arg = parse_name_type_value(tokens, "an argument name") @@ -144,6 +146,11 @@ def parse_function_or_method_signature(tokens: Token**, is_method: bool) -> AstS (*tokens)->fail_expected_got("a '->'") ++*tokens + if not used_self and is_method: + throwerror: byte[300] + snprintf(throwerror, sizeof throwerror, "missing self, should be 'def %s(self, ...)'", result.name) + fail((*tokens)->location, throwerror) + result.return_type = parse_type(tokens) return result diff --git a/src/parse.c b/src/parse.c index e5f22a8c..a18f83ec 100644 --- a/src/parse.c +++ b/src/parse.c @@ -127,7 +127,7 @@ static AstNameTypeValue parse_name_type_value(const Token **tokens, const char * static AstSignature parse_function_signature(const Token **tokens, bool accept_self) { AstSignature result = {0}; - + bool used_self = false; if ((*tokens)->type != TOKEN_NAME) fail_with_parse_error(*tokens, "a function name"); result.name_location = (*tokens)->location; @@ -150,6 +150,7 @@ static AstSignature parse_function_signature(const Token **tokens, bool accept_s fail_with_error((*tokens)->location, "'self' cannot be used here"); AstNameTypeValue self_arg = { .name="self", .name_location=(*tokens)++->location }; Append(&result.args, self_arg); + used_self = true; } else { AstNameTypeValue arg = parse_name_type_value(tokens, "an argument name"); @@ -167,7 +168,6 @@ static AstSignature parse_function_signature(const Token **tokens, bool accept_s else break; } - if (!is_operator(*tokens, ")")) fail_with_parse_error(*tokens, "a ')'"); ++*tokens; @@ -184,7 +184,15 @@ static AstSignature parse_function_signature(const Token **tokens, bool accept_s fail_with_parse_error(*tokens, "a '->'"); } ++*tokens; - + + if (!used_self && accept_self) { + fail_with_error( + (*tokens)->location, + "missing self, should be 'def %s(self, ...)'", + result.name + ); + } + result.returntype = parse_type(tokens); return result; } diff --git a/tests/syntax_error/missing_self.jou b/tests/syntax_error/missing_self.jou new file mode 100644 index 00000000..bc9d53b1 --- /dev/null +++ b/tests/syntax_error/missing_self.jou @@ -0,0 +1,8 @@ +class Foo: + def bar() -> void: # Error: missing self, should be 'def bar(self, ...)' + return + +def main() -> int: + f = Foo{} + f.bar() + return 0