public void Completion_Grammar_TypicalExpression() { // arrange var expression = "var c = a + b"; var inputStream = new AntlrInputStream(expression); var lexer = new ExprLexer(inputStream); var tokenStream = new CommonTokenStream(lexer); var parser = new ExprParser(tokenStream); parser.Interpreter.PredictionMode = PredictionMode.LlExactAmbigDetection; lexer.RemoveErrorListeners(); parser.RemoveErrorListeners(); var errorListener = new CountingErrorListener(); parser.AddErrorListener(errorListener); // act // assert // Specify our entry point var tree = parser.expression(); Check.That(errorListener.ErrorCount).IsEqualTo(0); // Tell the engine to return certain rules to us, which we could use to look up values in a symbol table. var preferredRules = new HashSet <int>() { ExprParser.RULE_functionRef, ExprParser.RULE_variableRef }; // Ignore operators and the generic ID token. var ignoredTokens = new HashSet <int>() { ExprLexer.PLUS, ExprLexer.MINUS, ExprLexer.MULTIPLY, ExprLexer.DIVIDE }; var core = new CodeCompletionCore(parser, preferredRules, ignoredTokens); // 1) At the input start. var candidates = core.CollectCandidates(0, null); Check.That(candidates.Tokens).HasSize(2); Check.That(candidates.Tokens).ContainsKey(ExprLexer.VAR); Check.That(candidates.Tokens).ContainsKey(ExprLexer.LET); Check.That(candidates.Tokens .TryGetValue(ExprLexer.VAR, out var varCandidates)) .IsTrue(); Check.That(candidates.Tokens .TryGetValue(ExprLexer.LET, out var letCandidates)) .IsTrue(); Check.That(varCandidates).HasSize(2); Check.That(letCandidates).HasSize(2); Check.That(varCandidates).IsEqualTo(new[] { ExprLexer.ID, ExprLexer.EQUAL }); Check.That(letCandidates).IsEqualTo(new[] { ExprLexer.ID, ExprLexer.EQUAL }); // 2) On the variable name ('c'). ignoredTokens = new HashSet <int>() { ExprLexer.ID, ExprLexer.PLUS, ExprLexer.MINUS, ExprLexer.MULTIPLY, ExprLexer.DIVIDE, ExprLexer.EQUAL }; core = new CodeCompletionCore(parser, preferredRules, ignoredTokens); candidates = core.CollectCandidates(2, null); Check.That(candidates.Tokens).HasSize(0); // 4) On the equal sign (ignoring whitespace positions from now on). candidates = core.CollectCandidates(4, null); Check.That(candidates.Tokens).HasSize(0); // 5) On the variable reference 'a'. candidates = core.CollectCandidates(6, null); Check.That(candidates.Tokens).HasSize(0); Check.That(candidates.Rules).HasSize(2); // Here we get 2 rule indexes, derived from 2 different IDs possible at this caret position. // These are what we told the engine above to be preferred rules for us. var found = 0; foreach (var candidate in candidates.Rules) { switch (candidate.Key) { case ExprParser.RULE_functionRef: { found++; break; } case ExprParser.RULE_variableRef: { found++; break; } } } Check.That(found).Equals(2); // 6) On the whitespace after the 'a' candidates = core.CollectCandidates(7, null); Check.That(candidates.Tokens).HasSize(0); Check.That(candidates.Rules).HasSize(1); // Here we get 2 rule indexes found = 0; foreach (var candidate in candidates.Rules) { switch (candidate.Key) { case ExprParser.RULE_functionRef: { found++; break; } case ExprParser.RULE_variableRef: { found++; break; } } } Check.That(found).Equals(1); }
public void Completion_Grammar_SimpleExpression() { // arrange var input = "var c = a + b()"; var inputStream = new AntlrInputStream(input); var lexer = new ExprLexer(inputStream); var tokenStream = new CommonTokenStream(lexer); var parser = new ExprParser(tokenStream); lexer.RemoveErrorListeners(); parser.RemoveErrorListeners(); var errorListener = new CountingErrorListener(); parser.AddErrorListener(errorListener); // act // assert // Specify our entry point var tree = parser.expression(); Check.That(errorListener.ErrorCount).IsEqualTo(0); var core = new CodeCompletionCore(parser, null, null); // 1) At the input start. var candidates = core.CollectCandidates(0, null); Check.That(candidates.Tokens).HasSize(3); Check.That(candidates.Tokens).ContainsKey(ExprLexer.VAR); Check.That(candidates.Tokens).ContainsKey(ExprLexer.LET); Check.That(candidates.Tokens).ContainsKey(ExprLexer.ID); Check.That(candidates.Tokens[ExprLexer.VAR]).IsEqualTo(new[] { ExprLexer.ID, ExprLexer.EQUAL }); Check.That(candidates.Tokens[ExprLexer.LET]).IsEqualTo(new[] { ExprLexer.ID, ExprLexer.EQUAL }); Check.That(candidates.Tokens[ExprLexer.ID]).HasSize(0); // 2) On the first whitespace. In real implementations you would do some additional checks where in the whitespace // the caret is, as the outcome is different depending on that position. candidates = core.CollectCandidates(1, null); Check.That(candidates.Tokens).HasSize(1); Check.That(candidates.Tokens).ContainsKey(ExprLexer.ID); // 3) On the variable name ('c'). candidates = core.CollectCandidates(2, null); Check.That(candidates.Tokens).HasSize(1); Check.That(candidates.Tokens).ContainsKey(ExprLexer.ID); // 4) On the equal sign (ignoring whitespace positions from now on). candidates = core.CollectCandidates(4, null); Check.That(candidates.Tokens).HasSize(1); Check.That(candidates.Tokens).ContainsKey(ExprLexer.EQUAL); // 5) On the variable reference 'a'. But since we have not configure the c3 engine to return us var refs // (or function refs for that matter) we only get an ID here. candidates = core.CollectCandidates(6, null); Check.That(candidates.Tokens).HasSize(1); Check.That(candidates.Tokens).ContainsKey(ExprLexer.ID); // 6) On the '+' operator. Usually you would not show operators as candidates, but we have not set up the c3 engine // yet to not return them. candidates = core.CollectCandidates(8, null); Check.That(candidates.Tokens).HasSize(5); Check.That(candidates.Tokens).ContainsKey(ExprLexer.PLUS); Check.That(candidates.Tokens).ContainsKey(ExprLexer.MINUS); Check.That(candidates.Tokens).ContainsKey(ExprLexer.MULTIPLY); Check.That(candidates.Tokens).ContainsKey(ExprLexer.DIVIDE); Check.That(candidates.Tokens).ContainsKey(ExprLexer.OPEN_PAR); }