Skip to main content

module demo::lang::pico::LanguageServer

rascal-0.34.0
rascal-lsp-2.20.0

Usage

import demo::lang::pico::LanguageServer;

Source code

http://github.com/usethesource/rascal-language-servers/blob/main/rascal-lsp/src/main/rascal/demo/lang/pico/LanguageServer.rsc

Dependencies

import util::LanguageServer;
import util::IDEServices;
import ParseTree;
import util::Reflective;
import lang::pico::\syntax::Main;
import IO;

function picoLanguageContributor

set[LanguageService] picoLanguageContributor() = {
parser(parser(#start[Program])),
outliner(picoOutliner),
lenses(picoLenses),
executor(picoCommands),
inlayHinter(picoHinter),
definer(lookupDef)
};

function picoLanguageContributorSlowSummary

set[LanguageService] picoLanguageContributorSlowSummary() = {
parser(parser(#start[Program])),
analyzer(picoAnalyzer, providesImplementations = false),
builder(picoBuilder)
};

function picoOutliner

list[DocumentSymbol] picoOutliner(start[Program] input)
= [symbol("<input.src>", DocumentSymbolKind::\file(), input.src, children=[
*[symbol("<var.id>", \variable(), var.src) | /IdType var := input]
])];

function picoAnalyzer

Summary picoAnalyzer(loc l, start[Program] input) = picoSummarizer(l, input, analyze());

function picoBuilder

Summary picoBuilder(loc l, start[Program] input) = picoSummarizer(l, input, build());

data PicoSummarizerMode

data PicoSummarizerMode  
= analyze()
| build()
;

function picoSummarizer

Summary picoSummarizer(loc l, start[Program] input, PicoSummarizerMode mode) {
Summary s = summary(l);

rel[str, loc] defs = {<"<var.id>", var.src> | /IdType var := input};
rel[loc, str] uses = {<id.src, "<id>"> | /Id id := input};
rel[loc, str] docs = {<var.src, "*variable* <var>"> | /IdType var := input};

// Provide errors (cheap to compute) both in analyze mode and in build mode
s.messages += {<src, error("<id> is not defined", src)> | <src, id> <- uses, id notin defs<0>};
s.references += (uses o defs)<1,0>;
s.definitions += uses o defs;
s.documentation += (uses o defs) o docs;

// Provide warnings (expensive to compute) only in build mode
if (build() := mode) {
rel[loc, str] asgn = {<id.src, "<id>"> | /Statement stmt := input, (Statement) `<Id id> := <Expression _>` := stmt};
s.messages += {<src, warning("<id> is not assigned", src)> | <id, src> <- defs, id notin asgn<1>};
}

return s;
}

function lookupDef

set[loc] lookupDef(loc _, start[Program] input, Tree cursor) =
{ d.src | /IdType d := input, cursor := d.id};

data Command

data Command  
= renameAtoB(start[Program] program)
;

function picoLenses

rel[loc,Command] picoLenses(start[Program] input) = {<input@\loc, renameAtoB(input, title="Rename variables a to b.")>};

function picoHinter

list[InlayHint] picoHinter(start[Program] input) {
typeLookup = ( "<name>" : "<tp>" | /(IdType)`<Id name> : <Type tp>` := input);
return [
hint(name.src, " : <typeLookup["<name>"]>", \type(), atEnd = true) | /(Expression)`<Id name>` := input, "<name>" in typeLookup
];
}

function getAtoBEdits

list[DocumentEdit] getAtoBEdits(start[Program] input)
= [changed(input@\loc.top, [replace(id@\loc, "b") | /id:(Id) `a` := input])];

function picoCommands

value picoCommands(renameAtoB(start[Program] input)) {
applyDocumentsEdits(getAtoBEdits(input));
return ("result": true);
}

function main

void main() {
registerLanguage(
language(
pathConfig(),
"Pico",
{"pico", "pico-new"},
"demo::lang::pico::LanguageServer",
"picoLanguageContributor"
)
);
registerLanguage(
language(
pathConfig(),
"Pico",
{"pico", "pico-new"},
"demo::lang::pico::LanguageServer",
"picoLanguageContributorSlowSummary"
)
);
}