完成世界书、骰子、apiconfig页面处理

This commit is contained in:
2026-04-30 01:35:10 +08:00
parent a3e3711b2b
commit ba9b925c32
4602 changed files with 785225 additions and 23 deletions

279
frontend/node_modules/langium/lib/utils/ast-utils.js generated vendored Normal file
View File

@@ -0,0 +1,279 @@
/******************************************************************************
* Copyright 2021 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { isAstNode, isMultiReference, isReference } from '../syntax-tree.js';
import { DONE_RESULT, StreamImpl, TreeStreamImpl } from './stream.js';
import { inRange } from './cst-utils.js';
/**
* Link the `$container` and other related properties of every AST node that is directly contained
* in the given `node`.
*/
export function linkContentToContainer(node, options = {}) {
for (const [name, value] of Object.entries(node)) {
if (!name.startsWith('$')) {
if (Array.isArray(value)) {
value.forEach((item, index) => {
if (isAstNode(item)) {
item.$container = node;
item.$containerProperty = name;
item.$containerIndex = index;
if (options.deep) {
linkContentToContainer(item, options);
}
}
});
}
else if (isAstNode(value)) {
value.$container = node;
value.$containerProperty = name;
if (options.deep) {
linkContentToContainer(value, options);
}
}
}
}
}
/**
* Walk along the hierarchy of containers from the given AST node to the root and return the first
* node that matches the type predicate. If the start node itself matches, it is returned.
* If no container matches, `undefined` is returned.
*/
export function getContainerOfType(node, typePredicate) {
let item = node;
while (item) {
if (typePredicate(item)) {
return item;
}
item = item.$container;
}
return undefined;
}
/**
* Walk along the hierarchy of containers from the given AST node to the root and check for existence
* of a container that matches the given predicate. The start node is included in the checks.
*/
export function hasContainerOfType(node, predicate) {
let item = node;
while (item) {
if (predicate(item)) {
return true;
}
item = item.$container;
}
return false;
}
/**
* Retrieve the document in which the given AST node is contained. A reference to the document is
* usually held by the root node of the AST.
*
* @throws an error if the node is not contained in a document.
*/
export function getDocument(node) {
const rootNode = findRootNode(node);
const result = rootNode.$document;
if (!result) {
throw new Error('AST node has no document.');
}
return result;
}
/**
* Returns the root node of the given AST node by following the `$container` references.
*/
export function findRootNode(node) {
while (node.$container) {
node = node.$container;
}
return node;
}
/**
* Returns all AST nodes that are referenced by the given reference or multi-reference.
*/
export function getReferenceNodes(reference) {
if (isReference(reference)) {
return reference.ref ? [reference.ref] : [];
}
else if (isMultiReference(reference)) {
return reference.items.map(item => item.ref);
}
return [];
}
/**
* Create a stream of all AST nodes that are directly contained in the given node. This includes
* single-valued as well as multi-valued (array) properties.
*/
export function streamContents(node, options) {
if (!node) {
throw new Error('Node must be an AstNode.');
}
const range = options?.range;
return new StreamImpl(() => ({
keys: Object.keys(node),
keyIndex: 0,
arrayIndex: 0
}), state => {
while (state.keyIndex < state.keys.length) {
const property = state.keys[state.keyIndex];
if (!property.startsWith('$')) {
const value = node[property];
if (isAstNode(value)) {
state.keyIndex++;
if (isAstNodeInRange(value, range)) {
return { done: false, value };
}
}
else if (Array.isArray(value)) {
while (state.arrayIndex < value.length) {
const index = state.arrayIndex++;
const element = value[index];
if (isAstNode(element) && isAstNodeInRange(element, range)) {
return { done: false, value: element };
}
}
state.arrayIndex = 0;
}
}
state.keyIndex++;
}
return DONE_RESULT;
});
}
/**
* Create a stream of all AST nodes that are directly and indirectly contained in the given root node.
* This does not include the root node itself.
*/
export function streamAllContents(root, options) {
if (!root) {
throw new Error('Root node must be an AstNode.');
}
return new TreeStreamImpl(root, node => streamContents(node, options));
}
/**
* Create a stream of all AST nodes that are directly and indirectly contained in the given root node,
* including the root node itself.
*/
export function streamAst(root, options) {
if (!root) {
throw new Error('Root node must be an AstNode.');
}
else if (options?.range && !isAstNodeInRange(root, options.range)) {
// Return an empty stream if the root node isn't in range
return new TreeStreamImpl(root, () => []);
}
return new TreeStreamImpl(root, node => streamContents(node, options), { includeRoot: true });
}
function isAstNodeInRange(astNode, range) {
if (!range) {
return true;
}
const nodeRange = astNode.$cstNode?.range;
if (!nodeRange) {
return false;
}
return inRange(nodeRange, range);
}
/**
* Create a stream of all cross-references that are held by the given AST node. This includes
* single-valued as well as multi-valued (array) properties.
*/
export function streamReferences(node) {
return new StreamImpl(() => ({
keys: Object.keys(node),
keyIndex: 0,
arrayIndex: 0
}), state => {
while (state.keyIndex < state.keys.length) {
const property = state.keys[state.keyIndex];
if (!property.startsWith('$')) {
const value = node[property];
if (isReference(value) || isMultiReference(value)) {
state.keyIndex++;
return { done: false, value: { reference: value, container: node, property } };
}
else if (Array.isArray(value)) {
while (state.arrayIndex < value.length) {
const index = state.arrayIndex++;
const element = value[index];
if (isReference(element) || isMultiReference(value)) {
return { done: false, value: { reference: element, container: node, property, index } };
}
}
state.arrayIndex = 0;
}
}
state.keyIndex++;
}
return DONE_RESULT;
});
}
/**
* Assigns all mandatory AST properties to the specified node.
*
* @param reflection Reflection object used to gather mandatory properties for the node.
* @param node Specified node is modified in place and properties are directly assigned.
*/
export function assignMandatoryProperties(reflection, node) {
const typeMetaData = reflection.getTypeMetaData(node.$type);
const genericNode = node;
for (const property of Object.values(typeMetaData.properties)) {
// Only set the value if the property is not already set and if it has a default value
if (property.defaultValue !== undefined && genericNode[property.name] === undefined) {
genericNode[property.name] = copyDefaultValue(property.defaultValue);
}
}
}
function copyDefaultValue(propertyType) {
if (Array.isArray(propertyType)) {
return [...propertyType.map(copyDefaultValue)];
}
else {
return propertyType;
}
}
/**
* Creates a deep copy of the specified AST node.
* The resulting copy will only contain semantically relevant information, such as the `$type` property and AST properties.
*
* @param node The AST node to deeply copy.
* @param buildReference References are not copied, instead this function is called to rebuild them.
* @param trace For the sake of tracking copied nodes and their originals a `trace` map can be provided (optional).
*/
export function copyAstNode(node, buildReference, trace) {
const copy = { $type: node.$type };
if (trace) {
trace.set(node, copy);
trace.set(copy, node);
}
for (const [name, value] of Object.entries(node)) {
if (!name.startsWith('$')) {
if (isAstNode(value)) {
copy[name] = copyAstNode(value, buildReference, trace);
}
else if (isReference(value)) {
copy[name] = buildReference(copy, name, value.$refNode, value.$refText, value);
}
else if (Array.isArray(value)) {
const copiedArray = [];
for (const element of value) {
if (isAstNode(element)) {
copiedArray.push(copyAstNode(element, buildReference, trace));
}
else if (isReference(element)) {
copiedArray.push(buildReference(copy, name, element.$refNode, element.$refText, element));
}
else {
copiedArray.push(element);
}
}
copy[name] = copiedArray;
}
else {
copy[name] = value;
}
}
}
linkContentToContainer(copy, { deep: true });
return copy;
}
//# sourceMappingURL=ast-utils.js.map

74
frontend/node_modules/langium/lib/utils/caching.d.ts generated vendored Normal file
View File

