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 492d342c..03c513c9 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 @@ -12,34 +12,34 @@ public class PBSFrontendThemes { "PBS Default", new FrontendEditorPaletteSpec( "#d9e2ec", - "#2d4f6b", - "#2d4f6b", - "#6f8193", - "#2c2140", - "#a47dff", - "#efe6ff"), + "#2f3f5b", + "#23314a", + "#6b7f99", + "#241f38", + "#b392f0", + "#f5efff"), List.of( - new FrontendTokenStyleSpec("pbs-comment", "#c090b0", true, false, false), - new FrontendTokenStyleSpec("pbs-string", "#00c088", false, false, false), - new FrontendTokenStyleSpec("pbs-number", "#ff90b0", false, false, false), - new FrontendTokenStyleSpec("pbs-literal", "#4fc1ff", false, false, false), - new FrontendTokenStyleSpec("pbs-lifecycle", "#ef50c0", false, false, false), - new FrontendTokenStyleSpec("pbs-keyword", "#569cd6", false, false, false), - new FrontendTokenStyleSpec("pbs-operator", "#d4d4d4", false, false, false), - new FrontendTokenStyleSpec("pbs-punctuation", "#d4d4d4", false, false, false), - new FrontendTokenStyleSpec("pbs-function", "#f2c14e", false, false, false), - new FrontendTokenStyleSpec("pbs-method", "#f2c14e", false, false, false), - new FrontendTokenStyleSpec("pbs-constructor", "#ecdcaa", false, false, false), - new FrontendTokenStyleSpec("pbs-struct", "#4ec9b0", false, false, false), - new FrontendTokenStyleSpec("pbs-contract", "#78dce8", false, false, false), - new FrontendTokenStyleSpec("pbs-host", "#b7a2fa", false, false, false), - new FrontendTokenStyleSpec("pbs-builtin-type", "#8be9fd", false, false, false), - new FrontendTokenStyleSpec("pbs-service", "#b7a2fa", false, false, false), - new FrontendTokenStyleSpec("pbs-error", "#ff5b5b", false, false, false), - new FrontendTokenStyleSpec("pbs-enum", "#56cfe1", false, false, false), - new FrontendTokenStyleSpec("pbs-callback", "#b7a2fa", false, false, false), - new FrontendTokenStyleSpec("pbs-global", "#f790fc", true, false, false), - new FrontendTokenStyleSpec("pbs-const", "#f78c6c", false, false, false), - new FrontendTokenStyleSpec("pbs-implements", "#a1c181", false, false, false), + new FrontendTokenStyleSpec("pbs-comment", "#8b949e", true, false, false), + new FrontendTokenStyleSpec("pbs-string", "#7ee787", false, false, false), + new FrontendTokenStyleSpec("pbs-number", "#ffa657", false, false, false), + new FrontendTokenStyleSpec("pbs-literal", "#79c0ff", false, false, false), + new FrontendTokenStyleSpec("pbs-lifecycle", "#ff7b72", false, true, false), + new FrontendTokenStyleSpec("pbs-keyword", "#d2a8ff", false, false, false), + new FrontendTokenStyleSpec("pbs-operator", "#c9d1d9", false, false, false), + new FrontendTokenStyleSpec("pbs-punctuation", "#8b949e", false, false, false), + new FrontendTokenStyleSpec("pbs-function", "#ffa657", false, true, false), + new FrontendTokenStyleSpec("pbs-method", "#ffd580", false, false, false), + new FrontendTokenStyleSpec("pbs-constructor", "#e3b341", false, true, false), + new FrontendTokenStyleSpec("pbs-struct", "#56d4dd", false, false, false), + 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-error", "#ff7b72", false, false, true), + new FrontendTokenStyleSpec("pbs-enum", "#56d4dd", false, true, false), + new FrontendTokenStyleSpec("pbs-callback", "#ffb3e6", false, false, false), + new FrontendTokenStyleSpec("pbs-global", "#f778ba", true, false, false), + new FrontendTokenStyleSpec("pbs-const", "#ffab70", false, true, false), + new FrontendTokenStyleSpec("pbs-implements", "#a5d6ff", false, false, false), new FrontendTokenStyleSpec("pbs-identifier", "#d4d4d4", false, false, false))); } diff --git a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsSemanticKind.java b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsSemanticKind.java index 0c577e4a..bae8c491 100644 --- a/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsSemanticKind.java +++ b/prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsSemanticKind.java @@ -51,12 +51,13 @@ public enum PbsSemanticKind { case COMMENT -> COMMENT; case STRING_LITERAL -> STRING; case INT_LITERAL, FLOAT_LITERAL, BOUNDED_LITERAL -> NUMBER; - case TRUE, FALSE, NONE -> LITERAL; + case TRUE, FALSE, NONE, SOME, OK, ERR -> LITERAL; + case VOID, OPTIONAL, RESULT -> BUILTIN_TYPE; case IMPORT, FROM, AS, SERVICE, HOST, FN, APPLY, BIND, NEW, IMPLEMENTS, USING, CTOR, DECLARE, LET, CONST, GLOBAL, STRUCT, CONTRACT, ERROR, ENUM, CALLBACK, BUILTIN, SELF, THIS, PUB, MUT, MOD, TYPE, IF, ELSE, SWITCH, DEFAULT, FOR, UNTIL, STEP, - WHILE, BREAK, CONTINUE, RETURN, VOID, OPTIONAL, RESULT, SOME, OK, ERR, HANDLE, - AND, OR, NOT, SPAWN, YIELD, SLEEP, MATCH -> KEYWORD; + WHILE, BREAK, CONTINUE, RETURN, HANDLE, AND, OR, NOT, SPAWN, YIELD, SLEEP, + MATCH -> KEYWORD; case PLUS, MINUS, STAR, SLASH, PERCENT, BANG, PLUS_EQUAL, MINUS_EQUAL, STAR_EQUAL, SLASH_EQUAL, PERCENT_EQUAL, BANG_EQUAL, EQUAL, EQUAL_EQUAL, LESS, LESS_EQUAL, GREATER, GREATER_EQUAL, AND_AND, OR_OR, ARROW, QUESTION -> OPERATOR; 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 3e26eb5e..743b144f 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 @@ -20,7 +20,8 @@ final class PbsSemanticPresentationContractTest { assertEquals(1, presentation.themes().size()); assertEquals("PBS Default", presentation.defaultTheme().displayName()); assertEquals("#d9e2ec", presentation.defaultTheme().editorPalette().baseForeground()); - assertEquals("#569cd6", presentation.defaultTheme().requireTokenStyle("pbs-keyword").foreground()); + assertEquals("#d2a8ff", presentation.defaultTheme().requireTokenStyle("pbs-keyword").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()); } diff --git a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/models/FrontendSemanticPresentationSpec.java b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/models/FrontendSemanticPresentationSpec.java index 9a4a6309..69938d91 100644 --- a/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/models/FrontendSemanticPresentationSpec.java +++ b/prometeu-compiler/prometeu-compiler-core/src/main/java/p/studio/compiler/models/FrontendSemanticPresentationSpec.java @@ -8,12 +8,6 @@ public record FrontendSemanticPresentationSpec( String defaultThemeId, List hostProjections) { - public FrontendSemanticPresentationSpec( - final List themes, - final String defaultThemeId) { - this(themes, defaultThemeId, List.of()); - } - public FrontendSemanticPresentationSpec { themes = List.copyOf(Objects.requireNonNull(themes, "themes")); defaultThemeId = Objects.requireNonNull(defaultThemeId, "defaultThemeId").trim(); diff --git a/prometeu-lsp/prometeu-lsp-v1/src/main/java/p/studio/lsp/services/compiler/CompilerLanguageServiceBridge.java b/prometeu-lsp/prometeu-lsp-v1/src/main/java/p/studio/lsp/services/compiler/CompilerLanguageServiceBridge.java index c85617d8..9a2d14a7 100644 --- a/prometeu-lsp/prometeu-lsp-v1/src/main/java/p/studio/lsp/services/compiler/CompilerLanguageServiceBridge.java +++ b/prometeu-lsp/prometeu-lsp-v1/src/main/java/p/studio/lsp/services/compiler/CompilerLanguageServiceBridge.java @@ -14,6 +14,7 @@ import p.studio.compiler.models.FrontendVisualThemeSpec; import p.studio.compiler.pbs.PbsSemanticKind; import p.studio.compiler.pbs.lexer.PbsLexer; import p.studio.compiler.pbs.lexer.PbsToken; +import p.studio.compiler.pbs.lexer.PbsTokenKind; import p.studio.compiler.source.identifiers.FileId; import p.studio.compiler.source.diagnostics.DiagnosticSink; import p.studio.compiler.utilities.SourceProviderFactory; @@ -29,8 +30,11 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; public record CompilerLanguageServiceBridge() implements LanguageServiceBridge { + private static final Set BUILTIN_TYPE_NAMES = Set.of("int", "float", "bool", "string", "i32", "i64", "f32", "f64"); + @Override public BaselineServerDescription describeServer(final LspProjectContext context) { @@ -182,7 +186,97 @@ public record CompilerLanguageServiceBridge() implements LanguageServiceBridge { if (isLifecycleToken(tokens, index, token)) { return PbsSemanticKind.LIFECYCLE; } - return PbsSemanticKind.IDENTIFIER; + return classifyIdentifierToken(tokens, index, token); + } + return null; + } + + private PbsSemanticKind classifyIdentifierToken( + final ReadOnlyList tokens, + final int index, + final PbsToken token) { + final PbsTokenKind previousKind = previousSignificantKind(tokens, index); + final PbsTokenKind nextKind = nextSignificantKind(tokens, index); + + if (previousKind == PbsTokenKind.STRUCT) { + return PbsSemanticKind.STRUCT; + } + if (previousKind == PbsTokenKind.CONTRACT) { + return PbsSemanticKind.CONTRACT; + } + if (previousKind == PbsTokenKind.HOST) { + return PbsSemanticKind.HOST; + } + if (previousKind == PbsTokenKind.SERVICE) { + return PbsSemanticKind.SERVICE; + } + if (previousKind == PbsTokenKind.ENUM || previousKind == PbsTokenKind.ERROR) { + return PbsSemanticKind.ENUM; + } + if (previousKind == PbsTokenKind.CALLBACK) { + return PbsSemanticKind.CALLBACK; + } + if (previousKind == PbsTokenKind.GLOBAL) { + return PbsSemanticKind.GLOBAL; + } + if (previousKind == PbsTokenKind.CONST) { + return PbsSemanticKind.CONST; + } + if (previousKind == PbsTokenKind.CTOR || previousKind == PbsTokenKind.NEW) { + return PbsSemanticKind.CONSTRUCTOR; + } + if (previousKind == PbsTokenKind.BUILTIN) { + return PbsSemanticKind.BUILTIN_TYPE; + } + if (previousKind == PbsTokenKind.DOT && nextKind == PbsTokenKind.LEFT_PAREN) { + return PbsSemanticKind.METHOD; + } + if (nextKind == PbsTokenKind.LEFT_PAREN) { + return PbsSemanticKind.FUNCTION; + } + if (isTypeReferenceContext(previousKind, token.lexeme())) { + return PbsSemanticKind.BUILTIN_TYPE; + } + return PbsSemanticKind.IDENTIFIER; + } + + private boolean isTypeReferenceContext( + final PbsTokenKind previousKind, + final String lexeme) { + if (previousKind == null) { + return false; + } + if (previousKind != PbsTokenKind.COLON + && previousKind != PbsTokenKind.ARROW + && previousKind != PbsTokenKind.AS + && previousKind != PbsTokenKind.IMPLEMENTS) { + return false; + } + return BUILTIN_TYPE_NAMES.contains(lexeme); + } + + private PbsTokenKind previousSignificantKind( + final ReadOnlyList tokens, + final int index) { + for (int cursor = index - 1; cursor >= 0; cursor -= 1) { + final PbsTokenKind kind = tokens.get(cursor).kind(); + if (kind == PbsTokenKind.COMMENT || kind == PbsTokenKind.EOF) { + continue; + } + return kind; + } + return null; + } + + private PbsTokenKind nextSignificantKind( + final ReadOnlyList tokens, + final int index) { + for (int cursor = index + 1; cursor < tokens.size(); cursor += 1) { + final PbsTokenKind kind = tokens.get(cursor).kind(); + if (kind == PbsTokenKind.COMMENT || kind == PbsTokenKind.EOF) { + continue; + } + return kind; } return null; } 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 1c3c0a61..30d03082 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 @@ -46,14 +46,28 @@ class CompilerLanguageServiceBridgeTest { new LspProjectContext("main", "pbs", Path.of(".")), Path.of("demo.pbs").toUri().toString(), """ + struct Vec2 { + fn length() -> int { + return 0; + } + } + fn main() -> void { - const answer = 42; + const answer: int = 42; + let value = new Vec2(); + value.length(); } """); assertTrue(semanticTokens.legend().contains("pbs-keyword")); assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-keyword"))); assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-number"))); + assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-struct"))); + assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-function"))); + assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-method"))); + 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"))); } @Test @@ -74,7 +88,7 @@ class CompilerLanguageServiceBridgeTest { assertEquals("#d9e2ec", description.visualThemes().getFirst().editorPalette().baseForeground()); assertTrue(description.visualThemes().getFirst().tokenStyles().stream() .anyMatch(tokenStyle -> tokenStyle.semanticKey().equals("pbs-keyword") - && tokenStyle.foreground().equals("#569cd6"))); + && tokenStyle.foreground().equals("#d2a8ff"))); } private Path findRepoRoot(final Path start) { diff --git a/test-projects/main/.vscode/settings.json b/test-projects/main/.vscode/settings.json index afd4ce90..593300da 100644 --- a/test-projects/main/.vscode/settings.json +++ b/test-projects/main/.vscode/settings.json @@ -3,66 +3,117 @@ "enabled": true, "rules": { "pbs-comment:pbs": { - "foreground": "#c090b0", + "foreground": "#8b949e", "italic": true }, - "pbs-string:pbs": "#00c088", - "pbs-number:pbs": "#ff90b0", - "pbs-literal:pbs": "#4fc1ff", - "pbs-lifecycle:pbs": "#ef50c0", - "pbs-keyword:pbs": "#569cd6", - "pbs-operator:pbs": "#d4d4d4", - "pbs-punctuation:pbs": "#d4d4d4", - "pbs-function:pbs": "#f2c14e", - "pbs-method:pbs": "#f2c14e", - "pbs-constructor:pbs": "#ecdcaa", - "pbs-struct:pbs": "#4ec9b0", - "pbs-contract:pbs": "#78dce8", - "pbs-host:pbs": "#b7a2fa", - "pbs-builtin-type:pbs": "#8be9fd", - "pbs-service:pbs": "#b7a2fa", - "pbs-error:pbs": "#ff5b5b", - "pbs-enum:pbs": "#56cfe1", - "pbs-callback:pbs": "#b7a2fa", + "pbs-string:pbs": "#7ee787", + "pbs-number:pbs": "#ffa657", + "pbs-literal:pbs": "#79c0ff", + "pbs-lifecycle:pbs": { + "foreground": "#ff7b72", + "bold": true + }, + "pbs-keyword:pbs": "#d2a8ff", + "pbs-operator:pbs": "#c9d1d9", + "pbs-punctuation:pbs": "#8b949e", + "pbs-function:pbs": { + "foreground": "#ffa657", + "bold": true + }, + "pbs-method:pbs": "#ffd580", + "pbs-constructor:pbs": { + "foreground": "#e3b341", + "bold": true + }, + "pbs-struct:pbs": "#56d4dd", + "pbs-contract:pbs": { + "foreground": "#79c0ff", + "underline": true + }, + "pbs-host:pbs": "#c297ff", + "pbs-builtin-type:pbs": { + "foreground": "#7ee787", + "italic": true + }, + "pbs-service:pbs": { + "foreground": "#c297ff", + "bold": true + }, + "pbs-error:pbs": { + "foreground": "#ff7b72", + "underline": true + }, + "pbs-enum:pbs": { + "foreground": "#56d4dd", + "bold": true + }, + "pbs-callback:pbs": "#ffb3e6", "pbs-global:pbs": { - "foreground": "#f790fc", + "foreground": "#f778ba", "italic": true }, - "pbs-const:pbs": "#f78c6c", - "pbs-implements:pbs": "#a1c181", + "pbs-const:pbs": { + "foreground": "#ffab70", + "bold": true + }, + "pbs-implements:pbs": "#a5d6ff", "pbs-identifier:pbs": "#d4d4d4", "comment:pbs": { - "foreground": "#c090b0", + "foreground": "#8b949e", "italic": true }, - "string:pbs": "#00c088", - "number:pbs": "#ff90b0", - "enumMember:pbs": "#4fc1ff", - "variable:pbs": "#4fc1ff", - "function.async:pbs": "#ef50c0", - "variable.async:pbs": "#ef50c0", - "keyword:pbs": "#569cd6", - "operator:pbs": "#d4d4d4", - "function:pbs": "#f2c14e", - "method:pbs": "#f2c14e", - "class.declaration:pbs": "#ecdcaa", - "type.declaration:pbs": "#ecdcaa", - "struct:pbs": "#4ec9b0", - "type:pbs": "#4ec9b0", - "interface:pbs": "#78dce8", - "class.defaultLibrary:pbs": "#b7a2fa", - "type.defaultLibrary:pbs": "#b7a2fa", - "variable.defaultLibrary:pbs": "#8be9fd", - "enum:pbs": "#ff5b5b", + "string:pbs": "#7ee787", + "number:pbs": "#ffa657", + "enumMember:pbs": "#79c0ff", + "variable:pbs": "#79c0ff", + "function.async:pbs": { + "foreground": "#ff7b72", + "bold": true + }, + "variable.async:pbs": { + "foreground": "#ff7b72", + "bold": true + }, + "keyword:pbs": "#d2a8ff", + "operator:pbs": "#c9d1d9", + "function:pbs": { + "foreground": "#ffa657", + "bold": true + }, + "method:pbs": "#ffd580", + "class.declaration:pbs": { + "foreground": "#e3b341", + "bold": true + }, + "type.declaration:pbs": { + "foreground": "#e3b341", + "bold": true + }, + "struct:pbs": "#56d4dd", + "type:pbs": "#56d4dd", + "interface:pbs": { + "foreground": "#79c0ff", + "underline": true + }, + "class.defaultLibrary:pbs": "#c297ff", + "type.defaultLibrary:pbs": "#c297ff", + "variable.defaultLibrary:pbs": { + "foreground": "#7ee787", + "italic": true + }, + "enum:pbs": { + "foreground": "#ff7b72", + "underline": true + }, "variable.readonly:pbs": { - "foreground": "#f790fc", + "foreground": "#f778ba", "italic": true } } }, "workbench.colorCustomizations": { "editor.foreground": "#d9e2ec", - "editor.selectionBackground": "#2d4f6b", - "editorLineNumber.foreground": "#6f8193" + "editor.selectionBackground": "#2f3f5b", + "editorLineNumber.foreground": "#6b7f99" } } \ No newline at end of file