diff --git a/ports/cpp/source/antlr4-c3/CodeCompletionCore.cpp b/ports/cpp/source/antlr4-c3/CodeCompletionCore.cpp index 1ca91c0..e5f5e28 100644 --- a/ports/cpp/source/antlr4-c3/CodeCompletionCore.cpp +++ b/ports/cpp/source/antlr4-c3/CodeCompletionCore.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -88,6 +89,18 @@ CodeCompletionCore::CodeCompletionCore(antlr4::Parser* parser) , cancel(nullptr) { } +void CodeCompletionCore::setIgnoredTokens(std::unordered_set&& ignoredTokens) { + this->ignoredTokens = std::move(ignoredTokens); +} + +void CodeCompletionCore::setPreferredRules(std::unordered_set&& preferredRules) { + this->preferredRules = std::move(preferredRules); +} + +void CodeCompletionCore::setTranslateRulesTopDown(bool isEnabled) { + this->translateRulesTopDown = isEnabled; +} + CandidatesCollection CodeCompletionCore::collectCandidates( size_t caretTokenIndex, Parameters parameters ) { @@ -131,7 +144,7 @@ CandidatesCollection CodeCompletionCore::collectCandidates( processRule(atn.ruleToStartState[startRule], 0, callStack, 0, 0, candidates.isCancelled); - if (showResult) { + if (show.result) { if (candidates.isCancelled) { std::cout << "*** TIMED OUT ***\n"; } @@ -266,7 +279,7 @@ bool CodeCompletionCore::translateToRuleIndex( .startTokenIndex = rwst.startTokenIndex, .ruleList = path, }; - if (showDebugOutput) { + if (show.debugOutput) { std::cout << "=====> collected: " << ruleNames[rwst.ruleIndex] << "\n"; } } @@ -481,7 +494,7 @@ CodeCompletionCore::RuleEndStatus CodeCompletionCore::processRule( // NOLINT // Check first if we've taken this path with the same input before. std::unordered_map& positionMap = shortcutMap[startState->ruleIndex]; if (positionMap.contains(tokenListIndex)) { - if (showDebugOutput) { + if (show.debugOutput) { std::cout << "=====> shortcut" << "\n"; } return positionMap[tokenListIndex]; @@ -538,7 +551,7 @@ CodeCompletionCore::RuleEndStatus CodeCompletionCore::processRule( // NOLINT if (!translateStackToRuleIndex(fullPath)) { for (const size_t symbol : set.intervals.toList()) { if (!ignoredTokens.contains(symbol)) { - if (showDebugOutput) { + if (show.debugOutput) { std::cout << "=====> collected: " << vocabulary.getDisplayName(symbol) << "\n"; } if (!candidates.tokens.contains(symbol)) { @@ -602,14 +615,14 @@ CodeCompletionCore::RuleEndStatus CodeCompletionCore::processRule( // NOLINT const size_t currentSymbol = tokens[currentEntry.tokenListIndex]->getType(); const bool atCaret = currentEntry.tokenListIndex >= tokens.size() - 1; - if (showDebugOutput) { + if (show.debugOutput) { printDescription( indentation, currentEntry.state, generateBaseDescription(currentEntry.state), currentEntry.tokenListIndex ); - if (showRuleStack) { + if (show.ruleStack) { printRuleState(callStack); } } @@ -720,7 +733,7 @@ CodeCompletionCore::RuleEndStatus CodeCompletionCore::processRule( // NOLINT const bool hasTokenSequence = list.size() == 1; for (const size_t symbol : list) { if (!ignoredTokens.contains(symbol)) { - if (showDebugOutput) { + if (show.debugOutput) { std::cout << "=====> collected: " << vocabulary.getDisplayName(symbol) << "\n"; } @@ -741,7 +754,7 @@ CodeCompletionCore::RuleEndStatus CodeCompletionCore::processRule( // NOLINT } } else { if (set.contains(currentSymbol)) { - if (showDebugOutput) { + if (show.debugOutput) { std::cout << "=====> consumed: " << vocabulary.getDisplayName(currentSymbol) << "\n"; } @@ -794,7 +807,7 @@ void CodeCompletionCore::printDescription( const auto indent = std::string(indentation * 2, ' '); std::string transitionDescription; - if (debugOutputWithTransitions) { + if (show.debugOutputWithTransitions) { for (const antlr4::atn::ConstTransitionPtr& transition : state->transitions) { std::string labels; std::vector symbols = transition->label().toList(); diff --git a/ports/cpp/source/antlr4-c3/CodeCompletionCore.hpp b/ports/cpp/source/antlr4-c3/CodeCompletionCore.hpp index e699f62..fe5426c 100644 --- a/ports/cpp/source/antlr4-c3/CodeCompletionCore.hpp +++ b/ports/cpp/source/antlr4-c3/CodeCompletionCore.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -128,44 +129,49 @@ class CodeCompletionCore { * Tailoring of the result: * Tokens which should not appear in the candidates set. */ - std::unordered_set ignoredTokens; // NOLINT: public field + void setIgnoredTokens(std::unordered_set&& ignoredTokens); /** * Rules which replace any candidate token they contain. * This allows to return descriptive rules (e.g. className, instead of * ID/identifier). */ - std::unordered_set preferredRules; // NOLINT: public field + void setPreferredRules(std::unordered_set&& preferredRules); /** * Specify if preferred rules should translated top-down (higher index rule * returns first) or bottom-up (lower index rule returns first). */ - bool translateRulesTopDown = false; // NOLINT: public field + void setTranslateRulesTopDown(bool isEnabled); - // -------------------------------------------------------- - // Debugging Options - // -------------------------------------------------------- - // Print human readable ATN state and other info. - - /** Not dependent on showDebugOutput. Prints the collected rules + tokens to - * terminal. */ - bool showResult = false; // NOLINT: public field - - /** Enables printing ATN state info to terminal. */ - bool showDebugOutput = false; // NOLINT: public field - - /** Only relevant when showDebugOutput is true. Enables transition printing - * for a state. */ - bool debugOutputWithTransitions = false; // NOLINT: public field - - /** Also depends on showDebugOutput. Enables call stack printing for each rule - * recursion. */ - bool showRuleStack = false; // NOLINT: public field - - // -------------------------------------------------------- - // Usage - // -------------------------------------------------------- + /** + * Print human readable ATN state and other info. + * NB. This API is only for a debugging and so is volatile. + */ + struct { + /** + * Not dependent on showDebugOutput. + * Prints the collected rules + tokens to terminal. + */ + bool result = false; + + /** + * Enables printing ATN state info to terminal. + */ + bool debugOutput = false; + + /** + * Only relevant when showDebugOutput is true. + * Enables transition printing for a state. + */ + bool debugOutputWithTransitions = false; + + /** + * Also depends on showDebugOutput. + * Enables call stack printing for each rule recursion. + */ + bool ruleStack = false; + } show; // NOLINT: public field, only for debugging /** * This is the main entry point. The caret token index specifies the token @@ -183,13 +189,14 @@ class CodeCompletionCore { */ CandidatesCollection collectCandidates(size_t caretTokenIndex, Parameters parameters = {}); - // -------------------------------------------------------- - // Private - // -------------------------------------------------------- private: static std::unordered_map followSetsByATN; static std::vector atnStateTypeMap; + std::unordered_set ignoredTokens; + std::unordered_set preferredRules; + bool translateRulesTopDown = false; + antlr4::Parser* parser; antlr4::atn::ATN const& atn; // NOLINT: reference field antlr4::dfa::Vocabulary const& vocabulary; // NOLINT: reference field diff --git a/ports/cpp/test/cpp14/Cpp14Test.cpp b/ports/cpp/test/cpp14/Cpp14Test.cpp index 5df0527..ca55539 100644 --- a/ports/cpp/test/cpp14/Cpp14Test.cpp +++ b/ports/cpp/test/cpp14/Cpp14Test.cpp @@ -38,7 +38,7 @@ TEST(CPP14Parser, SimpleExample) { // NOLINT: complexity CodeCompletionCore completion(&pipeline.parser); // Ignore operators and the generic ID token. - completion.ignoredTokens = { + completion.setIgnoredTokens({ CPP14Lexer::Identifier, CPP14Lexer::LeftParen, CPP14Lexer::RightParen, @@ -50,17 +50,17 @@ TEST(CPP14Parser, SimpleExample) { // NOLINT: complexity CPP14Lexer::Ellipsis, CPP14Lexer::Doublecolon, CPP14Lexer::Semi, - }; + }); // For a C++ grammar you can of course get many candidates of all kind. For // this test we focus only on a few, namely namespace, class and variable // references. For variable references there is no own rule, only an // "idexpression" as part of the primary expression. - completion.preferredRules = { + completion.setPreferredRules({ CPP14Parser::RuleClassname, CPP14Parser::RuleNamespacename, CPP14Parser::RuleIdexpression, - }; + }); { // 1) At the input start. @@ -154,7 +154,7 @@ TEST(CPP14Parser, SimpleExample) { // NOLINT: complexity // 2) Within the method body. // Note when counting token indexes: the C++14 grammar skips all // whitespaces, hence there are no tokens for them. - completion.translateRulesTopDown = translateRulesTopDown; + completion.setTranslateRulesTopDown(translateRulesTopDown); auto candidates = completion.collectCandidates(10); // NOLINT: magic const std::vector idexpressionStack = { @@ -239,7 +239,7 @@ TEST(CPP14Parser, SimpleExample) { // NOLINT: complexity // 2) Within the method body. // Note when counting token indexes: the C++14 grammar skips all // whitespaces, hence there are no tokens for them. - completion.translateRulesTopDown = true; + completion.setTranslateRulesTopDown(true); auto candidates = completion.collectCandidates(10); // NOLINT: magic EXPECT_EQ(candidates.tokens.size(), 82); @@ -281,7 +281,7 @@ TEST(CPP14Parser, SimpleCppExampleWithErrorsInInput) { CodeCompletionCore completion(&pipeline.parser); // Ignore operators and the generic ID token. - completion.ignoredTokens = { + completion.setIgnoredTokens({ CPP14Lexer::Identifier, // Let parentheses show up in this test, so // CPP14Lexer.LeftParen, @@ -294,13 +294,13 @@ TEST(CPP14Parser, SimpleCppExampleWithErrorsInInput) { CPP14Lexer::Ellipsis, CPP14Lexer::Doublecolon, CPP14Lexer::Semi, - }; + }); - completion.preferredRules = { + completion.setPreferredRules({ CPP14Parser::RuleClassname, CPP14Parser::RuleNamespacename, CPP14Parser::RuleIdexpression, - }; + }); { // At the opening parenthesis. @@ -360,7 +360,7 @@ TEST(CPP14Parser, RealCppFile) { // NOLINT: complexity CodeCompletionCore completion(&pipeline.parser); // Ignore operators and the generic ID token. - completion.ignoredTokens = { + completion.setIgnoredTokens({ CPP14Lexer::Identifier, CPP14Lexer::LeftParen, CPP14Lexer::RightParen, @@ -372,13 +372,12 @@ TEST(CPP14Parser, RealCppFile) { // NOLINT: complexity CPP14Lexer::Ellipsis, CPP14Lexer::Doublecolon, CPP14Lexer::Semi, - }; - - completion.preferredRules = { + }); + completion.setPreferredRules({ CPP14Parser::RuleClassname, CPP14Parser::RuleNamespacename, CPP14Parser::RuleIdexpression, - }; + }); const std::vector idexpressionStack = { CPP14Parser::RuleTranslationunit, @@ -439,7 +438,7 @@ TEST(CPP14Parser, RealCppFile) { // NOLINT: complexity { // We should receive more specific rules when translating top down. - completion.translateRulesTopDown = true; + completion.setTranslateRulesTopDown(true); auto candidates = completion.collectCandidates(3469); // NOLINT: magic EXPECT_THAT( diff --git a/ports/cpp/test/expr/ExprTest.cpp b/ports/cpp/test/expr/ExprTest.cpp index 87f8969..dfaa517 100644 --- a/ports/cpp/test/expr/ExprTest.cpp +++ b/ports/cpp/test/expr/ExprTest.cpp @@ -79,18 +79,18 @@ TEST(SimpleExpressionParser, TypicalSetup) { EXPECT_EQ(pipeline.listener.GetErrorCount(), 0); c3::CodeCompletionCore completion(&pipeline.parser); - completion.ignoredTokens = { + completion.setIgnoredTokens({ ExprLexer::ID, ExprLexer::PLUS, ExprLexer::MINUS, ExprLexer::MULTIPLY, ExprLexer::DIVIDE, ExprLexer::EQUAL, - }; - completion.preferredRules = { + }); + completion.setPreferredRules({ ExprParser::RuleFunctionRef, ExprParser::RuleVariableRef, - }; + }); { // 1) At the input start. @@ -141,7 +141,7 @@ TEST(SimpleExpressionParser, RecursivePreferredRule) { EXPECT_EQ(pipeline.listener.GetErrorCount(), 0); c3::CodeCompletionCore completion(&pipeline.parser); - completion.preferredRules = {ExprParser::RuleSimpleExpression}; + completion.setPreferredRules({ExprParser::RuleSimpleExpression}); { // 1) On the variable reference 'a'. @@ -152,7 +152,7 @@ TEST(SimpleExpressionParser, RecursivePreferredRule) { } { // 2) On the variable reference 'b'. - completion.translateRulesTopDown = false; + completion.setTranslateRulesTopDown(false); auto candidates = completion.collectCandidates(10); // NOLINT: magic EXPECT_THAT(Keys(candidates.rules), UnorderedElementsAre(ExprParser::RuleSimpleExpression)); // When translateRulesTopDown is false, startTokenIndex should match the @@ -162,7 +162,7 @@ TEST(SimpleExpressionParser, RecursivePreferredRule) { } { // 3) On the variable reference 'b' topDown preferred rules. - completion.translateRulesTopDown = true; + completion.setTranslateRulesTopDown(true); auto candidates = completion.collectCandidates(10); // NOLINT: magic EXPECT_THAT(Keys(candidates.rules), UnorderedElementsAre(ExprParser::RuleSimpleExpression)); // When translateRulesTopDown is true, startTokenIndex should match the @@ -178,11 +178,11 @@ TEST(SimpleExpressionParser, CandidateRulesWithDifferentStartTokens) { EXPECT_EQ(pipeline.listener.GetErrorCount(), 0); c3::CodeCompletionCore completion(&pipeline.parser); - completion.preferredRules = { + completion.setPreferredRules({ ExprParser::RuleAssignment, ExprParser::RuleVariableRef, - }; - completion.translateRulesTopDown = true; + }); + completion.setTranslateRulesTopDown(true); { // 1) On the token 'var'.