@@ -0,0 +1,74 @@
/******************************************************************************
* Copyright 2023 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import type { Disposable } from './disposable.js';
import type { URI } from './uri-utils.js';
import type { LangiumSharedCoreServices } from '../services.js';
import type { DocumentState } from '../workspace/documents.js';
export declare abstract class DisposableCache implements Disposable {
protected toDispose: Disposable[];
protected isDisposed: boolean;
onDispose(disposable: Disposable): void;
dispose(): void;
protected throwIfDisposed(): void;
abstract clear(): void;
}
export declare class SimpleCache<K, V> extends DisposableCache {
protected readonly cache: Map<K, V>;
has(key: K): boolean;
set(key: K, value: V): void;
get(key: K): V | undefined;
get(key: K, provider: () => V): V;
delete(key: K): boolean;
clear(): void;
}
export declare class ContextCache<Context, Key, Value, ContextKey = Context> extends DisposableCache {
private readonly cache;
private readonly converter;
constructor(converter?: (input: Context) => ContextKey);
has(contextKey: Context, key: Key): boolean;
set(contextKey: Context, key: Key, value: Value): void;
get(contextKey: Context, key: Key): Value | undefined;
get(contextKey: Context, key: Key, provider: () => Value): Value;
delete(contextKey: Context, key: Key): boolean;
clear(): void;
clear(contextKey: Context): void;
protected cacheForContext(contextKey: Context): Map<Key, Value>;
}
/**
* Every key/value pair in this cache is scoped to a document.
* If this document is changed or deleted, all associated key/value pairs are deleted.
*/
export declare class DocumentCache<K, V> extends ContextCache<URI | string, K, V, string> {
/**
* Creates a new document cache.
*
* @param sharedServices Service container instance to hook into document lifecycle events.
* @param state Optional document state on which the cache should evict.
* If not provided, the cache will evict on `DocumentBuilder#onUpdate`.
* *Deleted* documents are considered in both cases.
*
* Providing a state here will use `DocumentBuilder#onDocumentPhase` instead,
* which triggers on all documents that have been affected by this change, assuming that the
* state is `DocumentState.Linked` or a later state.
*/
constructor(sharedServices: LangiumSharedCoreServices, state?: DocumentState);
}
/**
* Every key/value pair in this cache is scoped to the whole workspace.
* If any document in the workspace is added, changed or deleted, the whole cache is evicted.
*/
export declare class WorkspaceCache<K, V> extends SimpleCache<K, V> {
/**
* Creates a new workspace cache.
*
* @param sharedServices Service container instance to hook into document lifecycle events.
* @param state Optional document state on which the cache should evict.
* If not provided, the cache will evict on `DocumentBuilder#onUpdate`.
* *Deleted* documents are considered in both cases.
*/
constructor(sharedServices: LangiumSharedCoreServices, state?: DocumentState);
}
//# sourceMappingURL=caching.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"caching.js","sourceRoot":"","sources":["../../src/utils/caching.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,8 @@
/******************************************************************************
* Copyright 2024 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
// eslint-disable-next-line no-restricted-imports
export * from 'vscode-jsonrpc/lib/common/cancellation.js';
//# sourceMappingURL=cancellation.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"cancellation.js","sourceRoot":"","sources":["../../src/utils/cancellation.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,iDAAiD;AACjD,cAAc,2CAA2C,CAAC"}

View File

@@ -0,0 +1 @@
{"version":3,"file":"disposable.js","sourceRoot":"","sources":["../../src/utils/disposable.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAgBhF,MAAM,KAAW,UAAU,CAQ1B;AARD,WAAiB,UAAU;IAGvB,SAAgB,MAAM,CAAC,QAAoC;QACvD,OAAO;YACH,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,MAAM,QAAQ,EAAE;SACxC,CAAC;IACN,CAAC;IAJe,iBAAM,SAIrB,CAAA;AACL,CAAC,EARgB,UAAU,KAAV,UAAU,QAQ1B"}

7
frontend/node_modules/langium/lib/utils/event.d.ts generated vendored Normal file
View File

@@ -0,0 +1,7 @@
/******************************************************************************
* Copyright 2024 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
export * from 'vscode-jsonrpc/lib/common/events.js';
//# sourceMappingURL=event.d.ts.map

1
frontend/node_modules/langium/lib/utils/event.js.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/utils/event.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,iDAAiD;AACjD,cAAc,qCAAqC,CAAC"}

View File

@@ -0,0 +1 @@
{"version":3,"file":"grammar-loader.js","sourceRoot":"","sources":["../../src/utils/grammar-loader.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAE9F,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACpD,OAAO,KAAK,GAAG,MAAM,+BAA+B,CAAC;AAGrD,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAErC,MAAM,oBAAoB,GAA4D;IAClF,OAAO,EAAE,GAAG,EAAE,CAAC,SAAmC;IAClD,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;QACrB,eAAe,EAAE,KAAK;QACtB,cAAc,EAAE,CAAC,UAAU,CAAC;QAC5B,UAAU,EAAE,SAAS;KACxB,CAAC;CACL,CAAC;AAEF,MAAM,0BAA0B,GAAwE;IACpG,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,2BAA2B,EAAE;CAC7D,CAAC;AAEF,SAAS,4BAA4B;IACjC,MAAM,MAAM,GAAG,MAAM,CACjB,6BAA6B,CAAC,eAAe,CAAC,EAC9C,0BAA0B,CAC7B,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,CAClB,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC,EACnC,oBAAoB,CACvB,CAAC;IACF,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzC,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC5C,MAAM,QAAQ,GAAG,4BAA4B,EAAE,CAAC;IAChD,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,cAAc,CAAC,WAAW,CAAC,IAAI,CAAyB,CAAC;IAC7F,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,sBAAsB,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,OAAO,CAAC,IAAI,IAAI,SAAS,UAAU,CAAC,CAAC,CAAC;IAC/H,OAAO,OAAO,CAAC;AACnB,CAAC"}

View File

@@ -0,0 +1,127 @@
/******************************************************************************
* Copyright 2021-2022 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import * as ast from '../languages/generated/ast.js';
import type { AstNode, CstNode } from '../syntax-tree.js';
/**
* Returns the entry rule of the given grammar, if any. If the grammar file does not contain an entry rule,
* the result is `undefined`.
*/
export declare function getEntryRule(grammar: ast.Grammar): ast.ParserRule | undefined;
/**
* Returns all hidden terminal rules of the given grammar, if any.
*/
export declare function getHiddenRules(grammar: ast.Grammar): ast.AbstractRule[];
/**
* Returns all rules that can be reached from the topmost rules of the specified grammar (entry and hidden terminal rules).
*
* @param grammar The grammar that contains all rules
* @param allTerminals Whether or not to include terminals that are referenced only by other terminals
* @returns A list of referenced parser and terminal rules. If the grammar contains no entry rule,
* this function returns all rules of the specified grammar.
*/
export declare function getAllReachableRules(grammar: ast.Grammar, allTerminals: boolean): Set<ast.AbstractRule>;
/**
* Returns all parser rules which provide types which are used in the grammar as type in cross-references.
* @param grammar the grammar to investigate
* @returns the set of parser rules whose contributed types are used as type in cross-references
*/
export declare function getAllRulesUsedForCrossReferences(grammar: ast.Grammar): Set<ast.ParserRule>;
/**
* Determines the grammar expression used to parse a cross-reference (usually a reference to a terminal rule).
* A cross-reference can declare this expression explicitly in the form `[Type : Terminal]`, but if `Terminal`
* is omitted, this function attempts to infer it from the name of the referenced `Type` (using `findNameAssignment`).
*
* Returns the grammar expression used to parse the given cross-reference, or `undefined` if it is not declared
* and cannot be inferred.
*/
export declare function getCrossReferenceTerminal(crossRef: ast.CrossReference): ast.AbstractElement | undefined;
/**
* Determines whether the given terminal rule represents a comment. This is true if the rule is marked
* as `hidden` and it does not match white space. This means every hidden token (i.e. excluded from the AST)
* that contains visible characters is considered a comment.
*/
export declare function isCommentTerminal(terminalRule: ast.TerminalRule): boolean;
/**
* Find all CST nodes within the given node that contribute to the specified property.
*
* @param node A CST node in which to look for property assignments. If this is undefined, the result is an empty array.
* @param property A property name of the constructed AST node. If this is undefined, the result is an empty array.
*/
export declare function findNodesForProperty(node: CstNode | undefined, property: string | undefined): CstNode[];
/**
* Find a single CST node within the given node that contributes to the specified property.
*
* @param node A CST node in which to look for property assignments. If this is undefined, the result is `undefined`.
* @param property A property name of the constructed AST node. If this is undefined, the result is `undefined`.
* @param index If no index is specified or the index is less than zero, the first found node is returned. If the
* specified index exceeds the number of assignments to the property, the last found node is returned. Otherwise,
* the node with the specified index is returned.
*/
export declare function findNodeForProperty(node: CstNode | undefined, property: string | undefined, index?: number): CstNode | undefined;
/**
* Find all CST nodes within the given node that correspond to the specified keyword.
*
* @param node A CST node in which to look for keywords. If this is undefined, the result is an empty array.
* @param keyword A keyword as specified in the grammar.
*/
export declare function findNodesForKeyword(node: CstNode | undefined, keyword: string): CstNode[];
/**
* Find a single CST node within the given node that corresponds to the specified keyword.
*
* @param node A CST node in which to look for keywords. If this is undefined, the result is `undefined`.
* @param keyword A keyword as specified in the grammar.
* @param index If no index is specified or the index is less than zero, the first found node is returned. If the
* specified index exceeds the number of keyword occurrences, the last found node is returned. Otherwise,
* the node with the specified index is returned.
*/
export declare function findNodeForKeyword(node: CstNode | undefined, keyword: string, index?: number): CstNode | undefined;
export declare function findNodesForKeywordInternal(node: CstNode, keyword: string, element: AstNode | undefined): CstNode[];
/**
* If the given CST node was parsed in the context of a property assignment, the respective `Assignment` grammar
* node is returned. If no assignment is found, the result is `undefined`.
*
* @param cstNode A CST node for which to find a property assignment.
*/
export declare function findAssignment(cstNode: CstNode): ast.Assignment | undefined;
/**
* Find an assignment to the `name` property for the given grammar type. This requires the `type` to be inferred
* from a parser rule, and that rule must contain an assignment to the `name` property. In all other cases,
* this function returns `undefined`.
*/
export declare function findNameAssignment(type: ast.AbstractType): ast.Assignment | undefined;
export declare function getActionAtElement(element: ast.AbstractElement): ast.Action | undefined;
export type Cardinality = '?' | '*' | '+' | undefined;
export type Operator = '=' | '+=' | '?=' | undefined;
export declare function isOptionalCardinality(cardinality?: Cardinality, element?: ast.AbstractElement): boolean;
export declare function isArrayCardinality(cardinality?: Cardinality): boolean;
export declare function isArrayOperator(operator?: Operator): boolean;
/**
* Determines whether the given parser rule is a _data type rule_, meaning that it has a
* primitive return type like `number`, `boolean`, etc.
*/
export declare function isDataTypeRule(rule: ast.ParserRule): boolean;
export declare function isDataType(type: ast.Type): boolean;
export declare function getExplicitRuleType(rule: ast.AbstractRule): string | undefined;
export declare function getTypeName(type: ast.AbstractType | ast.Action): string;
export declare function getActionType(action: ast.Action): string | undefined;
/**
* This function is used at development time (for code generation and the internal type system) to get the type of the AST node produced by the given rule.
* For data type rules, the name of the rule is returned,
* e.g. "INT_value returns number: MY_INT;" returns "INT_value".
* @param rule the given rule
* @returns the name of the AST node type of the rule
*/
export declare function getRuleTypeName(rule: ast.AbstractRule): string;
/**
* This function is used at runtime to get the actual type of the values produced by the given rule at runtime.
* For data type rules, the name of the declared return type of the rule is returned (if any),
* e.g. "INT_value returns number: MY_INT;" returns "number".
* @param rule the given rule
* @returns the name of the type of the produced values of the rule at runtime
*/
export declare function getRuleType(rule: ast.AbstractRule): string;
export declare function terminalRegex(terminalRule: ast.TerminalRule): RegExp;
//# sourceMappingURL=grammar-utils.d.ts.map

