Highlight color adjustments

This commit is contained in:
bQUARKz 2026-05-07 14:21:31 +01:00
parent dfad621d05
commit 905d92afe7
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
9 changed files with 705 additions and 462 deletions

View File

@ -39,6 +39,7 @@ public final class PBSFrontendHostProjections {
case HOST -> projection(HOST.semanticKey(), "class", "type", "defaultLibrary"); case HOST -> projection(HOST.semanticKey(), "class", "type", "defaultLibrary");
case BUILTIN_TYPE -> projection(BUILTIN_TYPE.semanticKey(), "type", "variable", "defaultLibrary"); case BUILTIN_TYPE -> projection(BUILTIN_TYPE.semanticKey(), "type", "variable", "defaultLibrary");
case SERVICE -> projection(SERVICE.semanticKey(), "class", "type", "defaultLibrary"); case SERVICE -> projection(SERVICE.semanticKey(), "class", "type", "defaultLibrary");
case ASSET -> projection(ASSET.semanticKey(), "variable", "string", "readonly");
case ERROR -> projection(ERROR.semanticKey(), "enum", "type"); case ERROR -> projection(ERROR.semanticKey(), "enum", "type");
case ENUM -> projection(ENUM.semanticKey(), "enum", "type"); case ENUM -> projection(ENUM.semanticKey(), "enum", "type");
case CALLBACK -> projection(CALLBACK.semanticKey(), "interface", "type"); case CALLBACK -> projection(CALLBACK.semanticKey(), "interface", "type");

View File

@ -20,21 +20,22 @@ public class PBSFrontendThemes {
"#f5efff"), "#f5efff"),
List.of( List.of(
new FrontendTokenStyleSpec("pbs-comment", "#8b949e", true, false, false), new FrontendTokenStyleSpec("pbs-comment", "#8b949e", true, false, false),
new FrontendTokenStyleSpec("pbs-string", "#7ee787", false, false, false), new FrontendTokenStyleSpec("pbs-string", "#d8b86a", false, false, false),
new FrontendTokenStyleSpec("pbs-number", "#ffa657", false, false, false), new FrontendTokenStyleSpec("pbs-number", "#ff8cc6", false, false, false),
new FrontendTokenStyleSpec("pbs-literal", "#79c0ff", false, false, false), new FrontendTokenStyleSpec("pbs-literal", "#7fb8ff", false, false, false),
new FrontendTokenStyleSpec("pbs-lifecycle", "#ff7b72", false, true, false), new FrontendTokenStyleSpec("pbs-lifecycle", "#ff7b72", false, true, false),
new FrontendTokenStyleSpec("pbs-keyword", "#d2a8ff", false, false, false), new FrontendTokenStyleSpec("pbs-keyword", "#7fb8ff", false, false, false),
new FrontendTokenStyleSpec("pbs-operator", "#c9d1d9", false, false, false), new FrontendTokenStyleSpec("pbs-operator", "#c9d1d9", false, false, false),
new FrontendTokenStyleSpec("pbs-punctuation", "#8b949e", false, false, false), new FrontendTokenStyleSpec("pbs-punctuation", "#8b949e", false, false, false),
new FrontendTokenStyleSpec("pbs-function", "#ffa657", false, true, false), new FrontendTokenStyleSpec("pbs-function", "#7ee787", false, true, false),
new FrontendTokenStyleSpec("pbs-method", "#ffd580", false, false, false), new FrontendTokenStyleSpec("pbs-method", "#7ee787", false, false, false),
new FrontendTokenStyleSpec("pbs-constructor", "#e3b341", false, true, false), new FrontendTokenStyleSpec("pbs-constructor", "#7ee787", false, true, false),
new FrontendTokenStyleSpec("pbs-struct", "#56d4dd", false, false, false), new FrontendTokenStyleSpec("pbs-struct", "#56d4dd", true, false, false),
new FrontendTokenStyleSpec("pbs-contract", "#79c0ff", false, false, true), new FrontendTokenStyleSpec("pbs-contract", "#79c0ff", false, false, true),
new FrontendTokenStyleSpec("pbs-host", "#c297ff", false, false, false), new FrontendTokenStyleSpec("pbs-host", "#c297ff", false, false, false),
new FrontendTokenStyleSpec("pbs-builtin-type", "#7ee787", true, false, false), new FrontendTokenStyleSpec("pbs-builtin-type", "#56d4dd", false, false, false),
new FrontendTokenStyleSpec("pbs-service", "#ff8e7a", false, true, false), new FrontendTokenStyleSpec("pbs-service", "#ff8e7a", false, true, false),
new FrontendTokenStyleSpec("pbs-asset", "#c297ff", false, false, false),
new FrontendTokenStyleSpec("pbs-error", "#ff7b72", false, false, true), new FrontendTokenStyleSpec("pbs-error", "#ff7b72", false, false, true),
new FrontendTokenStyleSpec("pbs-enum", "#56d4dd", false, true, false), new FrontendTokenStyleSpec("pbs-enum", "#56d4dd", false, true, false),
new FrontendTokenStyleSpec("pbs-callback", "#ffb3e6", false, false, false), new FrontendTokenStyleSpec("pbs-callback", "#ffb3e6", false, false, false),

View File

@ -2,33 +2,44 @@ package p.studio.compiler;
import p.studio.compiler.models.FrontendSemanticToken; import p.studio.compiler.models.FrontendSemanticToken;
import p.studio.compiler.models.FrontendSemanticTokenProvider; import p.studio.compiler.models.FrontendSemanticTokenProvider;
import p.studio.compiler.pbs.ast.PbsAst;
import p.studio.compiler.pbs.PbsSemanticKind; import p.studio.compiler.pbs.PbsSemanticKind;
import p.studio.compiler.pbs.lexer.PbsLexer; import p.studio.compiler.pbs.lexer.PbsLexer;
import p.studio.compiler.pbs.lexer.PbsToken; import p.studio.compiler.pbs.lexer.PbsToken;
import p.studio.compiler.pbs.lexer.PbsTokenKind; import p.studio.compiler.pbs.lexer.PbsTokenKind;
import p.studio.compiler.pbs.parser.PbsBarrelParser;
import p.studio.compiler.pbs.parser.PbsParser;
import p.studio.compiler.pbs.stdlib.ResourceStdlibEnvironmentResolver;
import p.studio.compiler.pbs.stdlib.StdlibModuleSource;
import p.studio.compiler.source.diagnostics.DiagnosticSink; import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.compiler.source.identifiers.FileId; import p.studio.compiler.source.identifiers.FileId;
import p.studio.utilities.structures.ReadOnlyList; import p.studio.utilities.structures.ReadOnlyList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProvider { public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProvider {
private static final Set<String> BUILTIN_TYPE_NAMES = Set.of("int", "float", "bool", "string", "i32", "i64", "f32", "f64"); private static final Set<String> BUILTIN_TYPE_NAMES = Set.of("int", "float", "bool", "string", "i32", "i64", "f32", "f64");
private static final int DEFAULT_STDLIB_VERSION = 1;
private static final ResourceStdlibEnvironmentResolver STDLIB_RESOLVER = new ResourceStdlibEnvironmentResolver();
private static final Map<PbsTokenKind, PbsSemanticKind> DECLARATION_KINDS = declarationKinds();
@Override @Override
public List<FrontendSemanticToken> tokenize(final String documentText) { public List<FrontendSemanticToken> tokenize(final String documentText) {
final String effectiveText = documentText == null ? "" : documentText; final String effectiveText = documentText == null ? "" : documentText;
final ReadOnlyList<PbsToken> tokens = PbsLexer.lex(effectiveText, FileId.none(), DiagnosticSink.empty()); final ReadOnlyList<PbsToken> tokens = PbsLexer.lex(effectiveText, FileId.none(), DiagnosticSink.empty());
final Map<String, PbsSemanticKind> declaredKindsByName = collectDeclaredKinds(tokens); final Map<String, PbsSemanticKind> declaredKindsByName = collectDeclaredKinds(tokens);
final Set<Integer> assetReferenceTokenIndexes = collectAssetReferenceTokenIndexes(tokens);
final ArrayList<FrontendSemanticToken> semanticTokens = new ArrayList<>(); final ArrayList<FrontendSemanticToken> semanticTokens = new ArrayList<>();
for (int index = 0; index < tokens.size(); index += 1) { for (int index = 0; index < tokens.size(); index += 1) {
final PbsToken token = tokens.get(index); final PbsToken token = tokens.get(index);
final PbsSemanticKind semanticKind = classifyToken(tokens, index, declaredKindsByName); final PbsSemanticKind semanticKind = classifyToken(tokens, index, declaredKindsByName, assetReferenceTokenIndexes);
if (semanticKind == null) { if (semanticKind == null) {
continue; continue;
} }
@ -41,13 +52,17 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv
private PbsSemanticKind classifyToken( private PbsSemanticKind classifyToken(
final ReadOnlyList<PbsToken> tokens, final ReadOnlyList<PbsToken> tokens,
final int index, final int index,
final Map<String, PbsSemanticKind> declaredKindsByName) { final Map<String, PbsSemanticKind> declaredKindsByName,
final Set<Integer> assetReferenceTokenIndexes) {
final PbsToken token = tokens.get(index); final PbsToken token = tokens.get(index);
final PbsSemanticKind lexicalKind = PbsSemanticKind.forToken(token); final PbsSemanticKind lexicalKind = PbsSemanticKind.forToken(token);
if (lexicalKind != null) { if (lexicalKind != null) {
return lexicalKind; return lexicalKind;
} }
if (token.kind() == PbsTokenKind.IDENTIFIER) { if (token.kind() == PbsTokenKind.IDENTIFIER) {
if (assetReferenceTokenIndexes.contains(index)) {
return PbsSemanticKind.ASSET;
}
if (isLifecycleToken(tokens, index, token)) { if (isLifecycleToken(tokens, index, token)) {
return PbsSemanticKind.LIFECYCLE; return PbsSemanticKind.LIFECYCLE;
} }
@ -63,6 +78,7 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv
final Map<String, PbsSemanticKind> declaredKindsByName) { final Map<String, PbsSemanticKind> declaredKindsByName) {
final PbsTokenKind previousKind = previousSignificantKind(tokens, index); final PbsTokenKind previousKind = previousSignificantKind(tokens, index);
final PbsTokenKind nextKind = nextSignificantKind(tokens, index); final PbsTokenKind nextKind = nextSignificantKind(tokens, index);
final boolean typeReferenceContext = isTypeReferenceContext(previousKind);
if (previousKind == PbsTokenKind.STRUCT) { if (previousKind == PbsTokenKind.STRUCT) {
return PbsSemanticKind.STRUCT; return PbsSemanticKind.STRUCT;
@ -101,7 +117,7 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv
} }
if (nextKind == PbsTokenKind.DOT if (nextKind == PbsTokenKind.DOT
|| previousKind == PbsTokenKind.NEW || previousKind == PbsTokenKind.NEW
|| isTypeReferenceContext(previousKind, token.lexeme())) { || typeReferenceContext) {
return declaredKind; return declaredKind;
} }
} }
@ -111,7 +127,7 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv
if (nextKind == PbsTokenKind.LEFT_PAREN) { if (nextKind == PbsTokenKind.LEFT_PAREN) {
return PbsSemanticKind.FUNCTION; return PbsSemanticKind.FUNCTION;
} }
if (isTypeReferenceContext(previousKind, token.lexeme())) { if (typeReferenceContext && BUILTIN_TYPE_NAMES.contains(token.lexeme())) {
return PbsSemanticKind.BUILTIN_TYPE; return PbsSemanticKind.BUILTIN_TYPE;
} }
return PbsSemanticKind.IDENTIFIER; return PbsSemanticKind.IDENTIFIER;
@ -131,28 +147,163 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv
} }
declaredKindsByName.put(nextToken.lexeme(), declarationKind); declaredKindsByName.put(nextToken.lexeme(), declarationKind);
} }
declaredKindsByName.putAll(collectStdlibImportedKinds(tokens));
return Map.copyOf(declaredKindsByName); return Map.copyOf(declaredKindsByName);
} }
private Set<Integer> collectAssetReferenceTokenIndexes(final ReadOnlyList<PbsToken> tokens) {
final Set<Integer> indexes = new HashSet<>();
for (int index = 0; index < tokens.size(); index += 1) {
final PbsToken token = tokens.get(index);
if (token.kind() != PbsTokenKind.IDENTIFIER || !"assets".equals(token.lexeme())) {
continue;
}
final Integer firstDotIndex = nextSignificantIndex(tokens, index);
if (firstDotIndex == null || tokens.get(firstDotIndex).kind() != PbsTokenKind.DOT) {
continue;
}
indexes.add(index);
Integer cursor = firstDotIndex;
while (cursor != null && tokens.get(cursor).kind() == PbsTokenKind.DOT) {
final Integer memberIndex = nextSignificantIndex(tokens, cursor);
if (memberIndex == null || tokens.get(memberIndex).kind() != PbsTokenKind.IDENTIFIER) {
break;
}
indexes.add(memberIndex);
cursor = nextSignificantIndex(tokens, memberIndex);
}
}
return Set.copyOf(indexes);
}
private PbsSemanticKind declarationKind(final PbsTokenKind kind) { private PbsSemanticKind declarationKind(final PbsTokenKind kind) {
return switch (kind) { return DECLARATION_KINDS.get(kind);
case STRUCT -> PbsSemanticKind.STRUCT; }
case CONTRACT -> PbsSemanticKind.CONTRACT;
case HOST -> PbsSemanticKind.HOST; private Map<String, PbsSemanticKind> collectStdlibImportedKinds(final ReadOnlyList<PbsToken> tokens) {
case SERVICE -> PbsSemanticKind.SERVICE; final DiagnosticSink diagnostics = DiagnosticSink.empty();
case ENUM, ERROR -> PbsSemanticKind.ENUM; final PbsAst.File file = PbsParser.parse(tokens, FileId.none(), diagnostics);
case CALLBACK -> PbsSemanticKind.CALLBACK; final Map<String, PbsSemanticKind> importedKindsByLocalName = new HashMap<>();
case GLOBAL -> PbsSemanticKind.GLOBAL; for (final PbsAst.ImportDecl importDecl : file.imports()) {
case CONST -> PbsSemanticKind.CONST; if (importDecl.items().isEmpty()) {
case CTOR -> PbsSemanticKind.CONSTRUCTOR; continue;
case BUILTIN -> PbsSemanticKind.BUILTIN_TYPE; }
default -> null; final Map<String, PbsSemanticKind> exportedKinds = resolveStdlibExportKinds(importDecl.moduleRef());
if (exportedKinds.isEmpty()) {
continue;
}
for (final Map.Entry<String, PbsSemanticKind> entry : exportedKinds.entrySet()) {
if (entry.getValue() == PbsSemanticKind.BUILTIN_TYPE) {
importedKindsByLocalName.put(entry.getKey(), entry.getValue());
}
}
for (final PbsAst.ImportItem item : importDecl.items()) {
final PbsSemanticKind semanticKind = exportedKinds.get(item.name());
if (semanticKind == null) {
continue;
}
importedKindsByLocalName.put(item.alias() == null ? item.name() : item.alias(), semanticKind);
}
}
return importedKindsByLocalName;
}
private Map<String, PbsSemanticKind> resolveStdlibExportKinds(final PbsAst.ModuleRef moduleRef) {
final var stdlibEnvironment = STDLIB_RESOLVER.resolve(DEFAULT_STDLIB_VERSION);
return stdlibEnvironment.resolveModule(moduleRef.project(), moduleRef.pathSegments())
.map(this::parseStdlibVisibleKinds)
.orElseGet(Map::of);
}
private Map<String, PbsSemanticKind> parseStdlibVisibleKinds(final StdlibModuleSource moduleSource) {
final Map<String, PbsSemanticKind> visibleKinds = new HashMap<>(parseBarrelExportKinds(moduleSource.barrelSource()));
for (final StdlibModuleSource.SourceFile sourceFile : moduleSource.sourceFiles()) {
visibleKinds.putAll(parseBuiltinTypeKinds(sourceFile.source()));
}
return visibleKinds;
}
private Map<String, PbsSemanticKind> parseBarrelExportKinds(final String barrelSource) {
final ReadOnlyList<PbsToken> barrelTokens = PbsLexer.lex(barrelSource, FileId.none(), DiagnosticSink.empty());
final PbsAst.BarrelFile barrelFile = PbsBarrelParser.parse(barrelTokens, FileId.none(), DiagnosticSink.empty());
final Map<String, PbsSemanticKind> exportedKinds = new HashMap<>();
for (final PbsAst.BarrelItem item : barrelFile.items()) {
final PbsSemanticKind semanticKind = semanticKindForBarrelItem(item);
if (semanticKind == null) {
continue;
}
if (item instanceof PbsAst.BarrelStructItem structItem && structItem.visibility() == PbsAst.Visibility.PUB) {
exportedKinds.put(structItem.name(), semanticKind);
} else if (item instanceof PbsAst.BarrelContractItem contractItem && contractItem.visibility() == PbsAst.Visibility.PUB) {
exportedKinds.put(contractItem.name(), semanticKind);
} else if (item instanceof PbsAst.BarrelHostItem hostItem && hostItem.visibility() == PbsAst.Visibility.PUB) {
exportedKinds.put(hostItem.name(), semanticKind);
} else if (item instanceof PbsAst.BarrelErrorItem errorItem && errorItem.visibility() == PbsAst.Visibility.PUB) {
exportedKinds.put(errorItem.name(), semanticKind);
} else if (item instanceof PbsAst.BarrelEnumItem enumItem && enumItem.visibility() == PbsAst.Visibility.PUB) {
exportedKinds.put(enumItem.name(), semanticKind);
} else if (item instanceof PbsAst.BarrelServiceItem serviceItem && serviceItem.visibility() == PbsAst.Visibility.PUB) {
exportedKinds.put(serviceItem.name(), semanticKind);
} else if (item instanceof PbsAst.BarrelGlobalItem globalItem && globalItem.visibility() == PbsAst.Visibility.PUB) {
exportedKinds.put(globalItem.name(), semanticKind);
} else if (item instanceof PbsAst.BarrelConstItem constItem && constItem.visibility() == PbsAst.Visibility.PUB) {
exportedKinds.put(constItem.name(), semanticKind);
} else if (item instanceof PbsAst.BarrelCallbackItem callbackItem && callbackItem.visibility() == PbsAst.Visibility.PUB) {
exportedKinds.put(callbackItem.name(), semanticKind);
}
}
return exportedKinds;
}
private Map<String, PbsSemanticKind> parseBuiltinTypeKinds(final String source) {
final ReadOnlyList<PbsToken> sourceTokens = PbsLexer.lex(source, FileId.none(), DiagnosticSink.empty());
final PbsAst.File file = PbsParser.parse(
sourceTokens,
FileId.none(),
DiagnosticSink.empty(),
PbsParser.ParseMode.INTERFACE_MODULE);
final Map<String, PbsSemanticKind> builtinKinds = new HashMap<>();
for (final PbsAst.TopDecl topDecl : file.topDecls()) {
if (topDecl instanceof PbsAst.BuiltinTypeDecl builtinTypeDecl) {
builtinKinds.put(builtinTypeDecl.name(), PbsSemanticKind.BUILTIN_TYPE);
}
}
return builtinKinds;
}
private PbsSemanticKind semanticKindForBarrelItem(final PbsAst.BarrelItem item) {
return switch (item) {
case PbsAst.BarrelStructItem ignored -> PbsSemanticKind.STRUCT;
case PbsAst.BarrelContractItem ignored -> PbsSemanticKind.CONTRACT;
case PbsAst.BarrelHostItem ignored -> PbsSemanticKind.HOST;
case PbsAst.BarrelErrorItem ignored -> PbsSemanticKind.ENUM;
case PbsAst.BarrelEnumItem ignored -> PbsSemanticKind.ENUM;
case PbsAst.BarrelServiceItem ignored -> PbsSemanticKind.SERVICE;
case PbsAst.BarrelGlobalItem ignored -> PbsSemanticKind.GLOBAL;
case PbsAst.BarrelConstItem ignored -> PbsSemanticKind.CONST;
case PbsAst.BarrelCallbackItem ignored -> PbsSemanticKind.CALLBACK;
case PbsAst.BarrelFunctionItem ignored -> null;
}; };
} }
private boolean isTypeReferenceContext( private static Map<PbsTokenKind, PbsSemanticKind> declarationKinds() {
final PbsTokenKind previousKind, final Map<PbsTokenKind, PbsSemanticKind> kinds = new EnumMap<>(PbsTokenKind.class);
final String lexeme) { kinds.put(PbsTokenKind.STRUCT, PbsSemanticKind.STRUCT);
kinds.put(PbsTokenKind.CONTRACT, PbsSemanticKind.CONTRACT);
kinds.put(PbsTokenKind.HOST, PbsSemanticKind.HOST);
kinds.put(PbsTokenKind.SERVICE, PbsSemanticKind.SERVICE);
kinds.put(PbsTokenKind.ENUM, PbsSemanticKind.ENUM);
kinds.put(PbsTokenKind.ERROR, PbsSemanticKind.ENUM);
kinds.put(PbsTokenKind.CALLBACK, PbsSemanticKind.CALLBACK);
kinds.put(PbsTokenKind.GLOBAL, PbsSemanticKind.GLOBAL);
kinds.put(PbsTokenKind.CONST, PbsSemanticKind.CONST);
kinds.put(PbsTokenKind.CTOR, PbsSemanticKind.CONSTRUCTOR);
kinds.put(PbsTokenKind.BUILTIN, PbsSemanticKind.BUILTIN_TYPE);
return Map.copyOf(kinds);
}
private boolean isTypeReferenceContext(final PbsTokenKind previousKind) {
if (previousKind == null) { if (previousKind == null) {
return false; return false;
} }
@ -162,7 +313,7 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv
&& previousKind != PbsTokenKind.IMPLEMENTS) { && previousKind != PbsTokenKind.IMPLEMENTS) {
return false; return false;
} }
return BUILTIN_TYPE_NAMES.contains(lexeme); return true;
} }
private PbsTokenKind previousSignificantKind( private PbsTokenKind previousSignificantKind(
@ -181,12 +332,19 @@ public final class PBSSemanticTokenProvider implements FrontendSemanticTokenProv
private PbsTokenKind nextSignificantKind( private PbsTokenKind nextSignificantKind(
final ReadOnlyList<PbsToken> tokens, final ReadOnlyList<PbsToken> tokens,
final int index) { final int index) {
final Integer cursor = nextSignificantIndex(tokens, index);
return cursor == null ? null : tokens.get(cursor).kind();
}
private Integer nextSignificantIndex(
final ReadOnlyList<PbsToken> tokens,
final int index) {
for (int cursor = index + 1; cursor < tokens.size(); cursor += 1) { for (int cursor = index + 1; cursor < tokens.size(); cursor += 1) {
final PbsTokenKind kind = tokens.get(cursor).kind(); final PbsTokenKind kind = tokens.get(cursor).kind();
if (kind == PbsTokenKind.COMMENT || kind == PbsTokenKind.EOF) { if (kind == PbsTokenKind.COMMENT || kind == PbsTokenKind.EOF) {
continue; continue;
} }
return kind; return cursor;
} }
return null; return null;
} }

View File

@ -22,6 +22,7 @@ public enum PbsSemanticKind {
HOST("pbs-host"), HOST("pbs-host"),
BUILTIN_TYPE("pbs-builtin-type"), BUILTIN_TYPE("pbs-builtin-type"),
SERVICE("pbs-service"), SERVICE("pbs-service"),
ASSET("pbs-asset"),
ERROR("pbs-error"), ERROR("pbs-error"),
ENUM("pbs-enum"), ENUM("pbs-enum"),
CALLBACK("pbs-callback"), CALLBACK("pbs-callback"),

View File

@ -23,9 +23,19 @@ final class PbsSemanticPresentationContractTest {
assertEquals(1, presentation.themes().size()); assertEquals(1, presentation.themes().size());
assertEquals("PBS Default", presentation.defaultTheme().displayName()); assertEquals("PBS Default", presentation.defaultTheme().displayName());
assertEquals("#d9e2ec", presentation.defaultTheme().editorPalette().baseForeground()); assertEquals("#d9e2ec", presentation.defaultTheme().editorPalette().baseForeground());
assertEquals("#d2a8ff", presentation.defaultTheme().requireTokenStyle("pbs-keyword").foreground()); assertEquals("#7fb8ff", presentation.defaultTheme().requireTokenStyle("pbs-keyword").foreground());
assertEquals("#d8b86a", presentation.defaultTheme().requireTokenStyle("pbs-string").foreground());
assertEquals("#ff8cc6", presentation.defaultTheme().requireTokenStyle("pbs-number").foreground());
assertEquals("#7fb8ff", presentation.defaultTheme().requireTokenStyle("pbs-literal").foreground());
assertEquals("#7ee787", presentation.defaultTheme().requireTokenStyle("pbs-function").foreground());
assertEquals("#7ee787", presentation.defaultTheme().requireTokenStyle("pbs-method").foreground());
assertEquals("#7ee787", presentation.defaultTheme().requireTokenStyle("pbs-constructor").foreground());
assertEquals("#56d4dd", presentation.defaultTheme().requireTokenStyle("pbs-struct").foreground());
assertTrue(presentation.defaultTheme().requireTokenStyle("pbs-struct").italic());
assertEquals("#56d4dd", presentation.defaultTheme().requireTokenStyle("pbs-builtin-type").foreground());
assertFalse(presentation.defaultTheme().requireTokenStyle("pbs-builtin-type").italic());
assertEquals("#ff8e7a", presentation.defaultTheme().requireTokenStyle("pbs-service").foreground()); assertEquals("#ff8e7a", presentation.defaultTheme().requireTokenStyle("pbs-service").foreground());
assertTrue(presentation.defaultTheme().requireTokenStyle("pbs-builtin-type").italic()); assertEquals("#c297ff", presentation.defaultTheme().requireTokenStyle("pbs-asset").foreground());
assertTrue(presentation.defaultTheme().requireTokenStyle("pbs-comment").italic()); assertTrue(presentation.defaultTheme().requireTokenStyle("pbs-comment").italic());
assertEquals(PBSFrontendHostProjections.VSCODE_HOST_ID, presentation.requireHostProjection("vscode").hostId()); assertEquals(PBSFrontendHostProjections.VSCODE_HOST_ID, presentation.requireHostProjection("vscode").hostId());
} }
@ -50,6 +60,7 @@ final class PbsSemanticPresentationContractTest {
vscodeProjection.tokenProjections().stream().map(tokenProjection -> tokenProjection.semanticKey()).toList()); vscodeProjection.tokenProjections().stream().map(tokenProjection -> tokenProjection.semanticKey()).toList());
assertEquals("keyword", vscodeProjection.requireProjection(PbsSemanticKind.KEYWORD.semanticKey()).hostTokenType()); assertEquals("keyword", vscodeProjection.requireProjection(PbsSemanticKind.KEYWORD.semanticKey()).hostTokenType());
assertEquals("type", vscodeProjection.requireProjection(PbsSemanticKind.STRUCT.semanticKey()).fallbackTokenType()); assertEquals("type", vscodeProjection.requireProjection(PbsSemanticKind.STRUCT.semanticKey()).fallbackTokenType());
assertEquals("variable", vscodeProjection.requireProjection(PbsSemanticKind.ASSET.semanticKey()).hostTokenType());
assertEquals( assertEquals(
java.util.List.of("readonly"), java.util.List.of("readonly"),
vscodeProjection.requireProjection(PbsSemanticKind.GLOBAL.semanticKey()).hostTokenModifiers()); vscodeProjection.requireProjection(PbsSemanticKind.GLOBAL.semanticKey()).hostTokenModifiers());
@ -73,7 +84,7 @@ final class PbsSemanticPresentationContractTest {
} }
"""); """);
assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.STRUCT.semanticKey()))); assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.BUILTIN_TYPE.semanticKey())));
assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.FUNCTION.semanticKey()))); assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.FUNCTION.semanticKey())));
assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.CONST.semanticKey()))); assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.CONST.semanticKey())));
assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.BUILTIN_TYPE.semanticKey()))); assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.BUILTIN_TYPE.semanticKey())));
@ -83,4 +94,53 @@ final class PbsSemanticPresentationContractTest {
assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.HOST.semanticKey()))); assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.HOST.semanticKey())));
assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.ENUM.semanticKey()))); assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.ENUM.semanticKey())));
} }
@Test
void shouldClassifyStdlibImportsUsingTheirPublishedBarrelKinds() {
final List<FrontendSemanticToken> semanticTokens = PBSDefinitions.PBS.getSemanticTokenProvider().tokenize("""
import { Log } from @sdk:log;
import { Composer } from @sdk:composer;
import { Color as Paint } from @core:color;
fn main() -> void {
Log.info("hello");
Composer.emit_sprite(0, 0, 0, 0, 0, 0, false, false, 0);
let paint: Paint;
}
""");
assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.SERVICE.semanticKey())));
assertTrue(semanticTokens.stream().anyMatch(token -> token.semanticKey().equals(PbsSemanticKind.BUILTIN_TYPE.semanticKey())));
}
@Test
void shouldClassifyAssetRootedAliasesUsingDedicatedSemanticKind() {
final List<FrontendSemanticToken> semanticTokens = PBSDefinitions.PBS.getSemanticTokenProvider().tokenize("""
import { Assets } from @sdk:asset;
fn main() -> void {
Assets.load(assets.ui.atlas2, 3);
}
""");
final long assetTokenCount = semanticTokens.stream()
.filter(token -> token.semanticKey().equals(PbsSemanticKind.ASSET.semanticKey()))
.count();
assertEquals(3, assetTokenCount);
}
@Test
void shouldClassifyBuiltinTypesExposedByImportedStdlibModules() {
final List<FrontendSemanticToken> semanticTokens = PBSDefinitions.PBS.getSemanticTokenProvider().tokenize("""
import { Input } from @sdk:input;
fn main() -> void {
let touch : InputTouch = Input.touch();
let pad : InputPad = Input.pad();
}
""");
assertTrue(semanticTokens.stream().filter(token -> token.semanticKey().equals(PbsSemanticKind.BUILTIN_TYPE.semanticKey())).count() >= 2);
}
} }

