diff --git a/pom.xml b/pom.xml index c5793fb9..1b2d6b25 100644 --- a/pom.xml +++ b/pom.xml @@ -63,12 +63,12 @@ org.unlaxer unlaxer-common - 3.0.14 + 3.0.15 org.unlaxer unlaxer-dsl - 3.0.14 + 3.0.15 org.jetbrains diff --git a/src/main/java/org/unlaxer/tinyexpression/p4/P4PreferredAstMapper.java b/src/main/java/org/unlaxer/tinyexpression/p4/P4PreferredAstMapper.java index b443dc40..e8e8d3cf 100644 --- a/src/main/java/org/unlaxer/tinyexpression/p4/P4PreferredAstMapper.java +++ b/src/main/java/org/unlaxer/tinyexpression/p4/P4PreferredAstMapper.java @@ -1,7 +1,5 @@ package org.unlaxer.tinyexpression.p4; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @@ -267,41 +265,35 @@ private static TinyExpressionP4AST parseViaMapperCompat( private static ParsedAst parseMappedCandidates( String source, List candidates, boolean allowDefault, long deadlineNanos) { - // unlaxer-dsl 3.0.14 emits only the // branch of @comment even though the - // javaStyle contract also includes block comments. Preserve layout so mapper - // source spans remain valid. This is one lexical input pass, not a retry or an - // alternate parser path; remove it when the generator's delimiter is corrected. + // Keep source offsets stable while accepting comments in positions where the generated + // grammar's interleave metadata is not applied to nested alternatives. String parserSource = TinyExpressionParserCapabilities.stripJavaStyleCommentsPreservingLayout(source); Token rootToken = parseRootToken(parserSource, deadlineNanos); + String sourceForSpanComparison = parserSource; RuntimeException lastFailure = null; - try { - for (String candidate : candidates) { - if (candidate == null || candidate.isBlank()) { + for (String candidate : candidates) { + if (candidate == null || candidate.isBlank()) { + continue; + } + try { + TinyExpressionP4Mapper.MappedAst mappedAst = + TinyExpressionP4Mapper.mapParsedToken(rootToken, candidate); + if (!coversWholeSource(sourceForSpanComparison, mappedAst.token())) { continue; } - try { - clearMapperSourceSpans(); - Token bestMappedToken = invokeFindBestMappedToken(rootToken, candidate); - if (!coversWholeSource(parserSource, bestMappedToken)) { - continue; - } - TinyExpressionP4AST mapped = invokeMapToken(bestMappedToken); - if (mapped != null && candidate.equals(mapped.getClass().getSimpleName())) { - return new ParsedAst(mapped, "preferred:" + candidate); - } - } catch (RuntimeException failure) { - lastFailure = failure; + TinyExpressionP4AST mapped = mappedAst.ast(); + if (mapped != null && candidate.equals(mapped.getClass().getSimpleName())) { + return new ParsedAst(mapped, "preferred:" + candidate); } + } catch (RuntimeException failure) { + lastFailure = failure; } - if (allowDefault) { - clearMapperSourceSpans(); - TinyExpressionP4AST mapped = invokeMapToken(invokeFindBestMappedToken(rootToken, null)); - if (mapped != null) { - return new ParsedAst(mapped, "default"); - } + } + if (allowDefault) { + TinyExpressionP4AST mapped = TinyExpressionP4Mapper.mapParsedToken(rootToken).ast(); + if (mapped != null) { + return new ParsedAst(mapped, "default"); } - } finally { - clearMapperSourceSpans(); } if (lastFailure != null) { throw toParseFailure(lastFailure); @@ -434,39 +426,6 @@ private static void closeParseContextQuietly(ParseContext context) { } } - private static void clearMapperSourceSpans() { - try { - Field field = TinyExpressionP4Mapper.class.getDeclaredField("NODE_SOURCE_SPANS"); - field.setAccessible(true); - Object value = field.get(null); - if (value instanceof java.util.Map map) { - map.clear(); - } - } catch (ReflectiveOperationException ignored) { - } - } - - private static Token invokeFindBestMappedToken(Token rootToken, String preferredAstSimpleName) { - try { - Method method = TinyExpressionP4Mapper.class.getDeclaredMethod( - "findBestMappedToken", Token.class, String.class); - method.setAccessible(true); - return (Token) method.invoke(null, rootToken, preferredAstSimpleName); - } catch (ReflectiveOperationException e) { - throw new IllegalArgumentException("Failed to resolve mapped token", e); - } - } - - private static TinyExpressionP4AST invokeMapToken(Token token) { - try { - Method method = TinyExpressionP4Mapper.class.getDeclaredMethod("mapToken", Token.class); - method.setAccessible(true); - return (TinyExpressionP4AST) method.invoke(null, token); - } catch (ReflectiveOperationException e) { - throw new IllegalArgumentException("Failed to map parse tree", e); - } - } - private static int consumedLengthCompat(Token token) { String text = tokenTextCompat(token); return text == null ? 0 : text.length(); @@ -476,63 +435,11 @@ private static String tokenTextCompat(Token token) { if (token == null) { return null; } - try { - Method method = token.getClass().getMethod("getToken"); - Object value = method.invoke(token); - if (value instanceof java.util.Optional optional && optional.isPresent()) { - Object tokenValue = optional.get(); - return tokenValue == null ? null : String.valueOf(tokenValue); - } - } catch (ReflectiveOperationException ignored) { - } - try { - Field field = token.getClass().getField("tokenString"); - Object value = field.get(token); - if (value instanceof java.util.Optional optional && optional.isPresent()) { - Object tokenValue = optional.get(); - return tokenValue == null ? null : String.valueOf(tokenValue); - } - } catch (ReflectiveOperationException ignored) { - } - try { - Field field = token.getClass().getField("source"); - Object source = field.get(token); - if (source != null) { - Method method = source.getClass().getMethod("sourceAsString"); - Object value = method.invoke(source); - return value == null ? null : String.valueOf(value); - } - } catch (ReflectiveOperationException ignored) { - } - return null; + return token.getToken().orElse(null); } private static StringSource createRootSourceCompat(String source) { - try { - Method method = StringSource.class.getMethod("createRootSource", String.class); - Object value = method.invoke(null, source); - if (value instanceof StringSource stringSource) { - return stringSource; - } - } catch (ReflectiveOperationException ignored) { - } - try { - for (java.lang.reflect.Constructor constructor : StringSource.class.getDeclaredConstructors()) { - Class[] types = constructor.getParameterTypes(); - if (types.length == 0 || types[0] != String.class) { - continue; - } - Object[] args = new Object[types.length]; - args[0] = source; - constructor.setAccessible(true); - Object value = constructor.newInstance(args); - if (value instanceof StringSource stringSource) { - return stringSource; - } - } - } catch (ReflectiveOperationException ignored) { - } - throw new IllegalStateException("No compatible StringSource initializer found"); + return StringSource.createRootSource(source); } private record MatchBody(String body, int bodyStartOffset) {} diff --git a/tools/tinyexpression-p4-lsp-vscode/grammar/tinyexpression-p4.ubnf b/tools/tinyexpression-p4-lsp-vscode/grammar/tinyexpression-p4.ubnf index 84d7776e..e97d006c 100644 --- a/tools/tinyexpression-p4-lsp-vscode/grammar/tinyexpression-p4.ubnf +++ b/tools/tinyexpression-p4-lsp-vscode/grammar/tinyexpression-p4.ubnf @@ -2,7 +2,6 @@ grammar TinyExpressionP4 { @package: org.unlaxer.tinyexpression.generated.p4 @whitespace: javaStyle - @comment: { line: '//' } token NUMBER = org.unlaxer.parser.elementary.NumberParser token IDENTIFIER = org.unlaxer.parser.clang.IdentifierParser @@ -13,6 +12,7 @@ grammar TinyExpressionP4 { token EOF = org.unlaxer.parser.elementary.EndOfSourceParser @root + @interleave(profile=javaStyle) @scopeTree(mode=lexical) @mapping(FormulaExpr, params=[imports, declarations, expression, methods]) Formula ::= { CodeBlock } { ImportDeclaration @imports } { VariableDeclaration @declarations } diff --git a/tools/tinyexpression-p4-lsp-vscode/pom.xml b/tools/tinyexpression-p4-lsp-vscode/pom.xml index 48b2fb18..35f81a5b 100644 --- a/tools/tinyexpression-p4-lsp-vscode/pom.xml +++ b/tools/tinyexpression-p4-lsp-vscode/pom.xml @@ -23,7 +23,7 @@ org.unlaxer unlaxer-dsl - 3.0.14 + 3.0.15 org.unlaxer