View File

@@ -0,0 +1,606 @@
/******************************************************************************
* Copyright 2021-2022 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { assertUnreachable } from '../utils/errors.js';
import * as ast from '../languages/generated/ast.js';
import { isCompositeCstNode } from '../syntax-tree.js';
import { getContainerOfType, streamAllContents } from './ast-utils.js';
import { streamCst } from './cst-utils.js';
import { escapeRegExp, isWhitespace } from './regexp-utils.js';
/**
* Returns the entry rule of the given grammar, if any. If the grammar file does not contain an entry rule,
* the result is `undefined`.
*/
export function getEntryRule(grammar) {
return grammar.rules.find(e => ast.isParserRule(e) && e.entry);
}
/**
* Returns all hidden terminal rules of the given grammar, if any.
*/
export function getHiddenRules(grammar) {
return grammar.rules.filter(e => ast.isTerminalRule(e) && e.hidden);
}
/**
* Returns all rules that can be reached from the topmost rules of the specified grammar (entry and hidden terminal rules).
*
* @param grammar The grammar that contains all rules
* @param allTerminals Whether or not to include terminals that are referenced only by other terminals
* @returns A list of referenced parser and terminal rules. If the grammar contains no entry rule,
* this function returns all rules of the specified grammar.
*/
export function getAllReachableRules(grammar, allTerminals) {
const ruleNames = new Set();
const entryRule = getEntryRule(grammar);
if (!entryRule) {
return new Set(grammar.rules);
}
const topMostRules = [entryRule].concat(getHiddenRules(grammar));
for (const rule of topMostRules) {
ruleDfs(rule, ruleNames, allTerminals);
}
const rules = new Set();
for (const rule of grammar.rules) {
if (ruleNames.has(rule.name) || (ast.isTerminalRule(rule) && rule.hidden)) {
rules.add(rule);
}
}
return rules;
}
function ruleDfs(rule, visitedSet, allTerminals) {
visitedSet.add(rule.name);
streamAllContents(rule).forEach(node => {
if (ast.isRuleCall(node) || (allTerminals && ast.isTerminalRuleCall(node))) {
const refRule = node.rule.ref;
if (refRule && !visitedSet.has(refRule.name)) {
ruleDfs(refRule, visitedSet, allTerminals);
}
}
});
}
/**
* Returns all parser rules which provide types which are used in the grammar as type in cross-references.
* @param grammar the grammar to investigate
* @returns the set of parser rules whose contributed types are used as type in cross-references
*/
export function getAllRulesUsedForCrossReferences(grammar) {
const result = new Set();
streamAllContents(grammar).forEach(node => {
if (ast.isCrossReference(node)) {
// the cross-reference refers directly to a parser rule (without "returns", without "infers")
if (ast.isParserRule(node.type.ref)) {
result.add(node.type.ref);
}
// the cross-reference refers to the explicitly inferred type of a parser rule
if (ast.isInferredType(node.type.ref) && ast.isParserRule(node.type.ref.$container)) {
result.add(node.type.ref.$container);
}
}
});
return result;
}
/**
* Determines the grammar expression used to parse a cross-reference (usually a reference to a terminal rule).
* A cross-reference can declare this expression explicitly in the form `[Type : Terminal]`, but if `Terminal`
* is omitted, this function attempts to infer it from the name of the referenced `Type` (using `findNameAssignment`).
*
* Returns the grammar expression used to parse the given cross-reference, or `undefined` if it is not declared
* and cannot be inferred.
*/
export function getCrossReferenceTerminal(crossRef) {
if (crossRef.terminal) {
return crossRef.terminal;
}
else if (crossRef.type.ref) {
const nameAssigment = findNameAssignment(crossRef.type.ref);
return nameAssigment?.terminal;
}
return undefined;
}
/**
* Determines whether the given terminal rule represents a comment. This is true if the rule is marked
* as `hidden` and it does not match white space. This means every hidden token (i.e. excluded from the AST)
* that contains visible characters is considered a comment.
*/
export function isCommentTerminal(terminalRule) {
return terminalRule.hidden && !isWhitespace(terminalRegex(terminalRule));
}
/**
* Find all CST nodes within the given node that contribute to the specified property.
*
* @param node A CST node in which to look for property assignments. If this is undefined, the result is an empty array.
* @param property A property name of the constructed AST node. If this is undefined, the result is an empty array.
*/
export function findNodesForProperty(node, property) {
if (!node || !property) {
return [];
}
return findNodesForPropertyInternal(node, property, node.astNode, true);
}
/**
* Find a single CST node within the given node that contributes to the specified property.
*
* @param node A CST node in which to look for property assignments. If this is undefined, the result is `undefined`.
* @param property A property name of the constructed AST node. If this is undefined, the result is `undefined`.
* @param index If no index is specified or the index is less than zero, the first found node is returned. If the
* specified index exceeds the number of assignments to the property, the last found node is returned. Otherwise,
* the node with the specified index is returned.
*/
export function findNodeForProperty(node, property, index) {
if (!node || !property) {
return undefined;
}
const nodes = findNodesForPropertyInternal(node, property, node.astNode, true);
if (nodes.length === 0) {
return undefined;
}
if (index !== undefined) {
index = Math.max(0, Math.min(index, nodes.length - 1));
}
else {
index = 0;
}
return nodes[index];
}
function findNodesForPropertyInternal(node, property, element, first) {
if (!first) {
const nodeFeature = getContainerOfType(node.grammarSource, ast.isAssignment);
if (nodeFeature && nodeFeature.feature === property) {
return [node];
}
}
if (isCompositeCstNode(node) && node.astNode === element) {
return node.content.flatMap(e => findNodesForPropertyInternal(e, property, element, false));
}
return [];
}
/**
* Find all CST nodes within the given node that correspond to the specified keyword.
*
* @param node A CST node in which to look for keywords. If this is undefined, the result is an empty array.
* @param keyword A keyword as specified in the grammar.
*/
export function findNodesForKeyword(node, keyword) {
if (!node) {
return [];
}
return findNodesForKeywordInternal(node, keyword, node?.astNode);
}
/**
* Find a single CST node within the given node that corresponds to the specified keyword.
*
* @param node A CST node in which to look for keywords. If this is undefined, the result is `undefined`.
* @param keyword A keyword as specified in the grammar.
* @param index If no index is specified or the index is less than zero, the first found node is returned. If the
* specified index exceeds the number of keyword occurrences, the last found node is returned. Otherwise,
* the node with the specified index is returned.
*/
export function findNodeForKeyword(node, keyword, index) {
if (!node) {
return undefined;
}
const nodes = findNodesForKeywordInternal(node, keyword, node?.astNode);
if (nodes.length === 0) {
return undefined;
}
if (index !== undefined) {
index = Math.max(0, Math.min(index, nodes.length - 1));
}
else {
index = 0;
}
return nodes[index];
}
export function findNodesForKeywordInternal(node, keyword, element) {
if (node.astNode !== element) {
return [];
}
if (ast.isKeyword(node.grammarSource) && node.grammarSource.value === keyword) {
return [node];
}
const treeIterator = streamCst(node).iterator();
let result;
const keywordNodes = [];
do {
result = treeIterator.next();
if (!result.done) {
const childNode = result.value;
if (childNode.astNode === element) {
if (ast.isKeyword(childNode.grammarSource) && childNode.grammarSource.value === keyword) {
keywordNodes.push(childNode);
}
}
else {
treeIterator.prune();
}
}
} while (!result.done);
return keywordNodes;
}
/**
* If the given CST node was parsed in the context of a property assignment, the respective `Assignment` grammar
* node is returned. If no assignment is found, the result is `undefined`.
*
* @param cstNode A CST node for which to find a property assignment.
*/
export function findAssignment(cstNode) {
const astNode = cstNode.astNode;
// Only search until the ast node of the parent cst node is no longer the original ast node
// This would make us jump to a preceding rule call, which contains only unrelated assignments
while (astNode === cstNode.container?.astNode) {
const assignment = getContainerOfType(cstNode.grammarSource, ast.isAssignment);
if (assignment) {
return assignment;
}
cstNode = cstNode.container;
}
return undefined;
}
/**
* Find an assignment to the `name` property for the given grammar type. This requires the `type` to be inferred
* from a parser rule, and that rule must contain an assignment to the `name` property. In all other cases,
* this function returns `undefined`.
*/
export function findNameAssignment(type) {
let startNode = type;
if (ast.isInferredType(startNode)) {
// for inferred types, the location to start searching for the name-assignment is different
if (ast.isAction(startNode.$container)) {
// a type which is explicitly inferred by an action: investigate the sibling of the Action node, i.e. start searching at the Action's parent
startNode = startNode.$container.$container;
}
else if (ast.isAbstractParserRule(startNode.$container)) {
// investigate the parser rule with the explicitly inferred type
startNode = startNode.$container;
}
else {
assertUnreachable(startNode.$container);
}
}
return findNameAssignmentInternal(type, startNode, new Map());
}
function findNameAssignmentInternal(type, startNode, cache) {
// the cache is only required to prevent infinite loops
function go(node, refType) {
let childAssignment = undefined;
const parentAssignment = getContainerOfType(node, ast.isAssignment);
// No parent assignment implies unassigned rule call
if (!parentAssignment) {
childAssignment = findNameAssignmentInternal(refType, refType, cache);
}
cache.set(type, childAssignment);
return childAssignment;
}
if (cache.has(type)) {
return cache.get(type);
}
cache.set(type, undefined);
for (const node of streamAllContents(startNode)) {
if (ast.isAssignment(node) && node.feature.toLowerCase() === 'name') {
cache.set(type, node);
return node;
}
else if (ast.isRuleCall(node) && ast.isParserRule(node.rule.ref)) {
return go(node, node.rule.ref);
}
else if (ast.isSimpleType(node) && node.typeRef?.ref) {
return go(node, node.typeRef.ref);
}
}
return undefined;
}
export function getActionAtElement(element) {
const parent = element.$container;
if (ast.isGroup(parent)) {
const elements = parent.elements;
const index = elements.indexOf(element);
for (let i = index - 1; i >= 0; i--) {
const item = elements[i];
if (ast.isAction(item)) {
return item;
}
else {
const action = streamAllContents(elements[i]).find(ast.isAction);
if (action) {
return action;
}
}
}
}
if (ast.isAbstractElement(parent)) {
return getActionAtElement(parent);
}
else {
return undefined;
}
}
export function isOptionalCardinality(cardinality, element) {
return cardinality === '?' || cardinality === '*' || (ast.isGroup(element) && Boolean(element.guardCondition));
}
export function isArrayCardinality(cardinality) {
return cardinality === '*' || cardinality === '+';
}
export function isArrayOperator(operator) {
return operator === '+=';
}
/**
* Determines whether the given parser rule is a _data type rule_, meaning that it has a
* primitive return type like `number`, `boolean`, etc.
*/
export function isDataTypeRule(rule) {
return isDataTypeRuleInternal(rule, new Set());
}
function isDataTypeRuleInternal(rule, visited) {
if (visited.has(rule)) {
return true;
}
else {
visited.add(rule);
}
for (const node of streamAllContents(rule)) {
if (ast.isRuleCall(node)) {
if (!node.rule.ref) {
// RuleCall to unresolved rule. Don't assume `rule` is a DataType rule.
return false;
}
if (ast.isParserRule(node.rule.ref) && !isDataTypeRuleInternal(node.rule.ref, visited)) {
return false;
}
if (ast.isInfixRule(node.rule.ref)) {
return false;
}
}
else if (ast.isAssignment(node)) {
return false;
}
else if (ast.isAction(node)) {
return false;
}
}
return Boolean(rule.definition);
}
export function isDataType(type) {
return isDataTypeInternal(type.type, new Set());
}
function isDataTypeInternal(type, visited) {
if (visited.has(type)) {
return true;
}
else {
visited.add(type);
}
if (ast.isArrayType(type)) {
return false;
}
else if (ast.isReferenceType(type)) {
return false;
}
else if (ast.isUnionType(type)) {
return type.types.every(e => isDataTypeInternal(e, visited));
}
else if (ast.isSimpleType(type)) {
if (type.primitiveType !== undefined) {
return true;
}
else if (type.stringType !== undefined) {
return true;
}
else if (type.typeRef !== undefined) {
const ref = type.typeRef.ref;
if (ast.isType(ref)) {
return isDataTypeInternal(ref.type, visited);
}
else {
return false;
}
}
else {
return false;
}
}
else {
return false;
}
}
export function getExplicitRuleType(rule) {
if (ast.isTerminalRule(rule)) {
return undefined;
}
if (rule.inferredType) {
return rule.inferredType.name;
}
else if (rule.dataType) {
return rule.dataType;
}
else if (rule.returnType) {
const refType = rule.returnType.ref;
if (refType) {
return refType.name;
}
}
return undefined;
}
export function getTypeName(type) {
if (ast.isAbstractParserRule(type)) {
return ast.isParserRule(type) && isDataTypeRule(type) ? type.name : getExplicitRuleType(type) ?? type.name;
}
else if (ast.isInterface(type) || ast.isType(type) || ast.isReturnType(type)) {
return type.name;
}
else if (ast.isAction(type)) {
const actionType = getActionType(type);
if (actionType) {
return actionType;
}
}
else if (ast.isInferredType(type)) {
return type.name;
}
throw new Error('Cannot get name of Unknown Type');
}
export function getActionType(action) {
if (action.inferredType) {
return action.inferredType.name;
}
else if (action.type?.ref) {
return getTypeName(action.type.ref);
}
return undefined; // not inferring and not referencing a valid type
}
/**
* This function is used at development time (for code generation and the internal type system) to get the type of the AST node produced by the given rule.
* For data type rules, the name of the rule is returned,
* e.g. "INT_value returns number: MY_INT;" returns "INT_value".
* @param rule the given rule
* @returns the name of the AST node type of the rule
*/
export function getRuleTypeName(rule) {
if (ast.isTerminalRule(rule)) {
return rule.type?.name ?? 'string';
}
else {
return ast.isParserRule(rule) && isDataTypeRule(rule) ? rule.name : getExplicitRuleType(rule) ?? rule.name;
}
}
/**
* This function is used at runtime to get the actual type of the values produced by the given rule at runtime.
* For data type rules, the name of the declared return type of the rule is returned (if any),
* e.g. "INT_value returns number: MY_INT;" returns "number".
* @param rule the given rule
* @returns the name of the type of the produced values of the rule at runtime
*/
export function getRuleType(rule) {
if (ast.isTerminalRule(rule)) {
return rule.type?.name ?? 'string';
}
else {
return getExplicitRuleType(rule) ?? rule.name;
}
}
export function terminalRegex(terminalRule) {
const flags = {
s: false,
i: false,
u: false
};
const source = abstractElementToRegex(terminalRule.definition, flags);
const flagText = Object.entries(flags).filter(([, value]) => value).map(([name]) => name).join('');
return new RegExp(source, flagText);
}
// Using [\s\S]* allows to match everything, compared to . which doesn't match line terminators
const WILDCARD = /[\s\S]/.source;
function abstractElementToRegex(element, flags) {
if (ast.isTerminalAlternatives(element)) {
return terminalAlternativesToRegex(element);
}
else if (ast.isTerminalGroup(element)) {
return terminalGroupToRegex(element);
}
else if (ast.isCharacterRange(element)) {
return characterRangeToRegex(element);
}
else if (ast.isTerminalRuleCall(element)) {
const rule = element.rule.ref;
if (!rule) {
throw new Error('Missing rule reference.');
}
return withCardinality(abstractElementToRegex(rule.definition), {
cardinality: element.cardinality,
lookahead: element.lookahead,
parenthesized: element.parenthesized
});
}
else if (ast.isNegatedToken(element)) {
return negateTokenToRegex(element);
}
else if (ast.isUntilToken(element)) {
return untilTokenToRegex(element);
}
else if (ast.isRegexToken(element)) {
const lastSlash = element.regex.lastIndexOf('/');
const source = element.regex.substring(1, lastSlash);
const regexFlags = element.regex.substring(lastSlash + 1);
if (flags) {
flags.i = regexFlags.includes('i');
flags.s = regexFlags.includes('s');
flags.u = regexFlags.includes('u');
}
return withCardinality(source, {
cardinality: element.cardinality,
lookahead: element.lookahead,
parenthesized: element.parenthesized,
wrap: false
});
}
else if (ast.isWildcard(element)) {
return withCardinality(WILDCARD, {
cardinality: element.cardinality,
lookahead: element.lookahead,
parenthesized: element.parenthesized
});
}
else {
throw new Error(`Invalid terminal element: ${element?.$type}, ${element?.$cstNode?.text}`);
}
}
function terminalAlternativesToRegex(alternatives) {
return withCardinality(alternatives.elements.map(e => abstractElementToRegex(e)).join('|'), {
cardinality: alternatives.cardinality,
lookahead: alternatives.lookahead,
parenthesized: alternatives.parenthesized,
wrap: false // wrapping is not required for top level alternatives, and nested alternatives are already parenthesized according to the grammar
});
}
function terminalGroupToRegex(group) {
return withCardinality(group.elements.map(e => abstractElementToRegex(e)).join(''), {
cardinality: group.cardinality,
lookahead: group.lookahead,
parenthesized: group.parenthesized,
wrap: false // wrapping is not required for top level group, and nested group are already parenthesized according to the grammar
});
}
function untilTokenToRegex(until) {
return withCardinality(`${WILDCARD}*?${abstractElementToRegex(until.terminal)}`, {
cardinality: until.cardinality,
lookahead: until.lookahead,
parenthesized: until.parenthesized
});
}
function negateTokenToRegex(negate) {
return withCardinality(`(?!${abstractElementToRegex(negate.terminal)})${WILDCARD}*?`, {
cardinality: negate.cardinality,
lookahead: negate.lookahead,
parenthesized: negate.parenthesized
});
}
function characterRangeToRegex(range) {
if (range.right) {
return withCardinality(`[${keywordToRegex(range.left)}-${keywordToRegex(range.right)}]`, {
cardinality: range.cardinality,
lookahead: range.lookahead,
parenthesized: range.parenthesized,
wrap: false
});
}
return withCardinality(keywordToRegex(range.left), {
cardinality: range.cardinality,
lookahead: range.lookahead,
parenthesized: range.parenthesized,
wrap: false
});
}
function keywordToRegex(keyword) {
return escapeRegExp(keyword.value);
}
function withCardinality(regex, options) {
if (options.parenthesized || options.lookahead || options.wrap !== false) {
const groupConfig = options.lookahead ?? (options.parenthesized ? '' : '?:');
regex = `(${groupConfig}${regex})`;
}
if (options.cardinality) {
return `${regex}${options.cardinality}`;
}
return regex;
}
//# sourceMappingURL=grammar-utils.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"promise-utils.d.ts","sourceRoot":"","sources":["../../src/utils/promise-utils.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAAE,iBAAiB,EAA2B,KAAK,+BAA+B,EAAE,MAAM,0BAA0B,CAAC;AAE5H,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;AAE5C;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAU7C;AAKD;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,+BAA+B,CAG1E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAE1D;AAED;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,eAA+B,CAAC;AAE/D;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,OAAO,kBAAkB,CAEnF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/E;AAED;;;GAGG;AACH,qBAAa,QAAQ,CAAC,CAAC,GAAG,IAAI;IAC1B,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC5B,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAEhC,OAAO,aASJ;CACN"}

