From 0b763257ed1e230767171234971cc8f660d59087 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 22 Oct 2026 04:00:38 +0000 Subject: refactor(parser): share call-argument, result-access and type-token checks Add ParseOptionalCallArgs() for member calls and NEW, diagnoseResultAccess() for the duplicated "access on a function result" diagnostic, and isBuiltinTypeToken() for the builtin type keyword list used by template-call lookahead, cast detection and CASE label scanning. Co-Authored-By: Claude Opus 5.5 --- include/cps/Parser.h | 3 +++ lib/Parser/ParserControlFlow.cc | 7 +++-- lib/Parser/ParserExpression.cc | 57 ++++++++++++++++++++++------------------- 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/include/cps/Parser.h b/include/cps/Parser.h index c9fe186..fbccb3c 100644 --- a/include/cps/Parser.h +++ b/include/cps/Parser.h @@ -49,6 +49,9 @@ class Parser { std::string ParseOperatorName(int *Op = nullptr); bool ParseCalleeName(std::string &Name); std::unique_ptr ParseParenExpr(); + bool ParseOptionalCallArgs(std::vector> &Args); + bool diagnoseResultAccess(); + static bool isBuiltinTypeToken(int Tok); std::unique_ptr ParseMemberCall( const std::string &Name, std::vector Accesses, int Line); std::string ParseTypeName(bool AllowVoid = false); diff --git a/lib/Parser/ParserControlFlow.cc b/lib/Parser/ParserControlFlow.cc index ba038d3..feedf44 100644 --- a/lib/Parser/ParserControlFlow.cc +++ b/lib/Parser/ParserControlFlow.cc @@ -156,14 +156,13 @@ bool Parser::isCaseLabel() { case ')': case ']': if (--Depth < 0) return false; break; case tok_identifier: case tok_number_int: case tok_number_real: case tok_string_literal: case tok_c_string_literal: case tok_char_literal: case tok_true: case tok_false: - case tok_integer_kw: case tok_real_kw: case tok_boolean_kw: - case tok_string_kw: case tok_char_kw: case tok_c_int: case tok_c_char: - case tok_c_string: case tok_c_double: case tok_to: case tok_otherwise: case tok_and: case tok_or: case tok_not: case tok_eq: case tok_ne: case tok_le: case tok_ge: case tok_div: case tok_mod: case '+': case '-': case '*': case '/': case '&': case '^': case '<': case '>': case '.': case ',': break; - default: return false; + default: + if (!isBuiltinTypeToken(T)) return false; + break; } } } diff --git a/lib/Parser/ParserExpression.cc b/lib/Parser/ParserExpression.cc index 398ba84..b3bb3d9 100644 --- a/lib/Parser/ParserExpression.cc +++ b/lib/Parser/ParserExpression.cc @@ -38,15 +38,20 @@ std::unique_ptr Parser::ParseNumberExpr() { return std::make_unique(Value); } +// Keyword tokens that name a builtin or C scalar type. +bool Parser::isBuiltinTypeToken(int Tok) { + return Tok == tok_integer_kw || Tok == tok_real_kw || Tok == tok_boolean_kw || + Tok == tok_string_kw || Tok == tok_char_kw || + Tok == tok_c_int || Tok == tok_c_char || Tok == tok_c_string || Tok == tok_c_double; +} + // Grammar lookahead distinguishes a template call from a comparison without // consuming tokens. Like C#, A < B, C > (D) selects the template-call grammar. bool Parser::isTemplateCall() { if (CurTok != '<') return false; unsigned Offset = 0; auto IsTypeToken = [](int Tok) { - return Tok == tok_identifier || Tok == tok_integer_kw || Tok == tok_real_kw || - Tok == tok_boolean_kw || Tok == tok_string_kw || Tok == tok_char_kw || - Tok == tok_c_int || Tok == tok_c_char || Tok == tok_c_string || Tok == tok_c_double; + return Tok == tok_identifier || isBuiltinTypeToken(Tok); }; std::function Type = [&] { if (!IsTypeToken(Lex.peekToken(Offset))) return false; @@ -99,10 +104,7 @@ std::unique_ptr Parser::ParseIdentifierExpr() { getNextToken(); auto Args = ParseExprList(')', true); if (!Args) return nullptr; - if (CurTok == '[' || CurTok == '^') { - cps::sourceError(Lex.getLine(), "record/array/pointer access on a function result is not supported"); - return nullptr; - } + if (diagnoseResultAccess()) return nullptr; return ParseResultMethods(std::make_unique(IdName, std::move(*Args), Line, std::move(TemplateArgs)), Line); } @@ -126,6 +128,13 @@ std::unique_ptr Parser::makeDesignator( return std::make_unique(Name, std::move(Accesses), Line); } +// Indexing or dereferencing a call result is rejected; true means diagnosed. +bool Parser::diagnoseResultAccess() { + if (CurTok != '[' && CurTok != '^') return false; + cps::sourceError(Lex.getLine(), "record/array/pointer access on a function result is not supported"); + return true; +} + // The final field suffix names the method; preceding suffixes form its receiver. std::unique_ptr Parser::ParseMemberCall( const std::string &Name, std::vector Accesses, int Line) { @@ -137,16 +146,8 @@ std::unique_ptr Parser::ParseMemberCall( Accesses.pop_back(); auto Receiver = std::make_unique(Name, std::move(Accesses), Line); std::vector> Args; - if (CurTok == '(') { - getNextToken(); - auto Parsed = ParseExprList(')', true); - if (!Parsed) return nullptr; - Args = std::move(*Parsed); - } - if (CurTok == '[' || CurTok == '^') { - cps::sourceError(Lex.getLine(), "record/array/pointer access on a function result is not supported"); - return nullptr; - } + if (!ParseOptionalCallArgs(Args)) return nullptr; + if (diagnoseResultAccess()) return nullptr; auto Result = ParseResultMethods(std::make_unique(std::move(Receiver), Method, std::move(Args), Line), Line); return std::unique_ptr(static_cast(Result.release())); } @@ -193,10 +194,7 @@ bool Parser::ParseDesignatorSuffix(std::vector &Out) { std::unique_ptr Parser::ParseParenExpr() { getNextToken(); - bool IsType = CurTok == tok_integer_kw || CurTok == tok_real_kw || - CurTok == tok_boolean_kw || CurTok == tok_string_kw || CurTok == tok_char_kw || - CurTok == tok_c_int || CurTok == tok_c_char || CurTok == tok_c_string || - CurTok == tok_c_double || + bool IsType = isBuiltinTypeToken(CurTok) || (CurTok == tok_identifier && TypeNames.count(Lex.IdentifierStr)); if (IsType) { std::string TypeName = ParseTypeName(); @@ -389,6 +387,16 @@ std::optional>> Parser::ParseExprList(char return Elems; } +// An optional parenthesized argument list; false means a diagnosed failure. +bool Parser::ParseOptionalCallArgs(std::vector> &Args) { + if (CurTok != '(') return true; + getNextToken(); + auto Parsed = ParseExprList(')', true); + if (!Parsed) return false; + Args = std::move(*Parsed); + return true; +} + std::unique_ptr Parser::ParseAssignmentRHS() { if (CurTok != tok_new) return ParseExpression(); int Line = Lex.getLine(); @@ -396,11 +404,6 @@ std::unique_ptr Parser::ParseAssignmentRHS() { std::string ClassName = ParseTypeName(false); if (ClassName.empty()) return nullptr; std::vector> Args; - if (CurTok == '(') { - getNextToken(); - auto Parsed = ParseExprList(')', true); - if (!Parsed) return nullptr; - Args = std::move(*Parsed); - } + if (!ParseOptionalCallArgs(Args)) return nullptr; return std::make_unique(ClassName, std::move(Args), Line); } -- cgit v1.3.1-4-g156e