ConceptPortal-public/rsconcept/frontend/src/utils/staticUI.ts

453 lines
18 KiB
TypeScript
Raw Normal View History

2023-07-30 00:47:07 +03:00
import { LayoutTypes } from 'reagraph';
2023-07-29 03:31:21 +03:00
import { resolveErrorClass,RSErrorClass, RSErrorType, TokenID } from './enums';
import { CstType, ExpressionStatus, type IConstituenta, IRSErrorDescription,type IRSForm, ParsingStatus, ValueClass } from './models';
2023-07-20 17:11:03 +03:00
export interface IRSButtonData {
text: string
tooltip: string
}
export interface IStatusInfo {
text: string
color: string
tooltip: string
}
export function getTypeLabel(cst: IConstituenta) {
if (cst.parse?.typification) {
2023-07-25 20:27:29 +03:00
return cst.parse.typification;
2023-07-20 17:11:03 +03:00
}
2023-07-25 20:27:29 +03:00
if (cst.parse?.status !== ParsingStatus.VERIFIED) {
return 'N/A';
2023-07-20 17:11:03 +03:00
}
return 'Логический';
}
export function getCstTypePrefix(type: CstType) {
switch (type) {
case CstType.BASE: return 'X';
case CstType.CONSTANT: return 'C';
case CstType.STRUCTURED: return 'S';
case CstType.AXIOM: return 'A';
case CstType.TERM: return 'D';
case CstType.FUNCTION: return 'F';
case CstType.PREDICATE: return 'P';
case CstType.THEOREM: return 'T';
}
}
export function getCstExpressionPrefix(cst: IConstituenta): string {
return cst.alias + (cst.cstType === CstType.STRUCTURED ? '::=' : ':==');
}
2023-07-20 17:11:03 +03:00
export function getRSButtonData(id: TokenID): IRSButtonData {
2023-07-25 20:27:29 +03:00
switch (id) {
2023-07-20 17:11:03 +03:00
case TokenID.BOOLEAN: return {
text: '()',
2023-07-25 20:27:29 +03:00
tooltip: 'Булеан [Alt + E]'
2023-07-20 17:11:03 +03:00
};
case TokenID.DECART: return {
text: '×',
2023-07-29 03:31:21 +03:00
tooltip: 'Декартово произведение [Shift + 8 / Alt + Shift + E]'
2023-07-20 17:11:03 +03:00
};
case TokenID.PUNC_PL: return {
text: '( )',
2023-07-25 20:27:29 +03:00
tooltip: 'Скобки вокруг выражения [ Alt + Shift + 9 ]'
2023-07-20 17:11:03 +03:00
};
case TokenID.PUNC_SL: return {
text: '[ ]',
2023-07-25 20:27:29 +03:00
tooltip: 'Скобки вокруг выражения [ Alt + [ ]'
2023-07-20 17:11:03 +03:00
};
case TokenID.FORALL: return {
text: '∀',
2023-07-25 20:27:29 +03:00
tooltip: 'Квантор всеобщности [`]'
2023-07-20 17:11:03 +03:00
};
case TokenID.EXISTS: return {
text: '∃',
2023-07-25 20:27:29 +03:00
tooltip: 'Квантор существования [Shift + `]'
2023-07-20 17:11:03 +03:00
};
case TokenID.NOT: return {
text: '¬',
2023-07-25 20:27:29 +03:00
tooltip: 'Отрицание [Alt + `]'
2023-07-20 17:11:03 +03:00
};
case TokenID.AND: return {
text: '&',
2023-07-25 20:27:29 +03:00
tooltip: 'Конъюнкция [Alt + 3 ~ Shift + 7]'
2023-07-20 17:11:03 +03:00
};
case TokenID.OR: return {
text: '',
2023-07-25 20:27:29 +03:00
tooltip: 'дизъюнкция [Alt + Shift + 3]'
2023-07-20 17:11:03 +03:00
};
case TokenID.IMPLICATION: return {
text: '⇒',
2023-07-25 20:27:29 +03:00
tooltip: 'импликация [Alt + 4]'
2023-07-20 17:11:03 +03:00
};
case TokenID.EQUIVALENT: return {
text: '⇔',
2023-07-25 20:27:29 +03:00
tooltip: 'эквивалентность [Alt + Shift + 4]'
2023-07-20 17:11:03 +03:00
};
case TokenID.LIT_EMPTYSET: return {
text: '∅',
2023-07-25 20:27:29 +03:00
tooltip: 'пустое множество [Alt + X]'
2023-07-20 17:11:03 +03:00
};
case TokenID.LIT_INTSET: return {
text: 'Z',
2023-07-25 20:27:29 +03:00
tooltip: 'целые числа [Alt + Z]'
2023-07-20 17:11:03 +03:00
};
case TokenID.EQUAL: return {
text: '=',
2023-07-25 20:27:29 +03:00
tooltip: 'равенство'
2023-07-20 17:11:03 +03:00
};
case TokenID.NOTEQUAL: return {
text: '≠',
2023-07-25 20:27:29 +03:00
tooltip: 'неравенство [Alt + Shift + `]'
2023-07-20 17:11:03 +03:00
};
case TokenID.GREATER_OR_EQ: return {
text: '≥',
2023-07-25 20:27:29 +03:00
tooltip: 'больше или равно'
2023-07-20 17:11:03 +03:00
};
case TokenID.LESSER_OR_EQ: return {
text: '≤',
2023-07-25 20:27:29 +03:00
tooltip: 'меньше или равно'
2023-07-20 17:11:03 +03:00
};
case TokenID.IN: return {
text: '∈',
tooltip: 'быть элементом (принадлежит) [Alt + 1]'
2023-07-20 17:11:03 +03:00
};
case TokenID.NOTIN: return {
text: '∉',
tooltip: 'не принадлежит [Alt + Shift + 1]'
2023-07-20 17:11:03 +03:00
};
case TokenID.SUBSET_OR_EQ: return {
text: '⊆',
2023-07-25 20:27:29 +03:00
tooltip: 'быть частью (нестрогое подмножество) [Alt + 2]'
2023-07-20 17:11:03 +03:00
};
case TokenID.SUBSET: return {
text: '⊂',
2023-07-25 20:27:29 +03:00
tooltip: 'строгое подмножество [Alt + ;]'
2023-07-20 17:11:03 +03:00
};
case TokenID.NOTSUBSET: return {
text: '⊄',
2023-07-25 20:27:29 +03:00
tooltip: 'не подмножество [Alt + Shift + 2]'
2023-07-20 17:11:03 +03:00
};
case TokenID.INTERSECTION: return {
text: '∩',
2023-07-25 20:27:29 +03:00
tooltip: 'пересечение [Alt + Y]'
2023-07-20 17:11:03 +03:00
};
case TokenID.UNION: return {
text: '',
2023-07-25 20:27:29 +03:00
tooltip: 'объединение [Alt + U]'
2023-07-20 17:11:03 +03:00
};
case TokenID.SET_MINUS: return {
2023-07-20 17:11:03 +03:00
text: '\\',
2023-07-25 20:27:29 +03:00
tooltip: 'Разность множеств [Alt + 5]'
2023-07-20 17:11:03 +03:00
};
case TokenID.SYMMINUS: return {
text: '∆',
2023-07-25 20:27:29 +03:00
tooltip: 'Симметрическая разность [Alt + Shift + 5]'
2023-07-20 17:11:03 +03:00
};
case TokenID.NT_DECLARATIVE_EXPR: return {
text: 'D{}',
2023-07-25 20:27:29 +03:00
tooltip: 'Декларативная форма определения терма [Alt + D]'
2023-07-20 17:11:03 +03:00
};
case TokenID.NT_IMPERATIVE_EXPR: return {
text: 'I{}',
2023-07-25 20:27:29 +03:00
tooltip: 'императивная форма определения терма [Alt + G]'
2023-07-20 17:11:03 +03:00
};
case TokenID.NT_RECURSIVE_FULL: return {
text: 'R{}',
2023-07-25 20:27:29 +03:00
tooltip: 'рекурсивная (цикличная) форма определения терма [Alt + T]'
2023-07-20 17:11:03 +03:00
};
case TokenID.BIGPR: return {
text: 'Pr1()',
2023-07-25 20:27:29 +03:00
tooltip: 'большая проекция [Alt + Q]'
2023-07-20 17:11:03 +03:00
};
case TokenID.SMALLPR: return {
text: 'pr1()',
2023-07-25 20:27:29 +03:00
tooltip: 'малая проекция [Alt + W]'
2023-07-20 17:11:03 +03:00
};
case TokenID.FILTER: return {
text: 'Fi1[]()',
2023-07-25 20:27:29 +03:00
tooltip: 'фильтр [Alt + F]'
2023-07-20 17:11:03 +03:00
};
case TokenID.REDUCE: return {
text: 'red()',
2023-07-25 20:27:29 +03:00
tooltip: 'множество-сумма [Alt + R]'
2023-07-20 17:11:03 +03:00
};
case TokenID.CARD: return {
text: 'card()',
2023-07-25 20:27:29 +03:00
tooltip: 'мощность [Alt + C]'
2023-07-20 17:11:03 +03:00
};
case TokenID.BOOL: return {
text: 'bool()',
2023-07-25 20:27:29 +03:00
tooltip: 'синглетон [Alt + B]'
2023-07-20 17:11:03 +03:00
};
case TokenID.DEBOOL: return {
text: 'debool()',
2023-07-25 20:27:29 +03:00
tooltip: 'десинглетон [Alt + V]'
2023-07-20 17:11:03 +03:00
};
case TokenID.PUNC_ASSIGN: return {
text: ':=',
tooltip: 'присвоение (императивный синтаксис) [Alt + Shift + 6]'
2023-07-20 17:11:03 +03:00
};
case TokenID.PUNC_ITERATE: return {
text: ':∈',
tooltip: 'перебор элементов множества (императивный синтаксис) [Alt + 6]'
2023-07-20 17:11:03 +03:00
};
}
return {
text: 'undefined',
2023-07-25 20:27:29 +03:00
tooltip: 'undefined'
2023-07-20 17:11:03 +03:00
}
}
export function getCstTypeLabel(type: CstType) {
2023-07-25 20:27:29 +03:00
switch (type) {
2023-07-20 17:11:03 +03:00
case CstType.BASE: return 'Базисное множество';
case CstType.CONSTANT: return 'Константное множество';
case CstType.STRUCTURED: return 'Родовая структура';
case CstType.AXIOM: return 'Аксиома';
case CstType.TERM: return 'Терм';
case CstType.FUNCTION: return 'Терм-функция';
case CstType.PREDICATE: return 'Предикат-функция';
case CstType.THEOREM: return 'Теорема';
}
}
export function getCstTypeShortcut(type: CstType) {
const prefix = getCstTypeLabel(type) + ' [Alt + ';
switch (type) {
case CstType.BASE: return prefix + '1]';
case CstType.STRUCTURED: return prefix + '2]';
case CstType.TERM: return prefix + '3]';
case CstType.AXIOM: return prefix + '4]';
case CstType.FUNCTION: return prefix + 'Q]';
case CstType.PREDICATE: return prefix + 'W]';
case CstType.CONSTANT: return prefix + '5]';
case CstType.THEOREM: return prefix + '6]';
}
}
export const CstTypeSelector = (Object.values(CstType)).map(
(typeStr) => {
const type = typeStr as CstType;
2023-07-25 20:27:29 +03:00
return { value: type, label: getCstTypeLabel(type) };
2023-07-30 00:47:07 +03:00
});
export const mapLayoutLabels: Map<string, string> = new Map([
['forceatlas2', 'Атлас 2D'],
['forceDirected2d', 'Силы 2D'],
['forceDirected3d', 'Силы 3D'],
['treeTd2d', 'ДеревоВерт 2D'],
['treeTd3d', 'ДеревоВерт 3D'],
['treeLr2d', 'ДеревоГор 2D'],
['treeLr3d', 'ДеревоГор 3D'],
['radialOut2d', 'Радиальная 2D'],
['radialOut3d', 'Радиальная 3D'],
['circular2d', 'Круговая'],
['hierarchicalTd', 'ИерархияВерт'],
['hierarchicalLr', 'ИерархияГор'],
['nooverlap', 'Без перекрытия']
]);
2023-07-30 00:47:07 +03:00
export const GraphLayoutSelector: {value: LayoutTypes, label: string}[] = [
{ value: 'forceatlas2', label: 'Атлас 2D'},
{ value: 'forceDirected2d', label: 'Силы 2D'},
{ value: 'forceDirected3d', label: 'Силы 3D'},
{ value: 'treeTd2d', label: 'ДеревоВ 2D'},
{ value: 'treeTd3d', label: 'ДеревоВ 3D'},
{ value: 'treeLr2d', label: 'ДеревоГ 2D'},
{ value: 'treeLr3d', label: 'ДеревоГ 3D'},
{ value: 'radialOut2d', label: 'Радиальная 2D'},
{ value: 'radialOut3d', label: 'Радиальная 3D'},
// { value: 'circular2d', label: 'circular2d'},
// { value: 'nooverlap', label: 'nooverlap'},
// { value: 'hierarchicalTd', label: 'hierarchicalTd'},
// { value: 'hierarchicalLr', label: 'hierarchicalLr'}
2023-07-30 00:47:07 +03:00
];
export const mapStatusInfo: Map<ExpressionStatus, IStatusInfo> = new Map([
[ ExpressionStatus.VERIFIED, {
text: 'ок',
color: 'bg-[#aaff80] dark:bg-[#2b8000]',
tooltip: 'выражение корректно и вычислимо'
}],
[ ExpressionStatus.INCORRECT, {
2023-07-20 17:11:03 +03:00
text: 'ошибка',
color: 'bg-[#ffc9c9] dark:bg-[#592b2b]',
2023-07-20 17:11:03 +03:00
tooltip: 'ошибка в выражении'
}],
[ ExpressionStatus.INCALCULABLE, {
2023-07-20 17:11:03 +03:00
text: 'невыч',
color: 'bg-[#ffbb80] dark:bg-[#964600]',
tooltip: 'выражение не вычислимо (экспоненциальная сложность)'
}],
[ ExpressionStatus.PROPERTY, {
2023-07-20 17:11:03 +03:00
text: 'св-во',
color: 'bg-[#a5e9fa] dark:bg-[#36899e]',
tooltip: 'можно проверить принадлежность, но нельзя получить значение'
}],
[ ExpressionStatus.UNKNOWN, {
text: 'неизв',
color: 'bg-[#b3bdff] dark:bg-[#1e00b3]',
tooltip: 'требует проверки выражения'
}],
[ ExpressionStatus.UNDEFINED, {
text: 'N/A',
color: 'bg-[#b3bdff] dark:bg-[#1e00b3]',
tooltip: 'произошла ошибка при проверке выражения'
}],
]);
2023-07-20 17:11:03 +03:00
export function createAliasFor(type: CstType, schema: IRSForm): string {
2023-07-25 20:27:29 +03:00
const prefix = getCstTypePrefix(type);
if (!schema.items || schema.items.length <= 0) {
return `${prefix}1`;
}
const index = schema.items.reduce((prev, cst, index) => {
if (cst.cstType !== type) {
return prev;
}
index = Number(cst.alias.slice(1 - cst.alias.length)) + 1;
return Math.max(prev, index);
}, 1);
return `${prefix}${index}`;
2023-07-25 20:27:29 +03:00
}
export function getMockConstituenta(id: number, alias: string, type: CstType, comment: string): IConstituenta {
return {
id: id,
alias: alias,
convention: comment,
cstType: type,
term: {
raw: '',
resolved: '',
forms: []
},
definition: {
formal: '',
text: {
raw: '',
resolved: ''
}
},
status: ExpressionStatus.INCORRECT,
parse: {
status: ParsingStatus.INCORRECT,
valueClass: ValueClass.INVALID,
typification: 'N/A',
syntaxTree: ''
}
};
2023-07-28 01:37:26 +03:00
}
export function getCloneTitle(schema: IRSForm): string {
if (!schema.title.includes('[клон]')) {
return schema.title + ' [клон]';
} else {
return (schema.title + '+');
}
2023-07-29 03:31:21 +03:00
}
export function getRSErrorPrefix(error: IRSErrorDescription): string {
const id = error.errorType.toString(16)
switch(resolveErrorClass(error.errorType)) {
case RSErrorClass.LEXER: return 'L' + id;
case RSErrorClass.PARSER: return 'P' + id;
case RSErrorClass.SEMANTIC: return 'S' + id;
case RSErrorClass.UNKNOWN: return 'U' + id;
}
}
export function getRSErrorMessage(error: IRSErrorDescription): string {
switch (error.errorType) {
case RSErrorType.syntax:
return 'UNKNOWN SYNTAX ERROR';
case RSErrorType.missingParanthesis:
return 'Некорректная конструкция языка родов структур, проверьте структуру выражения';
case RSErrorType.missingCurlyBrace:
return "Пропущен символ '}'";
case RSErrorType.invalidQuantifier:
return 'Некорректная кванторная декларация';
case RSErrorType.expectedArgDeclaration:
return 'Ожидалось объявление аргументов терм-функции';
case RSErrorType.expectedLocal:
return 'Ожидалось имя локальной переменной';
case RSErrorType.localDoubleDeclare:
return `Предупреждение! Повторное объявление локальной переменной ${error.params[0]}`;
case RSErrorType.localNotUsed:
return `Предупреждение! Переменная объявлена, но не использована: ${error.params[0]}`;
2023-07-29 03:31:21 +03:00
case RSErrorType.localShadowing:
return `Повторное объявление переменной: ${error.params[0]}`;
case RSErrorType.typesNotEqual:
return `Типизация операндов не совпадает! ${error.params[0]} != ${error.params[1]}`;
case RSErrorType.globalNotTyped:
return `Типизация конституенты не определена: ${error.params[0]}`;
case RSErrorType.invalidDecart:
return `τ(α×b) = (𝔇τ(α)×𝔇τ(b)). Некорректная типизация аргумента: ${error.params[0]}`;
case RSErrorType.invalidBoolean:
return `τ((a)) = ℬℬ𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`;
case RSErrorType.invalidTypeOperation:
return `Типизация операнда теоретико-множественной операции не корректна: ${error.params[0]}`;
case RSErrorType.invalidCard:
return `Некорректная типизация аргумента операции мощности: ${error.params[0]}`;
case RSErrorType.invalidDebool:
return `τ(debool(a)) = 𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`;
case RSErrorType.globalFuncMissing:
return `Неизвестное имя функции: ${error.params[0]}`;
case RSErrorType.globalFuncWithoutArgs:
return `Некорректное использование имени функции без аргументов: ${error.params[0]}`;
case RSErrorType.invalidReduce:
return `τ(red(a)) = ℬ𝔇𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`;
case RSErrorType.invalidProjectionTuple:
return `Проекция не определена: ${error.params[0]} -> ${error.params[1]}`;
case RSErrorType.invalidProjectionSet:
return `τ(Pri(a)) = 𝒞i𝔇τ(a). Некорректная типизация аргумента: ${error.params[0]}`;
case RSErrorType.invalidEnumeration:
return `Типизация аргументов перечисления не совпадает: ${error.params[0]} != ${error.params[1]}`;
case RSErrorType.ivalidBinding:
return `Количество переменных в кортеже не соответствует размерности декартова произведения`;
case RSErrorType.localOutOfScope:
return `Использование имени переменной вне области действия: ${error.params[0]}`;
case RSErrorType.invalidElementPredicat:
return `Несоответствие типизаций операндов для оператора: ${error.params[0]}${error.params[1]}${error.params[2]}`;
case RSErrorType.invalidArgsArtity:
return `Неверное число аргументов терм-функции: ${error.params[0]} != ${error.params[1]}`;
case RSErrorType.invalidArgumentType:
return `Типизация аргумента терм-функции не соответствует объявленной: ${error.params[0]} != ${error.params[1]}`;
case RSErrorType.invalidEqualsEmpty:
return `Только множества можно сравнивать с пустым множеством: ${error.params[0]}`;
case RSErrorType.globalStructure:
return `Выражение родовой структуры должно быть ступенью`;
case RSErrorType.globalExpectedFunction:
return `Ожидалось выражение объявления функции`;
case RSErrorType.emptySetUsage:
return `Запрещено использование пустого множества как типизированного выражения`;
case RSErrorType.radicalUsage:
return `Радикалы запрещены вне деклараций терм-функци: ${error.params[0]}`;
case RSErrorType.invalidFilterArgumentType:
return `Типизация аргумента фильтра не корректна: ${error.params[0]}(${error.params[1]})`;
case RSErrorType.invalidFilterArity:
return `Количество параметров фильтра не соответствует количеству индексов`;
case RSErrorType.arithmeticNotSupported:
return `Тип не поддерживает арифметические операторы: ${error.params[0]}`;
case RSErrorType.typesNotCompatible:
return `Типы не совместимы для выбранной операции: ${error.params[0]} и ${error.params[1]}`;
case RSErrorType.orderingNotSupported:
return `Тип не поддерживает предикаты порядка: ${error.params[0]}`;
case RSErrorType.globalNoValue:
return `Используется неинтерпретируемый глобальный идентификатор: ${error.params[0]}`;
case RSErrorType.invalidPropertyUsage:
return `Использование неитерируемого множества в качестве значения`;
case RSErrorType.globalMissingAST:
return `Не удалось получить дерево разбора для глобального идентификатора: ${error.params[0]}`;
case RSErrorType.globalFuncNoInterpretation:
return `Функция не интерпретируется для данных аргументов`;
}
return 'UNKNOWN ERROR';
}