View File

@@ -0,0 +1,99 @@
/******************************************************************************
* Copyright 2021 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { CancellationToken, CancellationTokenSource } from '../utils/cancellation.js';
/**
* Delays the execution of the current code to the next tick of the event loop.
* Don't call this method directly in a tight loop to prevent too many promises from being created.
*/
export function delayNextTick() {
return new Promise(resolve => {
// In case we are running in a non-node environment, `setImmediate` isn't available.
// Using `setTimeout` of the browser API accomplishes the same result.
if (typeof setImmediate === 'undefined') {
setTimeout(resolve, 0);
}
else {
setImmediate(resolve);
}
});
}
let lastTick = 0;
let globalInterruptionPeriod = 10;
/**
* Reset the global interruption period and create a cancellation token source.
*/
export function startCancelableOperation() {
lastTick = performance.now();
return new CancellationTokenSource();
}
/**
* Change the period duration for `interruptAndCheck` to the given number of milliseconds.
* The default value is 10ms.
*/
export function setInterruptionPeriod(period) {
globalInterruptionPeriod = period;
}
/**
* This symbol may be thrown in an asynchronous context by any Langium service that receives
* a `CancellationToken`. This means that the promise returned by such a service is rejected with
* this symbol as rejection reason.
*/
export const OperationCancelled = Symbol('OperationCancelled');
/**
* Use this in a `catch` block to check whether the thrown object indicates that the operation
* has been cancelled.
*/
export function isOperationCancelled(err) {
return err === OperationCancelled;
}
/**
* This function does two things:
* 1. Check the elapsed time since the last call to this function or to `startCancelableOperation`. If the predefined
* period (configured with `setInterruptionPeriod`) is exceeded, execution is delayed with `delayNextTick`.
* 2. If the predefined period is not met yet or execution is resumed after an interruption, the given cancellation
* token is checked, and if cancellation is requested, `OperationCanceled` is thrown.
*
* All services in Langium that receive a `CancellationToken` may potentially call this function, so the
* `CancellationToken` must be caught (with an `async` try-catch block or a `catch` callback attached to
* the promise) to avoid that event being exposed as an error.
*/
export async function interruptAndCheck(token) {
if (token === CancellationToken.None) {
// Early exit in case cancellation was disabled by the caller
return;
}
const current = performance.now();
if (current - lastTick >= globalInterruptionPeriod) {
lastTick = current;
await delayNextTick();
// prevent calling delayNextTick every iteration of loop
// where delayNextTick takes up the majority or all of the
// globalInterruptionPeriod itself
lastTick = performance.now();
}
if (token.isCancellationRequested) {
throw OperationCancelled;
}
}
/**
* Simple implementation of the deferred pattern.
* An object that exposes a promise and functions to resolve and reject it.
*/
export class Deferred {
constructor() {
this.promise = new Promise((resolve, reject) => {
this.resolve = (arg) => {
resolve(arg);
return this;
};
this.reject = (err) => {
reject(err);
return this;
};
});
}
}
//# sourceMappingURL=promise-utils.js.map

294
frontend/node_modules/langium/lib/utils/regexp-utils.js generated vendored Normal file
View File

@@ -0,0 +1,294 @@
/******************************************************************************
* Copyright 2021 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { RegExpParser, BaseRegExpVisitor } from '@chevrotain/regexp-to-ast';
export const NEWLINE_REGEXP = /\r?\n/gm;
const regexpParser = new RegExpParser();
/**
* This class is in charge of heuristically identifying start/end tokens of terminals.
*
* The way this works is by doing the following:
* 1. Traverse the regular expression in the "start state"
* 2. Add any encountered sets/single characters to the "start regexp"
* 3. Once we encounter any variable-length content (i.e. with quantifiers such as +/?/*), we enter the "end state"
* 4. In the end state, any sets/single characters are added to an "end stack".
* 5. If we re-encounter any variable-length content we reset the end stack
* 6. We continue visiting the regex until the end, reseting the end stack and rebuilding it as necessary
*
* After traversing a regular expression the `startRegexp/endRegexp` properties allow access to the stored start/end of the terminal
*/
class TerminalRegExpVisitor extends BaseRegExpVisitor {
constructor() {
super(...arguments);
this.isStarting = true;
this.endRegexpStack = [];
this.multiline = false;
}
get endRegex() {
return this.endRegexpStack.join('');
}
reset(regex) {
this.multiline = false;
this.regex = regex;
this.startRegexp = '';
this.isStarting = true;
this.endRegexpStack = [];
}
visitGroup(node) {
if (node.quantifier) {
this.isStarting = false;
this.endRegexpStack = [];
}
}
visitCharacter(node) {
const char = String.fromCharCode(node.value);
if (!this.multiline && char === '\n') {
this.multiline = true;
}
if (node.quantifier) {
this.isStarting = false;
this.endRegexpStack = [];
}
else {
const escapedChar = escapeRegExp(char);
this.endRegexpStack.push(escapedChar);
if (this.isStarting) {
this.startRegexp += escapedChar;
}
}
}
visitSet(node) {
if (!this.multiline) {
const set = this.regex.substring(node.loc.begin, node.loc.end);
const regex = new RegExp(set);
this.multiline = Boolean('\n'.match(regex));
}
if (node.quantifier) {
this.isStarting = false;
this.endRegexpStack = [];
}
else {
const set = this.regex.substring(node.loc.begin, node.loc.end);
this.endRegexpStack.push(set);
if (this.isStarting) {
this.startRegexp += set;
}
}
}
visitChildren(node) {
if (node.type === 'Group') {
// Ignore children of groups with quantifier (+/*/?)
// These groups are unrelated to start/end tokens of terminals
const group = node;
if (group.quantifier) {
return;
}
}
super.visitChildren(node);
}
}
const visitor = new TerminalRegExpVisitor();
export function getTerminalParts(regexp) {
try {
if (typeof regexp !== 'string') {
regexp = regexp.source;
}
regexp = `/${regexp}/`;
const pattern = regexpParser.pattern(regexp);
const parts = [];
for (const alternative of pattern.value.value) {
visitor.reset(regexp);
visitor.visit(alternative);
parts.push({
start: visitor.startRegexp,
end: visitor.endRegex
});
}
return parts;
}
catch {
return [];
}
}
export function isMultilineComment(regexp) {
try {
if (typeof regexp === 'string') {
regexp = new RegExp(regexp);
}
regexp = regexp.toString();
visitor.reset(regexp);
// Parsing the pattern might fail (since it's user code)
visitor.visit(regexpParser.pattern(regexp));
return visitor.multiline;
}
catch {
return false;
}
}
/**
* A set of all characters that are considered whitespace by the '\s' RegExp character class.
* Taken from [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Character_classes).
*/
export const whitespaceCharacters = ('\f\n\r\t\v\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007' +
'\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff').split('');
export function isWhitespace(value) {
const regexp = typeof value === 'string' ? new RegExp(value) : value;
return whitespaceCharacters.some((ws) => regexp.test(ws));
}
export function escapeRegExp(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
/**
* Determines whether the given input has a partial match with the specified regex.
* @param regex The regex to partially match against
* @param input The input string
* @returns Whether any match exists.
*/
export function partialMatches(regex, input) {
const partial = partialRegExp(regex);
const match = input.match(partial);
return !!match && match[0].length > 0;
}
/**
* Builds a partial regex from the input regex. A partial regex is able to match incomplete input strings. E.g.
* a partial regex constructed from `/ab/` is able to match the string `a` without needing a following `b` character. However it won't match `b` alone.
* @param regex The input regex to be converted.
* @returns A partial regex constructed from the input regex.
*/
export function partialRegExp(regex) {
if (typeof regex === 'string') {
regex = new RegExp(regex);
}
const re = regex, source = regex.source;
let i = 0;
function process() {
let result = '', tmp;
function appendRaw(nbChars) {
result += source.substr(i, nbChars);
i += nbChars;
}
function appendOptional(nbChars) {
result += '(?:' + source.substr(i, nbChars) + '|$)';
i += nbChars;
}
while (i < source.length) {
switch (source[i]) {
case '\\':
switch (source[i + 1]) {
case 'c':
appendOptional(3);
break;
case 'x':
appendOptional(4);
break;
case 'u':
if (re.unicode) {
if (source[i + 2] === '{') {
appendOptional(source.indexOf('}', i) - i + 1);
}
else {
appendOptional(6);
}
}
else {
appendOptional(2);
}
break;
case 'p':
case 'P':
if (re.unicode) {
appendOptional(source.indexOf('}', i) - i + 1);
}
else {
appendOptional(2);
}
break;
case 'k':
appendOptional(source.indexOf('>', i) - i + 1);
break;
default:
appendOptional(2);
break;
}
break;
case '[':
tmp = /\[(?:\\.|.)*?\]/g;
tmp.lastIndex = i;
tmp = tmp.exec(source) || [];
appendOptional(tmp[0].length);
break;
case '|':
case '^':
case '$':
case '*':
case '+':
case '?':
appendRaw(1);
break;
case '{':
tmp = /\{\d+,?\d*\}/g;
tmp.lastIndex = i;
tmp = tmp.exec(source);
if (tmp) {
appendRaw(tmp[0].length);
}
else {
appendOptional(1);
}
break;
case '(':
if (source[i + 1] === '?') {
switch (source[i + 2]) {
case ':':
result += '(?:';
i += 3;
result += process() + '|$)';
break;
case '=':
result += '(?=';
i += 3;
result += process() + ')';
break;
case '!':
tmp = i;
i += 3;
process();
result += source.substr(tmp, i - tmp);
break;
case '<':
switch (source[i + 3]) {
case '=':
case '!':
tmp = i;
i += 4;
process();
result += source.substr(tmp, i - tmp);
break;
default:
appendRaw(source.indexOf('>', i) - i + 1);
result += process() + '|$)';
break;
}
break;
}
}
else {
appendRaw(1);
result += process() + '|$)';
}
break;
case ')':
++i;
return result;
default:
appendOptional(1);
break;
}
}
return result;
}
return new RegExp(process(), regex.flags);
}
//# sourceMappingURL=regexp-utils.js.map

510
frontend/node_modules/langium/lib/utils/stream.js generated vendored Normal file
View File

@@ -0,0 +1,510 @@
/******************************************************************************
* Copyright 2021 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
/**
* The default implementation of `Stream` works with two input functions:
* - The first function creates the initial state of an iteration.
* - The second function gets the current state as argument and returns an `IteratorResult`.
*/
export class StreamImpl {
constructor(startFn, nextFn) {
this.startFn = startFn;
this.nextFn = nextFn;
}
iterator() {
const iterator = {
state: this.startFn(),
next: () => this.nextFn(iterator.state),
[Symbol.iterator]: () => iterator
};
return iterator;
}
[Symbol.iterator]() {
return this.iterator();
}
isEmpty() {
const iterator = this.iterator();
return Boolean(iterator.next().done);
}
count() {
const iterator = this.iterator();
let count = 0;
let next = iterator.next();
while (!next.done) {
count++;
next = iterator.next();
}
return count;
}
toArray() {
const result = [];
const iterator = this.iterator();
let next;
do {
next = iterator.next();
if (next.value !== undefined) {
result.push(next.value);
}
} while (!next.done);
return result;
}
toSet() {
return new Set(this);
}
toMap(keyFn, valueFn) {
const entryStream = this.map(element => [
keyFn ? keyFn(element) : element,
valueFn ? valueFn(element) : element
]);
return new Map(entryStream);
}
toString() {
return this.join();
}
concat(other) {
return new StreamImpl(() => ({ first: this.startFn(), firstDone: false, iterator: other[Symbol.iterator]() }), state => {
let result;
if (!state.firstDone) {
do {
result = this.nextFn(state.first);
if (!result.done) {
return result;
}
} while (!result.done);
state.firstDone = true;
}
do {
result = state.iterator.next();
if (!result.done) {
return result;
}
} while (!result.done);
return DONE_RESULT;
});
}
join(separator = ',') {
const iterator = this.iterator();
let value = '';
let result;
let addSeparator = false;
do {
result = iterator.next();
if (!result.done) {
if (addSeparator) {
value += separator;
}
value += toString(result.value);
}
addSeparator = true;
} while (!result.done);
return value;
}
indexOf(searchElement, fromIndex = 0) {
const iterator = this.iterator();
let index = 0;
let next = iterator.next();
while (!next.done) {
if (index >= fromIndex && next.value === searchElement) {
return index;
}
next = iterator.next();
index++;
}
return -1;
}
every(predicate) {
const iterator = this.iterator();
let next = iterator.next();
while (!next.done) {
if (!predicate(next.value)) {
return false;
}
next = iterator.next();
}
return true;
}
some(predicate) {
const iterator = this.iterator();
let next = iterator.next();
while (!next.done) {
if (predicate(next.value)) {
return true;
}
next = iterator.next();
}
return false;
}
forEach(callbackfn) {
const iterator = this.iterator();
let index = 0;
let next = iterator.next();
while (!next.done) {
callbackfn(next.value, index);
next = iterator.next();
index++;
}
}
map(callbackfn) {
return new StreamImpl(this.startFn, (state) => {
const { done, value } = this.nextFn(state);
if (done) {
return DONE_RESULT;
}
else {
return { done: false, value: callbackfn(value) };
}
});
}
filter(predicate) {
return new StreamImpl(this.startFn, state => {
let result;
do {
result = this.nextFn(state);
if (!result.done && predicate(result.value)) {
return result;
}
} while (!result.done);
return DONE_RESULT;
});
}
nonNullable() {
return this.filter(e => e !== undefined && e !== null);
}
reduce(callbackfn, initialValue) {
const iterator = this.iterator();
let previousValue = initialValue;
let next = iterator.next();
while (!next.done) {
if (previousValue === undefined) {
previousValue = next.value;
}
else {
previousValue = callbackfn(previousValue, next.value);
}
next = iterator.next();
}
return previousValue;
}
reduceRight(callbackfn, initialValue) {
return this.recursiveReduce(this.iterator(), callbackfn, initialValue);
}
recursiveReduce(iterator, callbackfn, initialValue) {
const next = iterator.next();
if (next.done) {
return initialValue;
}
const previousValue = this.recursiveReduce(iterator, callbackfn, initialValue);
if (previousValue === undefined) {
return next.value;
}
return callbackfn(previousValue, next.value);
}
find(predicate) {
const iterator = this.iterator();
let next = iterator.next();
while (!next.done) {
if (predicate(next.value)) {
return next.value;
}
next = iterator.next();
}
return undefined;
}
findIndex(predicate) {
const iterator = this.iterator();
let index = 0;
let next = iterator.next();
while (!next.done) {
if (predicate(next.value)) {
return index;
}
next = iterator.next();
index++;
}
return -1;
}
includes(searchElement) {
const iterator = this.iterator();
let next = iterator.next();
while (!next.done) {
if (next.value === searchElement) {
return true;
}
next = iterator.next();
}
return false;
}
flatMap(callbackfn) {
return new StreamImpl(() => ({ this: this.startFn() }), (state) => {
do {
if (state.iterator) {
const next = state.iterator.next();
if (next.done) {
state.iterator = undefined;
}
else {
return next;
}
}
const { done, value } = this.nextFn(state.this);
if (!done) {
const mapped = callbackfn(value);
if (isIterable(mapped)) {
state.iterator = mapped[Symbol.iterator]();
}
else {
return { done: false, value: mapped };
}
}
} while (state.iterator);
return DONE_RESULT;
});
}
flat(depth) {
if (depth === undefined) {
depth = 1;
}
if (depth <= 0) {
return this;
}
const stream = depth > 1 ? this.flat(depth - 1) : this;
return new StreamImpl(() => ({ this: stream.startFn() }), (state) => {
do {
if (state.iterator) {
const next = state.iterator.next();
if (next.done) {
state.iterator = undefined;
}
else {
return next;
}
}
const { done, value } = stream.nextFn(state.this);
if (!done) {
if (isIterable(value)) {
state.iterator = value[Symbol.iterator]();
}
else {
return { done: false, value: value };
}
}
} while (state.iterator);
return DONE_RESULT;
});
}
head() {
const iterator = this.iterator();
const result = iterator.next();
if (result.done) {
return undefined;
}
return result.value;
}
tail(skipCount = 1) {
return new StreamImpl(() => {
const state = this.startFn();
for (let i = 0; i < skipCount; i++) {
const next = this.nextFn(state);
if (next.done) {
return state;
}
}
return state;
}, this.nextFn);
}
limit(maxSize) {
return new StreamImpl(() => ({ size: 0, state: this.startFn() }), state => {
state.size++;
if (state.size > maxSize) {
return DONE_RESULT;
}
return this.nextFn(state.state);
});
}
distinct(by) {
return new StreamImpl(() => ({ set: new Set(), internalState: this.startFn() }), state => {
let result;
do {
result = this.nextFn(state.internalState);
if (!result.done) {
const value = by ? by(result.value) : result.value;
if (!state.set.has(value)) {
state.set.add(value);
return result;
}
}
} while (!result.done);
return DONE_RESULT;
});
}
exclude(other, key) {
const otherKeySet = new Set();
for (const item of other) {
const value = key ? key(item) : item;
otherKeySet.add(value);
}
return this.filter(e => {
const ownKey = key ? key(e) : e;
return !otherKeySet.has(ownKey);
});
}
}
function toString(item) {
if (typeof item === 'string') {
return item;
}
if (typeof item === 'undefined') {
return 'undefined';
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (typeof item.toString === 'function') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return item.toString();
}
return Object.prototype.toString.call(item);
}
function isIterable(obj) {
return !!obj && typeof obj[Symbol.iterator] === 'function';
}
/**
* An empty stream of any type.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const EMPTY_STREAM = new StreamImpl(() => undefined, () => DONE_RESULT);
/**
* Use this `IteratorResult` when implementing a `StreamImpl` to indicate that there are no more elements in the stream.
*/
export const DONE_RESULT = Object.freeze({ done: true, value: undefined });
/**
* Create a stream from one or more iterables or array-likes.
*/
export function stream(...collections) {
if (collections.length === 1) {
const collection = collections[0];
if (collection instanceof StreamImpl) {
return collection;
}
if (isIterable(collection)) {
return new StreamImpl(() => collection[Symbol.iterator](), (iterator) => iterator.next());
}
if (typeof collection.length === 'number') {
return new StreamImpl(() => ({ index: 0 }), (state) => {
if (state.index < collection.length) {
return { done: false, value: collection[state.index++] };
}
else {
return DONE_RESULT;
}
});
}
}
if (collections.length > 1) {
return new StreamImpl(() => ({ collIndex: 0, arrIndex: 0 }), (state) => {
do {
if (state.iterator) {
const next = state.iterator.next();
if (!next.done) {
return next;
}
state.iterator = undefined;
}
if (state.array) {
if (state.arrIndex < state.array.length) {
return { done: false, value: state.array[state.arrIndex++] };
}
state.array = undefined;
state.arrIndex = 0;
}
if (state.collIndex < collections.length) {
const collection = collections[state.collIndex++];
if (isIterable(collection)) {
state.iterator = collection[Symbol.iterator]();
}
else if (collection && typeof collection.length === 'number') {
state.array = collection;
}
}
} while (state.iterator || state.array || state.collIndex < collections.length);
return DONE_RESULT;
});
}
return EMPTY_STREAM;
}
/**
* The default implementation of `TreeStream` takes a root element and a function that computes the
* children of its argument. Whether the root node included in the stream is controlled with the
* `includeRoot` option, which defaults to `false`.
*/
export class TreeStreamImpl extends StreamImpl {
constructor(root, children, options) {
super(() => ({
iterators: options?.includeRoot ? [[root][Symbol.iterator]()] : [children(root)[Symbol.iterator]()],
pruned: false
}), state => {
if (state.pruned) {
state.iterators.pop();
state.pruned = false;
}
while (state.iterators.length > 0) {
const iterator = state.iterators[state.iterators.length - 1];
const next = iterator.next();
if (next.done) {
state.iterators.pop();
}
else {
state.iterators.push(children(next.value)[Symbol.iterator]());
return next;
}
}
return DONE_RESULT;
});
}
iterator() {
const iterator = {
state: this.startFn(),
next: () => this.nextFn(iterator.state),
prune: () => {
iterator.state.pruned = true;
},
[Symbol.iterator]: () => iterator
};
return iterator;
}
}
/**
* A set of utility functions that reduce a stream to a single value.
*/
export var Reduction;
(function (Reduction) {
/**
* Compute the sum of a number stream.
*/
function sum(stream) {
return stream.reduce((a, b) => a + b, 0);
}
Reduction.sum = sum;
/**
* Compute the product of a number stream.
*/
function product(stream) {
return stream.reduce((a, b) => a * b, 0);
}
Reduction.product = product;
/**
* Compute the minimum of a number stream. Returns `undefined` if the stream is empty.
*/
function min(stream) {
return stream.reduce((a, b) => Math.min(a, b));
}
Reduction.min = min;
/**
* Compute the maximum of a number stream. Returns `undefined` if the stream is empty.
*/
function max(stream) {
return stream.reduce((a, b) => Math.max(a, b));
}
Reduction.max = max;
})(Reduction || (Reduction = {}));
//# sourceMappingURL=stream.js.map

55
frontend/node_modules/langium/lib/utils/uri-utils.d.ts generated vendored Normal file
View File

@@ -0,0 +1,55 @@
/******************************************************************************
* Copyright 2022 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { URI, Utils } from 'vscode-uri';
export { URI };
export declare namespace UriUtils {
const basename: typeof Utils.basename;
const dirname: typeof Utils.dirname;
const extname: typeof Utils.extname;
const joinPath: typeof Utils.joinPath;
const resolvePath: typeof Utils.resolvePath;
function equals(a?: URI | string, b?: URI | string): boolean;
function relative(from: URI | string, to: URI | string): string;
function normalize(uri: URI | string): string;
function contains(parent: URI | string, child: URI | string): boolean;
}
interface InternalUriTrieNode<T> {
name: string;
children: Map<string, InternalUriTrieNode<T>>;
parent?: InternalUriTrieNode<T>;
element?: T;
}
export interface UriTrieNode<T> {
name: string;
uri: string;
element?: T;
}
/**
* A trie structure for URIs. It allows to insert, delete and find elements by their URI.
* More specifically, it allows to efficiently find all elements that are children of a given URI.
*
* Unlike a regular trie, this implementation uses the name of the URI segments as keys.
*
* @see {@link https://en.wikipedia.org/wiki/Trie}
*/
export declare class UriTrie<T> {
protected readonly root: InternalUriTrieNode<T>;
protected normalizeUri(uri: URI | string): string;
clear(): void;
insert(uri: URI | string, element: T): void;
delete(uri: URI | string): void;
has(uri: URI | string): boolean;
hasNode(uri: URI | string): boolean;
find(uri: URI | string): T | undefined;
findNode(uri: URI | string): UriTrieNode<T> | undefined;
findChildren(uri: URI | string): Array<UriTrieNode<T>>;
all(): T[];
findAll(prefix: URI | string): T[];
protected getNode(uri: string, create: true): InternalUriTrieNode<T>;
protected getNode(uri: string, create: false): InternalUriTrieNode<T> | undefined;
protected collectValues(node: InternalUriTrieNode<T>): T[];
}
//# sourceMappingURL=uri-utils.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"uri-utils.d.ts","sourceRoot":"","sources":["../../src/utils/uri-utils.ts"],"names":[],"mappings":"AAAA;;;;gFAIgF;AAEhF,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,GAAG,EAAE,CAAC;AAEf,yBAAiB,QAAQ,CAAC;IAEf,MAAM,QAAQ,uBAAiB,CAAC;IAChC,MAAM,OAAO,sBAAgB,CAAC;IAC9B,MAAM,OAAO,sBAAgB,CAAC;IAC9B,MAAM,QAAQ,uBAAiB,CAAC;IAChC,MAAM,WAAW,0BAAoB,CAAC;IAI7C,SAAgB,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,CAElE;IAED,SAAgB,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,MAAM,GAAG,MAAM,CA6BrE;IAED,SAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,MAAM,CAEnD;IAED,SAAgB,QAAQ,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO,CAwB3E;CAEJ;AAED,UAAU,mBAAmB,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC;IAEhC,OAAO,CAAC,EAAE,CAAC,CAAC;CACf;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,CAAC,CAAC;CACf;AAED;;;;;;;GAOG;AACH,qBAAa,OAAO,CAAC,CAAC;IAElB,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAqC;IAEpF,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,MAAM;IAIjD,KAAK,IAAI,IAAI;IAIb,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI;IAK3C,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI;IAO/B,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO;IAI/B,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,OAAO;IAInC,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,SAAS;IAItC,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS;IAavD,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAatD,GAAG,IAAI,CAAC,EAAE;IAIV,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,GAAG,CAAC,EAAE;IAQlC,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,mBAAmB,CAAC,CAAC,CAAC;IACpE,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,GAAG,mBAAmB,CAAC,CAAC,CAAC,GAAG,SAAS;IA2BjF,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE;CAW7D"}