diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSFrontendThemes.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSFrontendThemes.java index 03c513c9..1951d704 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSFrontendThemes.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSFrontendThemes.java @@ -34,7 +34,7 @@ public class PBSFrontendThemes { new FrontendTokenStyleSpec("pbs-contract", "#79c0ff", false, false, true), new FrontendTokenStyleSpec("pbs-host", "#c297ff", false, false, false), new FrontendTokenStyleSpec("pbs-builtin-type", "#7ee787", true, false, false), - new FrontendTokenStyleSpec("pbs-service", "#c297ff", false, true, false), + new FrontendTokenStyleSpec("pbs-service", "#ff8e7a", false, true, false), new FrontendTokenStyleSpec("pbs-error", "#ff7b72", false, false, true), new FrontendTokenStyleSpec("pbs-enum", "#56d4dd", false, true, false), new FrontendTokenStyleSpec("pbs-callback", "#ffb3e6", false, false, false), diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSSemanticTokenProvider.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSSemanticTokenProvider.java index b9c082e5..8e177534 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSSemanticTokenProvider.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/PBSSemanticTokenProvider.java @@ -11,7 +11,9 @@ import p.studio.compiler.source.identifiers.FileId; import p.studio.utilities.structures.ReadOnlyList; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProvider { @@ -21,11 +23,12 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv public List tokenize(final String documentText) { final String effectiveText = documentText == null ? "" : documentText; final ReadOnlyList tokens = PbsLexer.lex(effectiveText, FileId.none(), DiagnosticSink.empty()); + final Map declaredKindsByName = collectDeclaredKinds(tokens); final ArrayList semanticTokens = new ArrayList<>(); for (int index = 0; index < tokens.size(); index += 1) { final PbsToken token = tokens.get(index); - final PbsSemanticKind semanticKind = classifyToken(tokens, index); + final PbsSemanticKind semanticKind = classifyToken(tokens, index, declaredKindsByName); if (semanticKind == null) { continue; } @@ -37,7 +40,8 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv private PbsSemanticKind classifyToken( final ReadOnlyList tokens, - final int index) { + final int index, + final Map declaredKindsByName) { final PbsToken token = tokens.get(index); final PbsSemanticKind lexicalKind = PbsSemanticKind.forToken(token); if (lexicalKind != null) { @@ -47,7 +51,7 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv if (isLifecycleToken(tokens, index, token)) { return PbsSemanticKind.LIFECYCLE; } - return classifyIdentifierToken(tokens, index, token); + return classifyIdentifierToken(tokens, index, token, declaredKindsByName); } return null; } @@ -55,7 +59,8 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv private PbsSemanticKind classifyIdentifierToken( final ReadOnlyList tokens, final int index, - final PbsToken token) { + final PbsToken token, + final Map declaredKindsByName) { final PbsTokenKind previousKind = previousSignificantKind(tokens, index); final PbsTokenKind nextKind = nextSignificantKind(tokens, index); @@ -89,6 +94,17 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv if (previousKind == PbsTokenKind.BUILTIN) { return PbsSemanticKind.BUILTIN_TYPE; } + final PbsSemanticKind declaredKind = declaredKindsByName.get(token.lexeme()); + if (declaredKind != null) { + if (previousKind == PbsTokenKind.DOT && nextKind == PbsTokenKind.LEFT_PAREN) { + return PbsSemanticKind.METHOD; + } + if (nextKind == PbsTokenKind.DOT + || previousKind == PbsTokenKind.NEW + || isTypeReferenceContext(previousKind, token.lexeme())) { + return declaredKind; + } + } if (previousKind == PbsTokenKind.DOT && nextKind == PbsTokenKind.LEFT_PAREN) { return PbsSemanticKind.METHOD; } @@ -101,6 +117,39 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv return PbsSemanticKind.IDENTIFIER; } + private Map collectDeclaredKinds(final ReadOnlyList tokens) { + final Map declaredKindsByName = new HashMap<>(); + for (int index = 0; index < tokens.size() - 1; index += 1) { + final PbsToken token = tokens.get(index); + final PbsToken nextToken = tokens.get(index + 1); + if (nextToken.kind() != PbsTokenKind.IDENTIFIER) { + continue; + } + final PbsSemanticKind declarationKind = declarationKind(token.kind()); + if (declarationKind == null) { + continue; + } + declaredKindsByName.put(nextToken.lexeme(), declarationKind); + } + return Map.copyOf(declaredKindsByName); + } + + private PbsSemanticKind declarationKind(final PbsTokenKind kind) { + return switch (kind) { + case STRUCT -> PbsSemanticKind.STRUCT; + case CONTRACT -> PbsSemanticKind.CONTRACT; + case HOST -> PbsSemanticKind.HOST; + case SERVICE -> PbsSemanticKind.SERVICE; + case ENUM, ERROR -> PbsSemanticKind.ENUM; + case CALLBACK -> PbsSemanticKind.CALLBACK; + case GLOBAL -> PbsSemanticKind.GLOBAL; + case CONST -> PbsSemanticKind.CONST; + case CTOR -> PbsSemanticKind.CONSTRUCTOR; + case BUILTIN -> PbsSemanticKind.BUILTIN_TYPE; + default -> null; + }; + } + private boolean isTypeReferenceContext( final PbsTokenKind previousKind, final String lexeme) { diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/PbsSemanticPresentationContractTest.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/PbsSemanticPresentationContractTest.java index 6ef7400b..ff28d4ae 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/PbsSemanticPresentationContractTest.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/test/java/p/studio/compiler/pbs/PbsSemanticPresentationContractTest.java @@ -24,6 +24,7 @@ final class PbsSemanticPresentationContractTest { assertEquals("PBS Default", presentation.defaultTheme().displayName()); assertEquals("#d9e2ec", presentation.defaultTheme().editorPalette().baseForeground()); assertEquals("#d2a8ff", presentation.defaultTheme().requireTokenStyle("pbs-keyword").foreground()); + assertEquals("#ff8e7a", presentation.defaultTheme().requireTokenStyle("pbs-service").foreground()); assertTrue(presentation.defaultTheme().requireTokenStyle("pbs-builtin-type").italic()); assertTrue(presentation.defaultTheme().requireTokenStyle("pbs-comment").italic()); assertEquals(PBSFrontendHostProjections.VSCODE_HOST_ID, presentation.requireHostProjection("vscode").hostId()); @@ -58,11 +59,17 @@ final class PbsSemanticPresentationContractTest { void shouldPublishPbsOwnedSemanticTokenProvider() { final List semanticTokens = PBSDefinitions.PBS.getSemanticTokenProvider().tokenize(""" struct Vec2 {} + service Log {} + host Input {} + enum ResultKind { Ok = 1; } fn main() -> void { const answer: int = 42; let value = new Vec2(); value.length(); + Log.info(); + Input.read(); + let kind: ResultKind; } """); @@ -72,5 +79,8 @@ final class PbsSemanticPresentationContractTest { assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.BUILTIN_TYPE.semanticKey()))); assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.CONSTRUCTOR.semanticKey()))); assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.METHOD.semanticKey()))); + assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.SERVICE.semanticKey()))); + assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.HOST.semanticKey()))); + assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.ENUM.semanticKey()))); } } diff --git a/prometeu-lsp/prometeu-lsp-v1/src/test/java/p/studio/lsp/services/compiler/CompilerLanguageServiceBridgeTest.java b/prometeu-lsp/prometeu-lsp-v1/src/test/java/p/studio/lsp/services/compiler/CompilerLanguageServiceBridgeTest.java index 30d03082..39380c5d 100644 --- a/prometeu-lsp/prometeu-lsp-v1/src/test/java/p/studio/lsp/services/compiler/CompilerLanguageServiceBridgeTest.java +++ b/prometeu-lsp/prometeu-lsp-v1/src/test/java/p/studio/lsp/services/compiler/CompilerLanguageServiceBridgeTest.java @@ -52,10 +52,17 @@ class CompilerLanguageServiceBridgeTest { } } + service Log {} + host Input {} + enum ResultKind { Ok = 1; } + fn main() -> void { const answer: int = 42; let value = new Vec2(); value.length(); + Log.info(); + Input.read(); + let kind: ResultKind; } """); @@ -68,6 +75,9 @@ class CompilerLanguageServiceBridgeTest { assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-const"))); assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-builtin-type"))); assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-constructor"))); + assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-service"))); + assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-host"))); + assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-enum"))); } @Test diff --git a/test-projects/main/.vscode/settings.json b/test-projects/main/.vscode/settings.json index 593300da..1bbfd9cd 100644 --- a/test-projects/main/.vscode/settings.json +++ b/test-projects/main/.vscode/settings.json @@ -36,7 +36,7 @@ "italic": true }, "pbs-service:pbs": { - "foreground": "#c297ff", + "foreground": "#ff8e7a", "bold": true }, "pbs-error:pbs": {