View File

@ -80,6 +80,24 @@ class CompilerLanguageServiceBridgeTest {
assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-enum"))); assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-enum")));
} }
@Test
void semanticTokensClassifyBuiltinTypesExposedByImportedStdlibModules() {
final CompilerLanguageServiceBridge bridge = new CompilerLanguageServiceBridge();
final var semanticTokens = bridge.semanticTokens(
new LspProjectContext("main", "pbs", Path.of(".")),
Path.of("demo.pbs").toUri().toString(),
"""
import { Input } from @sdk:input;
fn main() -> void {
let touch : InputTouch = Input.touch();
}
""");
assertTrue(semanticTokens.tokens().stream().anyMatch(token -> token.semanticKey().equals("pbs-builtin-type")));
}
@Test @Test
void describeServerPublishesFrontendVisualThemes() { void describeServerPublishesFrontendVisualThemes() {
final CompilerLanguageServiceBridge bridge = new CompilerLanguageServiceBridge(); final CompilerLanguageServiceBridge bridge = new CompilerLanguageServiceBridge();
@ -98,7 +116,7 @@ class CompilerLanguageServiceBridgeTest {
assertEquals("#d9e2ec", description.visualThemes().getFirst().editorPalette().baseForeground()); assertEquals("#d9e2ec", description.visualThemes().getFirst().editorPalette().baseForeground());
assertTrue(description.visualThemes().getFirst().tokenStyles().stream() assertTrue(description.visualThemes().getFirst().tokenStyles().stream()
.anyMatch(tokenStyle -> tokenStyle.semanticKey().equals("pbs-keyword") .anyMatch(tokenStyle -> tokenStyle.semanticKey().equals("pbs-keyword")
&& tokenStyle.foreground().equals("#d2a8ff"))); && tokenStyle.foreground().equals("#7fb8ff")));
} }
private Path findRepoRoot(final Path start) { private Path findRepoRoot(final Path start) {

View File

@ -6,35 +6,35 @@
"foreground": "#8b949e", "foreground": "#8b949e",
"italic": true "italic": true
}, },
"pbs-string:pbs": "#7ee787", "pbs-string:pbs": "#d8b86a",
"pbs-number:pbs": "#ffa657", "pbs-number:pbs": "#ff8cc6",
"pbs-literal:pbs": "#79c0ff", "pbs-literal:pbs": "#7fb8ff",
"pbs-lifecycle:pbs": { "pbs-lifecycle:pbs": {
"foreground": "#ff7b72", "foreground": "#ff7b72",
"bold": true "bold": true
}, },
"pbs-keyword:pbs": "#d2a8ff", "pbs-keyword:pbs": "#7fb8ff",
"pbs-operator:pbs": "#c9d1d9", "pbs-operator:pbs": "#c9d1d9",
"pbs-punctuation:pbs": "#8b949e", "pbs-punctuation:pbs": "#8b949e",
"pbs-function:pbs": { "pbs-function:pbs": {
"foreground": "#ffa657", "foreground": "#7ee787",
"bold": true "bold": true
}, },
"pbs-method:pbs": "#ffd580", "pbs-method:pbs": "#7ee787",
"pbs-constructor:pbs": { "pbs-constructor:pbs": {
"foreground": "#e3b341", "foreground": "#7ee787",
"bold": true "bold": true
}, },
"pbs-struct:pbs": "#56d4dd", "pbs-struct:pbs": {
"foreground": "#56d4dd",
"italic": true
},
"pbs-contract:pbs": { "pbs-contract:pbs": {
"foreground": "#79c0ff", "foreground": "#79c0ff",
"underline": true "underline": true
}, },
"pbs-host:pbs": "#c297ff", "pbs-host:pbs": "#c297ff",
"pbs-builtin-type:pbs": { "pbs-builtin-type:pbs": "#56d4dd",
"foreground": "#7ee787",
"italic": true
},
"pbs-service:pbs": { "pbs-service:pbs": {
"foreground": "#ff8e7a", "foreground": "#ff8e7a",
"bold": true "bold": true
@ -62,10 +62,10 @@
"foreground": "#8b949e", "foreground": "#8b949e",
"italic": true "italic": true
}, },
"string:pbs": "#7ee787", "string:pbs": "#d8b86a",
"number:pbs": "#ffa657", "number:pbs": "#ff8cc6",
"enumMember:pbs": "#79c0ff", "enumMember:pbs": "#7fb8ff",
"variable:pbs": "#79c0ff", "variable:pbs": "#7fb8ff",
"function.async:pbs": { "function.async:pbs": {
"foreground": "#ff7b72", "foreground": "#ff7b72",
"bold": true "bold": true
@ -74,41 +74,43 @@
"foreground": "#ff7b72", "foreground": "#ff7b72",
"bold": true "bold": true
}, },
"keyword:pbs": "#d2a8ff", "keyword:pbs": "#7fb8ff",
"operator:pbs": "#c9d1d9", "operator:pbs": "#c9d1d9",
"function:pbs": { "function:pbs": {
"foreground": "#ffa657", "foreground": "#7ee787",
"bold": true "bold": true
}, },
"method:pbs": "#ffd580", "method:pbs": "#7ee787",
"class.declaration:pbs": { "class.declaration:pbs": {
"foreground": "#e3b341", "foreground": "#7ee787",
"bold": true "bold": true
}, },
"type.declaration:pbs": { "type.declaration:pbs": {
"foreground": "#e3b341", "foreground": "#7ee787",
"bold": true "bold": true
}, },
"struct:pbs": "#56d4dd", "struct:pbs": {
"type:pbs": "#56d4dd", "foreground": "#56d4dd",
"italic": true
},
"type:pbs": {
"foreground": "#56d4dd",
"italic": true
},
"interface:pbs": { "interface:pbs": {
"foreground": "#79c0ff", "foreground": "#79c0ff",
"underline": true "underline": true
}, },
"class.defaultLibrary:pbs": "#c297ff", "class.defaultLibrary:pbs": "#c297ff",
"type.defaultLibrary:pbs": "#c297ff", "type.defaultLibrary:pbs": "#c297ff",
"variable.defaultLibrary:pbs": { "variable.defaultLibrary:pbs": "#56d4dd",
"foreground": "#7ee787",
"italic": true
},
"enum:pbs": { "enum:pbs": {
"foreground": "#ff7b72", "foreground": "#ff7b72",
"underline": true "underline": true
}, },
"variable.readonly:pbs": { "variable.readonly:pbs": "#c297ff",
"foreground": "#f778ba", "pbs-asset:pbs": "#c297ff",
"italic": true "string.readonly:pbs": "#c297ff"
}
} }
}, },
"workbench.colorCustomizations": { "workbench.colorCustomizations": {

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,8 @@ declare global camera_mult: int = 1;
declare const MAX_FRAMES: int = 4; declare const MAX_FRAMES: int = 4;
declare const CAMERA_SPEED: int = 1; declare const CAMERA_SPEED: int = 1;
declare struct Bla (a: int) {}
[Init] [Init]
fn init() -> void fn init() -> void
{ {
@ -25,6 +27,7 @@ fn init() -> void
camera_x = 0; camera_x = 0;
camera_mult = 1; camera_mult = 1;
Composer.bind_scene(0); Composer.bind_scene(0);
let bla: Bla = new Bla(1);
} }
[Frame] [Frame]
@ -55,9 +58,8 @@ fn frame() -> void
} }
} }
let touch : InputTouch = Input.touch(); let touch : InputTouch = Input.touch();
let pad : InputPad = Input.pad();
if (touch.button().released()) if (touch.button().released())
{ {
@ -93,15 +95,15 @@ fn frame() -> void
let b : int = 15; let b : int = 15;
let total : int = a + b; let total : int = a + b;
if (Input.pad().a().pressed()) if (pad.a().pressed())
{ {
total += 25; total += 25;
} }
else if (Input.pad().b().pressed()) else if (pad.b().pressed())
{ {
total += 5; total += 5;
} }
else if (Input.pad().x().pressed()) else if (pad.x().pressed())
{ {
total -= 10; total -= 10;
} }