Skip to content

Completions may be incorrect or missing and throw ClassCastExceptions in v4.2.1.21 #57

@willplatt

Description

@willplatt

Consider this very simple grammer:

namespace org.example.brackets.agl

grammar Brackets {
	sentence = '[' 'x' ']';
	
	skip WHITESPACE = "\s+";
}

And this Java program that uses it to get completions on some example strings:

import net.akehurst.language.agl.Agl;
import net.akehurst.language.agl.simple.ContextWithScope;
import net.akehurst.language.api.processor.CompletionItem;
import net.akehurst.language.api.processor.LanguageProcessor;
import net.akehurst.language.asm.api.Asm;

import java.io.InputStream;
import java.util.List;
import java.util.Scanner;

import static java.nio.charset.StandardCharsets.UTF_8;

public class BracketsSuggestions {
	private static final String GRAMMAR_STRING = readResource(BracketsSuggestions.class.getResourceAsStream("Brackets.agl"));
	private static final LanguageProcessor<Asm, ContextWithScope<Object, Object>> LANGUAGE_PROCESSOR = Agl.INSTANCE.processorFromStringSimpleJava(
			GRAMMAR_STRING, null, null, null, null, null,
			Agl.INSTANCE.configurationSimple(), null).getProcessor();
	
	public static void main(String[] args) {
		System.out.print("Initial suggestions:          ");
		printSuggestions("", 0);
		System.out.print("Suggestions after '[':        ");
		printSuggestions("[", 1);
		System.out.print("Suggestions after '[ ':       ");
		printSuggestions("[ ", 2);
		System.out.print("Suggestions after '[x':       ");
		printSuggestions("[x", 2);
		System.out.print("Suggestions within '[ ':      ");
		printSuggestions("[ ", 1);
		System.out.print("Suggestions within '[]':      ");
		printSuggestions("[]", 1);
		System.out.print("Suggestions within '[  ]':    ");
		printSuggestions("[  ]", 3);
		System.out.print("Suggestions after '[x]':      ");
		printSuggestions("[x]", 3);
		System.out.print("Suggestions after '[x] ':     ");
		printSuggestions("[x] ", 4);
	}
	
	private static String readResource(InputStream resourceStream) {
		return new Scanner(resourceStream, UTF_8).useDelimiter("\\A").next();
	}
	
	private static void printSuggestions(String str, int position) {
		System.out.println(String.join(", ", getSuggestions(str, position)));
	}
	
	private static List<String> getSuggestions(String str, int position) {
		try {
			return LANGUAGE_PROCESSOR.expectedItemsAt(str, position, LANGUAGE_PROCESSOR.optionsDefault()).getItems().stream().map(CompletionItem::getText)
					.toList();
		} catch (ClassCastException e) {
			e.printStackTrace();
			return List.of();
		}
	}
}

Hopefully this is an appropriate way to initialise the LanguageProcessor; I don't know if I should be providing more parameters or using some other configuration.

This is the kind of output I would expect ("[x]" would be acceptable in place of "[", as would "x]" in place of "x"; indeed, that may even be preferable):

Initial suggestions:          [
Suggestions after '[':        x
Suggestions after '[ ':       x
Suggestions after '[x':       ]
Suggestions within '[ ':      x
Suggestions within '[]':      x
Suggestions within '[  ]':    x
Suggestions after '[x]':      
Suggestions after '[x] ':     

But here is the actual output:

Initial suggestions:          [ x ], [
Suggestions after '[':        [ x ], [
Suggestions after '[ ':       x
Suggestions after '[x':       
Suggestions within '[ ':      [ x ], [
Suggestions within '[]':      [ x ], [
Suggestions within '[  ]':    x
Suggestions after '[x]':      
Suggestions after '[x] ':     

Note the clearly incorrect suggestion of "[" after an existing "[" and the missing suggestions of "]" and "x". The suggestion of "[ x ]" after a "[" also appears incorrect, although it could be interpreted as suggesting the existing string be replaced by "[ x ]".

The problem may be related to whitespace; whitespace appears to be expected between each literal, although the grammar doesn't require it (parsing works as expected). But removing the line from the grammar that makes whitespace skippable results in almost identical suggestions (still incorrect and lacking).

ClassCastException

Finally, note that I have to catch ClassCastException in the program above, because with another grammar like below it throws this exception (for every attempt to get completions except the last one):

java.lang.ClassCastException: class net.akehurst.language.grammar.asm.SimpleListDefault cannot be cast to class net.akehurst.language.grammar.api.TangibleItem (net.akehurst.language.grammar.asm.SimpleListDefault and net.akehurst.language.grammar.api.TangibleItem are in unnamed module of loader 'app')
	at net.akehurst.language.agl.completionProvider.SpineDefault.expectedNextLeafNonTerminalOrTerminal_delegate$lambda$1(CompletionProviderAbstract.kt:69)
	at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:83)
	at net.akehurst.language.agl.completionProvider.SpineDefault.getExpectedNextLeafNonTerminalOrTerminal(CompletionProviderAbstract.kt:64)
	at net.akehurst.language.agl.simple.CompletionProviderSimple.provide(CompletionProviderSimple.kt:66)
	at net.akehurst.language.agl.processor.LanguageProcessorAbstract.expectedItemsAt(LanguageProcessorAbstract.kt:296)
	at BracketsSuggestions.getSuggestions(BracketsSuggestions.java:50)
	at BracketsSuggestions.printSuggestions(BracketsSuggestions.java:45)
	at BracketsSuggestions.main(BracketsSuggestions.java:21)

Grammar causing the exception:

namespace org.example.bracketscomplex.agl

grammar BracketsComplex {
	sentence = word | bracketed;
	bracketed = '[' word* ']';
	word = NAME;
	
	leaf NAME = NAME_CHAR+;
	leaf NAME_CHAR = "[-.0-9]";
	
	skip WHITESPACE = "\s+";
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions