Refactor UI labels

This commit is contained in:
IRBorisov 2023-09-21 14:58:01 +03:00
parent b3e866bb00
commit c322e2e8eb
39 changed files with 1227 additions and 947 deletions

View File

@ -34,6 +34,7 @@ This readme file is used mostly to document project dependencies
<pre> <pre>
- tailwindcss postcss autoprefixer - tailwindcss postcss autoprefixer
- eslint-plugin-simple-import-sort - eslint-plugin-simple-import-sort
- eslint-plugin-tsdoc
- jest - jest
- ts-jest - ts-jest
- @types/jest - @types/jest

View File

@ -15,13 +15,16 @@
"project": ["tsconfig.json", "tsconfig.node.json"] "project": ["tsconfig.json", "tsconfig.node.json"]
}, },
"plugins": [ "plugins": [
"react-refresh", "simple-import-sort" "react-refresh",
"simple-import-sort",
"eslint-plugin-tsdoc"
], ],
"rules": { "rules": {
"react-refresh/only-export-components": [ "react-refresh/only-export-components": [
"off", "off",
{ "allowConstantExport": true } { "allowConstantExport": true }
], ],
"simple-import-sort/imports": "warn" "simple-import-sort/imports": "warn",
"tsdoc/syntax": "warn"
} }
} }

View File

@ -40,6 +40,7 @@
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3", "eslint-plugin-react-refresh": "^0.4.3",
"eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-tsdoc": "^0.2.17",
"jest": "^29.6.4", "jest": "^29.6.4",
"postcss": "^8.4.29", "postcss": "^8.4.29",
"tailwindcss": "^3.3.3", "tailwindcss": "^3.3.3",
@ -2228,6 +2229,37 @@
"resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.2.tgz", "resolved": "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.2.tgz",
"integrity": "sha512-d8Q9uRK89ZRWmED2JLI9/blpJcfdbh0iEUuMo8TgkMzNfQBY1/GC0FEJWrairTwHkxIf6Oud1vFBP+aHicWqJA==" "integrity": "sha512-d8Q9uRK89ZRWmED2JLI9/blpJcfdbh0iEUuMo8TgkMzNfQBY1/GC0FEJWrairTwHkxIf6Oud1vFBP+aHicWqJA=="
}, },
"node_modules/@microsoft/tsdoc": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz",
"integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==",
"dev": true
},
"node_modules/@microsoft/tsdoc-config": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz",
"integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==",
"dev": true,
"dependencies": {
"@microsoft/tsdoc": "0.14.2",
"ajv": "~6.12.6",
"jju": "~1.4.0",
"resolve": "~1.19.0"
}
},
"node_modules/@microsoft/tsdoc-config/node_modules/resolve": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
"integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
"dev": true,
"dependencies": {
"is-core-module": "^2.1.0",
"path-parse": "^1.0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -4252,6 +4284,16 @@
"eslint": ">=5.0.0" "eslint": ">=5.0.0"
} }
}, },
"node_modules/eslint-plugin-tsdoc": {
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz",
"integrity": "sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA==",
"dev": true,
"dependencies": {
"@microsoft/tsdoc": "0.14.2",
"@microsoft/tsdoc-config": "0.16.2"
}
},
"node_modules/eslint-scope": { "node_modules/eslint-scope": {
"version": "7.2.2", "version": "7.2.2",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
@ -6837,6 +6879,12 @@
"jiti": "bin/jiti.js" "jiti": "bin/jiti.js"
} }
}, },
"node_modules/jju": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
"integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==",
"dev": true
},
"node_modules/js-file-download": { "node_modules/js-file-download": {
"version": "0.4.12", "version": "0.4.12",
"resolved": "https://registry.npmjs.org/js-file-download/-/js-file-download-0.4.12.tgz", "resolved": "https://registry.npmjs.org/js-file-download/-/js-file-download-0.4.12.tgz",

View File

@ -44,6 +44,7 @@
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3", "eslint-plugin-react-refresh": "^0.4.3",
"eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-tsdoc": "^0.2.17",
"jest": "^29.6.4", "jest": "^29.6.4",
"postcss": "^8.4.29", "postcss": "^8.4.29",
"tailwindcss": "^3.3.3", "tailwindcss": "^3.3.3",

View File

@ -19,14 +19,14 @@ function HelpRSLang() {
return ( return (
<div className='flex flex-col w-full gap-4'> <div className='flex flex-col w-full gap-4'>
<div> <div>
<h1>Язык родов структур</h1> <h1>Родоструктурная экспликация концептуальных схем</h1>
<p>Формальная запись (<i>экспликация</i>) концептуальных схем осуществляется с помощью языка родов структур.</p> <p>Формальная запись (<i>экспликация</i>) концептуальных схем осуществляется с помощью языка родов структур.</p>
<p>Данный математический аппарат основан на аксиоматической теории множеств Цермелло-Френкеля и аппарате родов структур Н.Бурбаки.</p> <p>Данный математический аппарат основан на аксиоматической теории множеств Цермелло-Френкеля и аппарате родов структур Н.Бурбаки.</p>
<p>Для ознакомления с основами родов структур можно использовать следующие материалы:</p> <p>Для ознакомления с основами родов структур можно использовать следующие материалы:</p>
<ul> <ul>
<li>1. <a className='underline' href={urls.intro_video}>Краткое введение в мат. аппарат</a></li> <li>1. <a className='underline' href={urls.intro_video}>Видео: Краткое введение в мат. аппарат</a></li>
<li>2. <a className='underline' href={urls.full_course}>Видео лекций по мат. аппарату для 4 курса (второй семестр 2022-23 год)</a></li> <li>2. <a className='underline' href={urls.ponomarev}>Текст: Учебник И. Н. Пономарева</a></li>
<li>3. <a className='underline' href={urls.ponomarev}>Учебник И. Н. Пономарева</a></li> <li>3. <a className='underline' href={urls.full_course}>Видео: лекции для 4 курса (второй семестр 2022-23 год)</a></li>
</ul> </ul>
</div> </div>
<div className='justify-center hidden w-full md:flex fleex-col'> <div className='justify-center hidden w-full md:flex fleex-col'>

View File

@ -1,5 +1,5 @@
import { IConstituenta } from '../../models/rsform'; import { IConstituenta } from '../../models/rsform';
import { getCstTypificationLabel } from '../../utils/staticUI'; import { labelCstTypification } from '../../utils/labels';
interface InfoConstituentaProps interface InfoConstituentaProps
extends React.HTMLAttributes<HTMLDivElement> { extends React.HTMLAttributes<HTMLDivElement> {
@ -10,7 +10,7 @@ function InfoConstituenta({ data, ...props }: InfoConstituentaProps) {
return ( return (
<div {...props}> <div {...props}>
<h1>Конституента {data.alias}</h1> <h1>Конституента {data.alias}</h1>
<p><b>Типизация: </b>{getCstTypificationLabel(data)}</p> <p><b>Типизация: </b>{labelCstTypification(data)}</p>
<p><b>Термин: </b>{data.term_resolved || data.term_raw}</p> <p><b>Термин: </b>{data.term_resolved || data.term_raw}</p>
{data.definition_formal && <p><b>Выражение: </b>{data.definition_formal}</p>} {data.definition_formal && <p><b>Выражение: </b>{data.definition_formal}</p>}
{data.definition_resolved && <p><b>Определение: </b>{data.definition_resolved}</p>} {data.definition_resolved && <p><b>Определение: </b>{data.definition_resolved}</p>}

View File

@ -1,6 +1,8 @@
import { useConceptTheme } from '../../context/ThemeContext'; import { useConceptTheme } from '../../context/ThemeContext';
import { CstClass } from '../../models/rsform';
import { colorbgCstClass } from '../../utils/color';
import { prefixes } from '../../utils/constants'; import { prefixes } from '../../utils/constants';
import { getCstClassColor, mapCstClassInfo } from '../../utils/staticUI'; import { describeCstClass, labelCstClass } from '../../utils/labels';
interface InfoCstClassProps { interface InfoCstClassProps {
title?: string title?: string
@ -12,19 +14,19 @@ function InfoCstClass({ title }: InfoCstClassProps) {
return ( return (
<div className='flex flex-col gap-1'> <div className='flex flex-col gap-1'>
{ title && <h1>{title}</h1>} { title && <h1>{title}</h1>}
{ [... mapCstClassInfo.entries()].map( { Object.values(CstClass).map(
([cstClass, info], index) => { (cclass, index) => {
return ( return (
<p key={`${prefixes.cst_status_list}${index}`}> <p key={`${prefixes.cst_status_list}${index}`}>
<span <span
className='px-1 inline-block font-semibold min-w-[7rem] text-center border text-sm' className='px-1 inline-block font-semibold min-w-[7rem] text-center border text-sm'
style={{backgroundColor: getCstClassColor(cstClass, colors)}} style={{backgroundColor: colorbgCstClass(cclass, colors)}}
> >
{info.text} {labelCstClass(cclass)}
</span> </span>
<span> - </span> <span> - </span>
<span> <span>
{info.tooltip} {describeCstClass(cclass)}
</span> </span>
</p>); </p>);
})} })}

View File

@ -1,6 +1,8 @@
import { useConceptTheme } from '../../context/ThemeContext'; import { useConceptTheme } from '../../context/ThemeContext';
import { ExpressionStatus } from '../../models/rsform';
import { colorbgCstStatus } from '../../utils/color';
import { prefixes } from '../../utils/constants'; import { prefixes } from '../../utils/constants';
import { getCstStatusBgColor, mapStatusInfo } from '../../utils/staticUI'; import { describeExpressionStatus, labelExpressionStatus } from '../../utils/labels';
interface InfoCstStatusProps { interface InfoCstStatusProps {
title?: string title?: string
@ -12,19 +14,19 @@ function InfoCstStatus({ title }: InfoCstStatusProps) {
return ( return (
<div className='flex flex-col gap-1'> <div className='flex flex-col gap-1'>
{ title && <h1>{title}</h1>} { title && <h1>{title}</h1>}
{ [... mapStatusInfo.entries()].map( { Object.values(ExpressionStatus).map(
([status, info], index) => { (status, index) => {
return ( return (
<p key={`${prefixes.cst_status_list}${index}`}> <p key={`${prefixes.cst_status_list}${index}`}>
<span <span
className='px-1 inline-block font-semibold min-w-[5rem] text-center border text-sm' className='px-1 inline-block font-semibold min-w-[5rem] text-center border text-sm'
style={{backgroundColor: getCstStatusBgColor(status, colors)}} style={{backgroundColor: colorbgCstStatus(status, colors)}}
> >
{info.text} {labelExpressionStatus(status)}
</span> </span>
<span> - </span> <span> - </span>
<span> <span>
{info.tooltip} {describeExpressionStatus(status)}
</span> </span>
</p>); </p>);
})} })}

View File

@ -2,13 +2,13 @@ import { Extension } from '@codemirror/state';
import { hoverTooltip } from '@codemirror/view'; import { hoverTooltip } from '@codemirror/view';
import { IConstituenta } from '../../models/rsform'; import { IConstituenta } from '../../models/rsform';
import { getCstTypificationLabel } from '../../utils/staticUI'; import { labelCstTypification } from '../../utils/labels';
function createTooltipFor(cst: IConstituenta) { function createTooltipFor(cst: IConstituenta) {
const dom = document.createElement('div'); const dom = document.createElement('div');
dom.className = 'overflow-y-auto border shadow-md max-h-[25rem] max-w-[25rem] min-w-[10rem] w-fit z-tooltip text-sm px-2 py-2'; dom.className = 'overflow-y-auto border shadow-md max-h-[25rem] max-w-[25rem] min-w-[10rem] w-fit z-tooltip text-sm px-2 py-2';
const alias = document.createElement('p'); const alias = document.createElement('p');
alias.innerHTML = `<b>${cst.alias}:</b> ${getCstTypificationLabel(cst)}`; alias.innerHTML = `<b>${cst.alias}:</b> ${labelCstTypification(cst)}`;
dom.appendChild(alias); dom.appendChild(alias);
if (cst.term_resolved) { if (cst.term_resolved) {
const term = document.createElement('p'); const term = document.createElement('p');

View File

@ -5,7 +5,7 @@ import { CstType, IConstituenta, type IRSForm } from '../models/rsform';
import { IExpressionParse, IFunctionArg } from '../models/rslang'; import { IExpressionParse, IFunctionArg } from '../models/rslang';
import { RSErrorType } from '../models/rslang'; import { RSErrorType } from '../models/rslang';
import { DataCallback, postCheckExpression } from '../utils/backendAPI'; import { DataCallback, postCheckExpression } from '../utils/backendAPI';
import { getCstExpressionPrefix } from '../utils/staticUI'; import { getCstExpressionPrefix } from '../utils/misc';
const LOGIC_TYPIIFCATION = 'LOGIC'; const LOGIC_TYPIIFCATION = 'LOGIC';

View File

@ -0,0 +1,20 @@
import { Grammeme, parseGrammemes } from './language';
describe('Testing grammeme parsing', () => {
test('empty input',
() => {
expect(parseGrammemes('').length).toBe(0);
expect(parseGrammemes(' ').length).toBe(0);
expect(parseGrammemes(' , ').length).toBe(0);
});
test('regular grammemes',
() => {
expect(parseGrammemes('NOUN')).toStrictEqual([{type: Grammeme.NOUN, data: 'NOUN'}]);
expect(parseGrammemes('sing,nomn')).toStrictEqual([
{type: Grammeme.sing, data: 'sing'},
{type: Grammeme.nomn, data: 'nomn'}
]);
});
});

View File

@ -3,6 +3,9 @@
// ====== Morphology ======== // ====== Morphology ========
export enum Grammeme { export enum Grammeme {
// Неизвестная граммема
UNKN = 'UNKN',
// Части речи // Части речи
NOUN = 'NOUN', NOUN = 'NOUN',
ADJF = 'ADJF', ADJF = 'ADJF',
@ -21,7 +24,6 @@ export enum Grammeme {
CONJ = 'CONJ', CONJ = 'CONJ',
PRCL = 'PRCL', PRCL = 'PRCL',
INTJ = 'INTJ', INTJ = 'INTJ',
PNCT = 'PNCT',
// Одушевленность // Одушевленность
anim = 'anim', anim = 'anim',
@ -88,8 +90,7 @@ export const PartOfSpeech = [
Grammeme.NOUN, Grammeme.ADJF, Grammeme.ADJS, Grammeme.COMP, Grammeme.NOUN, Grammeme.ADJF, Grammeme.ADJS, Grammeme.COMP,
Grammeme.VERB, Grammeme.INFN, Grammeme.PRTF, Grammeme.PRTS, Grammeme.VERB, Grammeme.INFN, Grammeme.PRTF, Grammeme.PRTS,
Grammeme.GRND, Grammeme.ADVB, Grammeme.NPRO, Grammeme.PRED, Grammeme.GRND, Grammeme.ADVB, Grammeme.NPRO, Grammeme.PRED,
Grammeme.PREP, Grammeme.CONJ, Grammeme.PRCL, Grammeme.INTJ, Grammeme.PREP, Grammeme.CONJ, Grammeme.PRCL, Grammeme.INTJ
Grammeme.PNCT
]; ];
export const Gender = [ export const Gender = [
@ -101,6 +102,94 @@ export const Case = [
Grammeme.accs, Grammeme.ablt, Grammeme.loct Grammeme.accs, Grammeme.ablt, Grammeme.loct
]; ];
export const Plurality = [ Grammeme.sing, Grammeme.plur ];
export const Perfectivity = [ Grammeme.perf, Grammeme.impf ];
export const Transitivity = [ Grammeme.tran, Grammeme.intr ];
export const Mood = [ Grammeme.indc, Grammeme.impr ];
export const Inclusion = [ Grammeme.incl, Grammeme.excl ];
export const Voice = [ Grammeme.actv, Grammeme.pssv ];
export const Tense = [
Grammeme.pres,
Grammeme.past,
Grammeme.futr
];
export const Person = [
Grammeme.per1,
Grammeme.per2,
Grammeme.per3
];
export const GrammemeGroups = [
PartOfSpeech, Gender, Case, Plurality, Perfectivity,
Transitivity, Mood, Inclusion, Voice, Tense, Person
];
export const NounGrams = [
Grammeme.NOUN, Grammeme.ADJF, Grammeme.ADJS,
...Gender,
...Case,
...Plurality
];
export const VerbGrams = [
Grammeme.VERB, Grammeme.INFN, Grammeme.PRTF, Grammeme.PRTS,
...Perfectivity,
...Transitivity,
...Mood,
...Inclusion,
...Voice,
...Tense,
...Person
];
// Grammeme parse data
export interface IGramData {
type: Grammeme
data: string
}
// Equality comparator for IGramData
export function matchGrammeme(value: IGramData, test: IGramData): boolean {
if (value.type !== test.type) {
return false;
}
return value.type !== Grammeme.UNKN || value.data === test.data;
}
function parseSingleGrammeme(text: string): IGramData {
if (Object.values(Grammeme).includes(text as Grammeme)) {
return {
data: text,
type: text as Grammeme
}
} else {
return {
data: text,
type: Grammeme.UNKN
}
}
}
export function parseGrammemes(termForm: string): IGramData[] {
const result: IGramData[] = [];
const chunks = termForm.split(',');
chunks.forEach(chunk => {
chunk = chunk.trim();
if (chunk !== '') {
result.push(parseSingleGrammeme(chunk));
}
});
return result;
}
export interface IWordForm {
text: string
grams: IGramData[]
}
// ====== Reference resolution ===== // ====== Reference resolution =====
export interface IRefsText { export interface IRefsText {
text: string text: string
@ -110,6 +199,7 @@ export enum ReferenceType {
ENTITY = 'entity', ENTITY = 'entity',
SYNTACTIC = 'syntax' SYNTACTIC = 'syntax'
} }
export interface IEntityReference { export interface IEntityReference {
entity: string entity: string
form: string form: string

View File

@ -274,3 +274,30 @@ export function inferClass(type: CstType, isTemplate: boolean): CstClass {
} }
} }
export function createMockConstituenta(schema: number, id: number, alias: string, type: CstType, comment: string): IConstituenta {
return {
id: id,
order: -1,
schema: schema,
alias: alias,
convention: comment,
cst_type: type,
term_raw: '',
term_resolved: '',
term_forms: [],
definition_formal: '',
definition_raw: '',
definition_resolved: '',
status: ExpressionStatus.INCORRECT,
is_template: false,
cst_class: CstClass.DERIVED,
parse: {
status: ParsingStatus.INCORRECT,
valueClass: ValueClass.INVALID,
typification: 'N/A',
syntaxTree: '',
args: []
}
};
}

View File

@ -1,6 +1,6 @@
import { HelpTopic } from '../../models/miscelanious'; import { HelpTopic } from '../../models/miscelanious';
import { prefixes } from '../../utils/constants'; import { prefixes } from '../../utils/constants';
import { mapTopicInfo } from '../../utils/staticUI'; import { describeHelpTopic, labelHelpTopic } from '../../utils/labels';
interface TopicsListProps { interface TopicsListProps {
activeTopic: HelpTopic activeTopic: HelpTopic
@ -11,15 +11,15 @@ function TopicsList({ activeTopic, onChangeTopic }: TopicsListProps) {
return ( return (
<div className='sticky top-0 left-0 border-r border-b min-w-[13rem] pt-2 select-none flex flex-col clr-controls'> <div className='sticky top-0 left-0 border-r border-b min-w-[13rem] pt-2 select-none flex flex-col clr-controls'>
<div className='mb-2 font-semibold text-center'>Справка</div> <div className='mb-2 font-semibold text-center'>Справка</div>
{ [... mapTopicInfo.entries()].map( { Object.values(HelpTopic).map(
([topic, info], index) => { (topic, index) => {
return ( return (
<div key={`${prefixes.topic_list}${index}`} <div key={`${prefixes.topic_list}${index}`}
className={`px-3 py-1 border-y cursor-pointer clr-hover ${activeTopic === topic ? 'font-semibold clr-selected ' : ''}`} className={`px-3 py-1 border-y cursor-pointer clr-hover ${activeTopic === topic ? 'font-semibold clr-selected ' : ''}`}
title={info.tooltip} title={describeHelpTopic(topic)}
onClick={() => onChangeTopic(topic)} onClick={() => onChangeTopic(topic)}
> >
{info.text} {labelHelpTopic(topic)}
</div>) </div>)
})} })}
</div> </div>

View File

@ -9,7 +9,7 @@ import { useLibrary } from '../../context/LibraryContext';
import { useConceptNavigation } from '../../context/NagivationContext'; import { useConceptNavigation } from '../../context/NagivationContext';
import { useRSForm } from '../../context/RSFormContext'; import { useRSForm } from '../../context/RSFormContext';
import { IRSFormCreateData } from '../../models/rsform'; import { IRSFormCreateData } from '../../models/rsform';
import { getCloneTitle } from '../../utils/staticUI'; import { cloneTitle } from '../../utils/misc';
interface DlgCloneRSFormProps interface DlgCloneRSFormProps
extends Pick<ModalProps, 'hideWindow'> {} extends Pick<ModalProps, 'hideWindow'> {}
@ -27,7 +27,7 @@ function DlgCloneRSForm({ hideWindow }: DlgCloneRSFormProps) {
useEffect(() => { useEffect(() => {
if (schema) { if (schema) {
setTitle(getCloneTitle(schema)); setTitle(cloneTitle(schema));
setAlias(schema.alias); setAlias(schema.alias);
setComment(schema.comment); setComment(schema.comment);
setCommon(schema.is_common); setCommon(schema.is_common);

View File

@ -6,7 +6,7 @@ import TextArea from '../../components/Common/TextArea';
import RSInput from '../../components/RSInput'; import RSInput from '../../components/RSInput';
import { CstType,ICstCreateData } from '../../models/rsform'; import { CstType,ICstCreateData } from '../../models/rsform';
import { SelectorCstType } from '../../utils/selectors'; import { SelectorCstType } from '../../utils/selectors';
import { getCstTypeLabel } from '../../utils/staticUI'; import { labelCstType } from '../../utils/labels';
interface DlgCreateCstProps interface DlgCreateCstProps
extends Pick<ModalProps, 'hideWindow'> { extends Pick<ModalProps, 'hideWindow'> {
@ -62,7 +62,7 @@ function DlgCreateCst({ hideWindow, initial, onCreate }: DlgCreateCstProps) {
className='my-2 min-w-[15rem] self-center' className='my-2 min-w-[15rem] self-center'
options={SelectorCstType} options={SelectorCstType}
placeholder='Выберите тип' placeholder='Выберите тип'
value={selectedType ? { value: selectedType, label: getCstTypeLabel(selectedType) } : null} value={selectedType ? { value: selectedType, label: labelCstType(selectedType) } : null}
onChange={data => setSelectedType(data?.value ?? CstType.BASE)} onChange={data => setSelectedType(data?.value ?? CstType.BASE)}
/> />
</div> </div>

View File

@ -3,7 +3,7 @@ import { useMemo, useState } from 'react';
import Checkbox from '../../components/Common/Checkbox'; import Checkbox from '../../components/Common/Checkbox';
import Modal, { ModalProps } from '../../components/Common/Modal'; import Modal, { ModalProps } from '../../components/Common/Modal';
import { useRSForm } from '../../context/RSFormContext'; import { useRSForm } from '../../context/RSFormContext';
import { getCstLabel } from '../../utils/staticUI'; import { labelConstituenta } from '../../utils/labels';
interface DlgDeleteCstProps interface DlgDeleteCstProps
extends Pick<ModalProps, 'hideWindow'> { extends Pick<ModalProps, 'hideWindow'> {
@ -39,14 +39,14 @@ function DlgDeleteCst({ hideWindow, selected, onDelete }: DlgDeleteCstProps) {
<div className='px-3 border h-[9rem] mt-1 overflow-y-auto whitespace-nowrap'> <div className='px-3 border h-[9rem] mt-1 overflow-y-auto whitespace-nowrap'>
{selected.map(id => { {selected.map(id => {
const cst = schema!.items.find(cst => cst.id === id); const cst = schema!.items.find(cst => cst.id === id);
return (cst && <p>{getCstLabel(cst)}</p>); return (cst && <p>{labelConstituenta(cst)}</p>);
})} })}
</div> </div>
<p className='mt-4'>Зависимые конституенты: <b>{expansion.length}</b></p> <p className='mt-4'>Зависимые конституенты: <b>{expansion.length}</b></p>
<div className='mt-1 mb-3 px-3 border h-[9rem] overflow-y-auto whitespace-nowrap'> <div className='mt-1 mb-3 px-3 border h-[9rem] overflow-y-auto whitespace-nowrap'>
{expansion.map(id => { {expansion.map(id => {
const cst = schema!.items.find(cst => cst.id === id); const cst = schema!.items.find(cst => cst.id === id);
return (cst && <p>{getCstLabel(cst)}</p>); return (cst && <p>{labelConstituenta(cst)}</p>);
})} })}
</div> </div>
<Checkbox <Checkbox

View File

@ -1,39 +1,100 @@
import { useLayoutEffect, useState } from 'react'; import { useEffect, useLayoutEffect, useMemo, useState } from 'react';
import Divider from '../../components/Common/Divider'; import Divider from '../../components/Common/Divider';
import MiniButton from '../../components/Common/MiniButton'; import MiniButton from '../../components/Common/MiniButton';
import Modal from '../../components/Common/Modal'; import Modal from '../../components/Common/Modal';
import SelectMulti from '../../components/Common/SelectMulti'; import SelectMulti from '../../components/Common/SelectMulti';
import TextArea from '../../components/Common/TextArea'; import TextArea from '../../components/Common/TextArea';
import DataTable, { createColumnHelper } from '../../components/DataTable';
import { CheckIcon, ChevronDoubleUpIcon, ChevronUpIcon, CrossIcon } from '../../components/Icons'; import { CheckIcon, ChevronDoubleUpIcon, ChevronUpIcon, CrossIcon } from '../../components/Icons';
import { Grammeme } from '../../models/language'; import { Grammeme, GrammemeGroups, IWordForm, NounGrams, parseGrammemes,VerbGrams } from '../../models/language';
import { IConstituenta } from '../../models/rsform'; import { IConstituenta, TermForm } from '../../models/rsform';
import { SelectorGrammems } from '../../utils/selectors'; import { labelGrammeme } from '../../utils/labels';
import { IGrammemeOption, SelectorGrammems } from '../../utils/selectors';
interface DlgEditTermProps { interface DlgEditTermProps {
hideWindow: () => void hideWindow: () => void
target: IConstituenta target: IConstituenta
onSave: () => void onSave: (data: TermForm[]) => void
} }
const columnHelper = createColumnHelper<IWordForm>();
function DlgEditTerm({ hideWindow, target, onSave }: DlgEditTermProps) { function DlgEditTerm({ hideWindow, target, onSave }: DlgEditTermProps) {
const [term, setTerm] = useState(''); const [term, setTerm] = useState('');
const [inputText, setInputText] = useState(''); const [inputText, setInputText] = useState('');
const [inputTags, setInputTags] = useState<{ value: Grammeme, label: string }[]>([]); const [inputGrams, setInputGrams] = useState<IGrammemeOption[]>([]);
const [options, setOptions] = useState<IGrammemeOption[]>([]);
const [forms, setForms] = useState<IWordForm[]>([]);
function getData(): TermForm[] {
// function getData() { const result: TermForm[] = [];
// return { forms.forEach(
({text, grams}) => result.push({
text: text,
tags: grams.join(',')
}));
return result;
}
// }; // Initialization
// } useLayoutEffect(
() => {
const initForms: IWordForm[] = [];
target.term_forms.forEach(
term => initForms.push({
text: term.text,
grams: parseGrammemes(term.tags),
}));
setForms(initForms);
setTerm(target.term_resolved);
}, [target]);
const handleSubmit = () => onSave(); // getData() // Filter grammemes when input changes
useEffect(
() => {
let newFilter: Grammeme[] = [];
inputGrams.forEach(({value: gram}) => {
if (!newFilter.includes(gram)) {
if (NounGrams.includes(gram)) {
newFilter.push(...NounGrams);
}
if (VerbGrams.includes(gram)) {
newFilter.push(...NounGrams);
}
}
});
inputGrams.forEach(({value: gram}) =>
GrammemeGroups.forEach(group => {
if (group.includes(gram)) {
newFilter = newFilter.filter(item => !group.includes(item) || item === gram);
}
}));
newFilter.push(...inputGrams.map(({value: gram}) => gram));
if (newFilter.length === 0) {
newFilter = [...VerbGrams, ...NounGrams];
}
newFilter = [... new Set(newFilter)];
setOptions(SelectorGrammems.filter(({value: gram}) => newFilter.includes(gram)));
}, [inputGrams]);
const handleSubmit = () => onSave(getData());
function handleAddForm() { function handleAddForm() {
setForms(forms => [
...forms,
{
text: inputText,
grams: inputGrams.map(item => ({
type: item.value, data: item.value as string
}))
}
]);
} }
function handleResetForm() { function handleResetForm() {
@ -48,10 +109,56 @@ function DlgEditTerm({ hideWindow, target, onSave }: DlgEditTermProps) {
} }
useLayoutEffect( const columns = useMemo(
() => { () => [
setTerm(target.term_resolved); columnHelper.accessor('text', {
}, [target]); id: 'text',
header: 'Текст',
size: 350,
minSize: 350,
maxSize: 350
}),
columnHelper.accessor('grams', {
id: 'grams',
header: 'Граммемы',
size: 250,
minSize: 250,
maxSize: 250,
cell: props => {
return (
<div className='flex justify-start gap-1 select-none'>
{ props.getValue().map(
data => (<>
<div
className='min-w-[3rem] px-1 text-center rounded-md whitespace-nowrap border clr-border clr-input'
title=''
// style={{
// borderWidth: '1px',
// borderColor: getCstStatusFgColor(cst.status, colors),
// color: getCstStatusFgColor(cst.status, colors),
// fontWeight: 600,
// backgroundColor: isMockCst(cst) ? colors.bgWarning : colors.bgInput
// }}
>
{labelGrammeme(data)}
</div>
{/* <ConstituentaTooltip data={cst} anchor={`#${prefixes.cst_list}${cst.alias}`} /> */}
</>))}
</div>);
}
// cell: props =>
// <div style={{
// fontSize: 12,
// color: isMockCst(props.row.original) ? colors.fgWarning : undefined
// }}>
// {props.getValue()}
// </div>
}),
// columnHelper.accessor(, {
// })
], []);
return ( return (
<Modal <Modal
@ -108,15 +215,29 @@ function DlgEditTerm({ hideWindow, target, onSave }: DlgEditTermProps) {
</div> </div>
<SelectMulti <SelectMulti
className='z-modal-top min-w-[20rem] max-w-[20rem] h-full flex-grow' className='z-modal-top min-w-[20rem] max-w-[20rem] h-full flex-grow'
options={SelectorGrammems} options={options}
placeholder='Выберите граммемы' placeholder='Выберите граммемы'
value={inputTags} value={inputGrams}
onChange={data => setInputTags(data.map(value => value))} onChange={data => setInputGrams(data.map(value => value))}
/> />
</div> </div>
<div>
Таблица <div className='border overflow-y-auto max-h-[20rem]'>
<DataTable
data={forms}
columns={columns}
dense
noDataComponent={
<span className='flex flex-col justify-center p-2 text-center min-h-[2rem]'>
<p>Список пуст</p>
</span>
}
// onRowDoubleClicked={handleDoubleClick}
// onRowClicked={handleRowClicked}
/>
</div> </div>
</div> </div>
</Modal>); </Modal>);

View File

@ -3,7 +3,7 @@ import { useLayoutEffect, useState } from 'react';
import Checkbox from '../../components/Common/Checkbox'; import Checkbox from '../../components/Common/Checkbox';
import Modal, { ModalProps } from '../../components/Common/Modal'; import Modal, { ModalProps } from '../../components/Common/Modal';
import { CstType } from '../../models/rsform'; import { CstType } from '../../models/rsform';
import { getCstTypeLabel } from '../../utils/staticUI'; import { labelCstType } from '../../utils/labels';
import { GraphEditorParams } from './EditorTermGraph'; import { GraphEditorParams } from './EditorTermGraph';
interface DlgGraphOptionsProps interface DlgGraphOptionsProps
@ -105,42 +105,42 @@ function DlgGraphOptions({ hideWindow, initial, onConfirm }:DlgGraphOptionsProps
<div className='flex flex-col gap-1'> <div className='flex flex-col gap-1'>
<h1>Типы конституент</h1> <h1>Типы конституент</h1>
<Checkbox <Checkbox
label={getCstTypeLabel(CstType.BASE)} label={labelCstType(CstType.BASE)}
value={allowBase} value={allowBase}
setValue={ value => setAllowBase(value) } setValue={ value => setAllowBase(value) }
/> />
<Checkbox <Checkbox
label={getCstTypeLabel(CstType.STRUCTURED)} label={labelCstType(CstType.STRUCTURED)}
value={allowStruct} value={allowStruct}
setValue={ value => setAllowStruct(value) } setValue={ value => setAllowStruct(value) }
/> />
<Checkbox <Checkbox
label={getCstTypeLabel(CstType.TERM)} label={labelCstType(CstType.TERM)}
value={allowTerm} value={allowTerm}
setValue={ value => setAllowTerm(value) } setValue={ value => setAllowTerm(value) }
/> />
<Checkbox <Checkbox
label={getCstTypeLabel(CstType.AXIOM)} label={labelCstType(CstType.AXIOM)}
value={allowAxiom} value={allowAxiom}
setValue={ value => setAllowAxiom(value) } setValue={ value => setAllowAxiom(value) }
/> />
<Checkbox <Checkbox
label={getCstTypeLabel(CstType.FUNCTION)} label={labelCstType(CstType.FUNCTION)}
value={allowFunction} value={allowFunction}
setValue={ value => setAllowFunction(value) } setValue={ value => setAllowFunction(value) }
/> />
<Checkbox <Checkbox
label={getCstTypeLabel(CstType.PREDICATE)} label={labelCstType(CstType.PREDICATE)}
value={allowPredicate} value={allowPredicate}
setValue={ value => setAllowPredicate(value) } setValue={ value => setAllowPredicate(value) }
/> />
<Checkbox <Checkbox
label={getCstTypeLabel(CstType.CONSTANT)} label={labelCstType(CstType.CONSTANT)}
value={allowConstant} value={allowConstant}
setValue={ value => setAllowConstant(value) } setValue={ value => setAllowConstant(value) }
/> />
<Checkbox <Checkbox
label={getCstTypeLabel(CstType.THEOREM)} label={labelCstType(CstType.THEOREM)}
value={allowTheorem} value={allowTheorem}
setValue ={ value => setAllowTheorem(value) } setValue ={ value => setAllowTheorem(value) }
/> />

View File

@ -6,7 +6,8 @@ import TextInput from '../../components/Common/TextInput';
import { useRSForm } from '../../context/RSFormContext'; import { useRSForm } from '../../context/RSFormContext';
import { CstType, ICstRenameData } from '../../models/rsform'; import { CstType, ICstRenameData } from '../../models/rsform';
import { SelectorCstType } from '../../utils/selectors'; import { SelectorCstType } from '../../utils/selectors';
import { createAliasFor, getCstTypeLabel, getCstTypePrefix } from '../../utils/staticUI'; import { createAliasFor, getCstTypePrefix } from '../../utils/misc';
import { labelCstType } from '../../utils/labels';
interface DlgRenameCstProps interface DlgRenameCstProps
extends Pick<ModalProps, 'hideWindow'> { extends Pick<ModalProps, 'hideWindow'> {
@ -72,7 +73,7 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
className='min-w-[14rem] self-center z-modal-top' className='min-w-[14rem] self-center z-modal-top'
options={SelectorCstType} options={SelectorCstType}
placeholder='Выберите тип' placeholder='Выберите тип'
value={cstType ? { value: cstType, label: getCstTypeLabel(cstType) } : null} value={cstType ? { value: cstType, label: labelCstType(cstType) } : null}
onChange={data => setCstType(data?.value ?? CstType.BASE)} onChange={data => setCstType(data?.value ?? CstType.BASE)}
/> />
<div> <div>

View File

@ -5,8 +5,9 @@ import Modal, { ModalProps } from '../../components/Common/Modal';
import { useConceptTheme } from '../../context/ThemeContext'; import { useConceptTheme } from '../../context/ThemeContext';
import { SyntaxTree } from '../../models/rslang'; import { SyntaxTree } from '../../models/rslang';
import { graphDarkT, graphLightT } from '../../utils/color'; import { graphDarkT, graphLightT } from '../../utils/color';
import { colorbgSyntaxTree } from '../../utils/color';
import { resources } from '../../utils/constants'; import { resources } from '../../utils/constants';
import { getASTNodeColor, getASTNodeLabel } from '../../utils/staticUI'; import { labelSyntaxTree } from '../../utils/labels';
interface DlgShowASTProps interface DlgShowASTProps
extends Pick<ModalProps, 'hideWindow'> { extends Pick<ModalProps, 'hideWindow'> {
@ -24,8 +25,8 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
const nodes: GraphNode[] = useMemo( const nodes: GraphNode[] = useMemo(
() => syntaxTree.map(node => ({ () => syntaxTree.map(node => ({
id: String(node.uid), id: String(node.uid),
label: getASTNodeLabel(node), label: labelSyntaxTree(node),
fill: getASTNodeColor(node, colors), fill: colorbgSyntaxTree(node, colors),
})), [syntaxTree, colors]); })), [syntaxTree, colors]);
const edges: GraphEdge[] = useMemo( const edges: GraphEdge[] = useMemo(

View File

@ -13,7 +13,7 @@ import useWindowSize from '../../hooks/useWindowSize';
import { EditMode } from '../../models/miscelanious'; import { EditMode } from '../../models/miscelanious';
import { CstType, IConstituenta, ICstCreateData, ICstRenameData, ICstUpdateData } from '../../models/rsform'; import { CstType, IConstituenta, ICstCreateData, ICstRenameData, ICstUpdateData } from '../../models/rsform';
import { SyntaxTree } from '../../models/rslang'; import { SyntaxTree } from '../../models/rslang';
import { getCstTypificationLabel } from '../../utils/staticUI'; import { labelCstTypification } from '../../utils/labels';
import EditorRSExpression from './EditorRSExpression'; import EditorRSExpression from './EditorRSExpression';
import ViewSideConstituents from './elements/ViewSideConstituents'; import ViewSideConstituents from './elements/ViewSideConstituents';
@ -78,7 +78,7 @@ function EditorConstituenta({
setTerm(activeCst.term_raw || ''); setTerm(activeCst.term_raw || '');
setTextDefinition(activeCst.definition_raw || ''); setTextDefinition(activeCst.definition_raw || '');
setExpression(activeCst.definition_formal || ''); setExpression(activeCst.definition_formal || '');
setTypification(activeCst ? getCstTypificationLabel(activeCst) : 'N/A'); setTypification(activeCst ? labelCstTypification(activeCst) : 'N/A');
} }
}, [activeCst, onOpenEdit, schema]); }, [activeCst, onOpenEdit, schema]);

View File

@ -11,8 +11,10 @@ import { useRSForm } from '../../context/RSFormContext';
import { useConceptTheme } from '../../context/ThemeContext'; import { useConceptTheme } from '../../context/ThemeContext';
import useWindowSize from '../../hooks/useWindowSize'; import useWindowSize from '../../hooks/useWindowSize';
import { CstType, IConstituenta, ICstCreateData, ICstMovetoData } from '../../models/rsform' import { CstType, IConstituenta, ICstCreateData, ICstMovetoData } from '../../models/rsform'
import { colorfgCstStatus } from '../../utils/color';
import { prefixes } from '../../utils/constants'; import { prefixes } from '../../utils/constants';
import { getCstStatusFgColor, getCstTypePrefix, getCstTypeShortcut, getCstTypificationLabel, mapStatusInfo } from '../../utils/staticUI'; import { describeExpressionStatus, labelCstTypification } from '../../utils/labels';
import { getCstTypePrefix, getCstTypeShortcut } from '../../utils/misc';
// Window width cutoff for columns // Window width cutoff for columns
const COLUMN_DEFINITION_HIDE_THRESHOLD = 1000; const COLUMN_DEFINITION_HIDE_THRESHOLD = 1000;
@ -221,15 +223,14 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
maxSize: 65, maxSize: 65,
cell: props => { cell: props => {
const cst = props.row.original; const cst = props.row.original;
const info = mapStatusInfo.get(cst.status);
return (<> return (<>
<div <div
id={`${prefixes.cst_list}${cst.alias}`} id={`${prefixes.cst_list}${cst.alias}`}
className='w-full min-w-[3.1rem] max-w-[3.1rem] px-1 text-center rounded-md whitespace-nowrap' className='w-full min-w-[3.1rem] max-w-[3.1rem] px-1 text-center rounded-md whitespace-nowrap'
style={{ style={{
borderWidth: "1px", borderWidth: "1px",
borderColor: getCstStatusFgColor(cst.status, colors), borderColor: colorfgCstStatus(cst.status, colors),
color: getCstStatusFgColor(cst.status, colors), color: colorfgCstStatus(cst.status, colors),
fontWeight: 600, fontWeight: 600,
backgroundColor: colors.bgInput backgroundColor: colors.bgInput
}} }}
@ -240,12 +241,12 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
anchorSelect={`#${prefixes.cst_list}${cst.alias}`} anchorSelect={`#${prefixes.cst_list}${cst.alias}`}
place='right' place='right'
> >
<p><span className='font-semibold'>Статус</span>: {info!.tooltip}</p> <p><span className='font-semibold'>Статус</span>: {describeExpressionStatus(cst.status)}</p>
</ConceptTooltip> </ConceptTooltip>
</>); </>);
} }
}), }),
columnHelper.accessor(cst => getCstTypificationLabel(cst), { columnHelper.accessor(cst => labelCstTypification(cst), {
id: 'type', id: 'type',
header: 'Типизация', header: 'Типизация',
size: 150, size: 150,

View File

@ -10,7 +10,8 @@ import useCheckExpression from '../../hooks/useCheckExpression';
import { IConstituenta } from '../../models/rsform'; import { IConstituenta } from '../../models/rsform';
import { IRSErrorDescription, SyntaxTree } from '../../models/rslang'; import { IRSErrorDescription, SyntaxTree } from '../../models/rslang';
import { TokenID } from '../../models/rslang'; import { TokenID } from '../../models/rslang';
import { getCstExpressionPrefix, getTypificationLabel } from '../../utils/staticUI'; import { labelTypification } from '../../utils/labels';
import { getCstExpressionPrefix } from '../../utils/misc';
import ParsingResult from './elements/ParsingResult'; import ParsingResult from './elements/ParsingResult';
import RSLocalButton from './elements/RSLocalButton'; import RSLocalButton from './elements/RSLocalButton';
import RSTokenButton from './elements/RSTokenButton'; import RSTokenButton from './elements/RSTokenButton';
@ -67,7 +68,7 @@ function EditorRSExpression({
rsInput.current?.view?.focus(); rsInput.current?.view?.focus();
} }
setIsModified(false); setIsModified(false);
setTypification(getTypificationLabel({ setTypification(labelTypification({
isValid: parse.parseResult, isValid: parse.parseResult,
resultType: parse.typification, resultType: parse.typification,
args: parse.args args: parse.args
@ -111,49 +112,49 @@ function EditorRSExpression({
<div className='flex items-center justify-between w-full'> <div className='flex items-center justify-between w-full'>
<div className='text-sm w-fit'> <div className='text-sm w-fit'>
<div className='flex justify-start'> <div className='flex justify-start'>
<RSTokenButton id={TokenID.NT_DECLARATIVE_EXPR} onInsert={handleEdit}/> <RSTokenButton token={TokenID.NT_DECLARATIVE_EXPR} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.NT_IMPERATIVE_EXPR} onInsert={handleEdit}/> <RSTokenButton token={TokenID.NT_IMPERATIVE_EXPR} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.NT_RECURSIVE_FULL} onInsert={handleEdit}/> <RSTokenButton token={TokenID.NT_RECURSIVE_FULL} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.BIGPR} onInsert={handleEdit}/> <RSTokenButton token={TokenID.BIGPR} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.SMALLPR} onInsert={handleEdit}/> <RSTokenButton token={TokenID.SMALLPR} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.FILTER} onInsert={handleEdit}/> <RSTokenButton token={TokenID.FILTER} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.REDUCE} onInsert={handleEdit}/> <RSTokenButton token={TokenID.REDUCE} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.CARD} onInsert={handleEdit}/> <RSTokenButton token={TokenID.CARD} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.BOOL} onInsert={handleEdit}/> <RSTokenButton token={TokenID.BOOL} onInsert={handleEdit}/>
</div> </div>
<div className='flex justify-start'> <div className='flex justify-start'>
<RSTokenButton id={TokenID.BOOLEAN} onInsert={handleEdit}/> <RSTokenButton token={TokenID.BOOLEAN} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.PUNC_PL} onInsert={handleEdit}/> <RSTokenButton token={TokenID.PUNC_PL} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.INTERSECTION} onInsert={handleEdit}/> <RSTokenButton token={TokenID.INTERSECTION} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.LIT_EMPTYSET} onInsert={handleEdit}/> <RSTokenButton token={TokenID.LIT_EMPTYSET} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.FORALL} onInsert={handleEdit}/> <RSTokenButton token={TokenID.FORALL} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.NOT} onInsert={handleEdit}/> <RSTokenButton token={TokenID.NOT} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.IN} onInsert={handleEdit}/> <RSTokenButton token={TokenID.IN} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.SUBSET_OR_EQ} onInsert={handleEdit}/> <RSTokenButton token={TokenID.SUBSET_OR_EQ} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.AND} onInsert={handleEdit}/> <RSTokenButton token={TokenID.AND} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.IMPLICATION} onInsert={handleEdit}/> <RSTokenButton token={TokenID.IMPLICATION} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.SET_MINUS} onInsert={handleEdit}/> <RSTokenButton token={TokenID.SET_MINUS} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.PUNC_ITERATE} onInsert={handleEdit}/> <RSTokenButton token={TokenID.PUNC_ITERATE} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.SUBSET} onInsert={handleEdit}/> <RSTokenButton token={TokenID.SUBSET} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.DEBOOL} onInsert={handleEdit}/> <RSTokenButton token={TokenID.DEBOOL} onInsert={handleEdit}/>
</div> </div>
<div className='flex justify-start'> <div className='flex justify-start'>
<RSTokenButton id={TokenID.DECART} onInsert={handleEdit}/> <RSTokenButton token={TokenID.DECART} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.PUNC_SL} onInsert={handleEdit}/> <RSTokenButton token={TokenID.PUNC_SL} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.UNION} onInsert={handleEdit}/> <RSTokenButton token={TokenID.UNION} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.LIT_INTSET} onInsert={handleEdit}/> <RSTokenButton token={TokenID.LIT_INTSET} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.EXISTS} onInsert={handleEdit}/> <RSTokenButton token={TokenID.EXISTS} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.NOTEQUAL} onInsert={handleEdit}/> <RSTokenButton token={TokenID.NOTEQUAL} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.NOTIN} onInsert={handleEdit}/> <RSTokenButton token={TokenID.NOTIN} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.NOTSUBSET} onInsert={handleEdit}/> <RSTokenButton token={TokenID.NOTSUBSET} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.OR} onInsert={handleEdit}/> <RSTokenButton token={TokenID.OR} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.EQUIVALENT} onInsert={handleEdit}/> <RSTokenButton token={TokenID.EQUIVALENT} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.SYMMINUS} onInsert={handleEdit}/> <RSTokenButton token={TokenID.SYMMINUS} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.PUNC_ASSIGN} onInsert={handleEdit}/> <RSTokenButton token={TokenID.PUNC_ASSIGN} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.EQUAL} onInsert={handleEdit}/> <RSTokenButton token={TokenID.EQUAL} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.GREATER_OR_EQ} onInsert={handleEdit}/> <RSTokenButton token={TokenID.GREATER_OR_EQ} onInsert={handleEdit}/>
<RSTokenButton id={TokenID.LESSER_OR_EQ} onInsert={handleEdit}/> <RSTokenButton token={TokenID.LESSER_OR_EQ} onInsert={handleEdit}/>
</div> </div>
</div> </div>
<div className='text-xs w-fit'> <div className='text-xs w-fit'>

View File

@ -21,9 +21,10 @@ import { prefixes, resources, TIMEOUT_GRAPH_REFRESH } from '../../utils/constant
import { Graph } from '../../utils/Graph'; import { Graph } from '../../utils/Graph';
import { SelectorGraphLayout } from '../../utils/selectors'; import { SelectorGraphLayout } from '../../utils/selectors';
import { SelectorGraphColoring } from '../../utils/selectors'; import { SelectorGraphColoring } from '../../utils/selectors';
import { getCstClassColor, getCstStatusBgColor, import { colorbgCstClass } from '../../utils/color';
mapColoringLabels, mapLayoutLabels import { colorbgCstStatus } from '../../utils/color';
} from '../../utils/staticUI'; import { mapLabelColoring } from '../../utils/labels';
import { mapLableLayout } from '../../utils/labels';
import DlgGraphOptions from './DlgGraphOptions'; import DlgGraphOptions from './DlgGraphOptions';
import ConstituentaTooltip from './elements/ConstituentaTooltip'; import ConstituentaTooltip from './elements/ConstituentaTooltip';
@ -32,10 +33,10 @@ const TREE_SIZE_MILESTONE = 50;
function getCstNodeColor(cst: IConstituenta, coloringScheme: ColoringScheme, colors: IColorTheme): string { function getCstNodeColor(cst: IConstituenta, coloringScheme: ColoringScheme, colors: IColorTheme): string {
if (coloringScheme === 'type') { if (coloringScheme === 'type') {
return getCstClassColor(cst.cst_class, colors); return colorbgCstClass(cst.cst_class, colors);
} }
if (coloringScheme === 'status') { if (coloringScheme === 'status') {
return getCstStatusBgColor(cst.status, colors); return colorbgCstStatus(cst.status, colors);
} }
return ''; return '';
} }
@ -407,7 +408,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
options={SelectorGraphColoring} options={SelectorGraphColoring}
isSearchable={false} isSearchable={false}
placeholder='Выберите цвет' placeholder='Выберите цвет'
value={coloringScheme ? { value: coloringScheme, label: mapColoringLabels.get(coloringScheme) } : null} value={coloringScheme ? { value: coloringScheme, label: mapLabelColoring.get(coloringScheme) } : null}
onChange={data => setColoringScheme(data?.value ?? SelectorGraphColoring[0].value)} onChange={data => setColoringScheme(data?.value ?? SelectorGraphColoring[0].value)}
/> />
@ -417,7 +418,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
options={SelectorGraphLayout} options={SelectorGraphLayout}
isSearchable={false} isSearchable={false}
placeholder='Способ расположения' placeholder='Способ расположения'
value={layout ? { value: layout, label: mapLayoutLabels.get(layout) } : null} value={layout ? { value: layout, label: mapLableLayout.get(layout) } : null}
onChange={data => handleChangeLayout(data?.value ?? SelectorGraphLayout[0].value)} onChange={data => handleChangeLayout(data?.value ?? SelectorGraphLayout[0].value)}
/> />
<div className='flex flex-col gap-1 mt-2'> <div className='flex flex-col gap-1 mt-2'>

View File

@ -17,7 +17,7 @@ import useModificationPrompt from '../../hooks/useModificationPrompt';
import { ICstCreateData, ICstRenameData } from '../../models/rsform'; import { ICstCreateData, ICstRenameData } from '../../models/rsform';
import { SyntaxTree } from '../../models/rslang'; import { SyntaxTree } from '../../models/rslang';
import { EXTEOR_TRS_FILE, prefixes, TIMEOUT_UI_REFRESH } from '../../utils/constants'; import { EXTEOR_TRS_FILE, prefixes, TIMEOUT_UI_REFRESH } from '../../utils/constants';
import { createAliasFor } from '../../utils/staticUI'; import { createAliasFor } from '../../utils/misc';
import DlgCloneRSForm from './DlgCloneRSForm'; import DlgCloneRSForm from './DlgCloneRSForm';
import DlgCreateCst from './DlgCreateCst'; import DlgCreateCst from './DlgCreateCst';
import DlgDeleteCst from './DlgDeleteCst'; import DlgDeleteCst from './DlgDeleteCst';

View File

@ -4,7 +4,7 @@ import Dropdown from '../../../components/Common/Dropdown';
import DropdownButton from '../../../components/Common/DropdownButton'; import DropdownButton from '../../../components/Common/DropdownButton';
import useDropdown from '../../../hooks/useDropdown'; import useDropdown from '../../../hooks/useDropdown';
import { DependencyMode } from '../../../models/miscelanious'; import { DependencyMode } from '../../../models/miscelanious';
import { getDependencyLabel } from '../../../utils/staticUI'; import { labelDependencyMode } from '../../../utils/labels';
interface DependencyModePickerProps { interface DependencyModePickerProps {
value: DependencyMode value: DependencyMode
@ -27,7 +27,7 @@ function DependencyModePicker({ value, onChange }: DependencyModePickerProps) {
tabIndex={-1} tabIndex={-1}
onClick={pickerMenu.toggle} onClick={pickerMenu.toggle}
> >
{getDependencyLabel(value)} {labelDependencyMode(value)}
</span> </span>
{ pickerMenu.isActive && { pickerMenu.isActive &&
<Dropdown stretchLeft > <Dropdown stretchLeft >

View File

@ -4,7 +4,7 @@ import Dropdown from '../../../components/Common/Dropdown';
import DropdownButton from '../../../components/Common/DropdownButton'; import DropdownButton from '../../../components/Common/DropdownButton';
import useDropdown from '../../../hooks/useDropdown'; import useDropdown from '../../../hooks/useDropdown';
import { CstMatchMode } from '../../../models/miscelanious'; import { CstMatchMode } from '../../../models/miscelanious';
import { getCstCompareLabel } from '../../../utils/staticUI'; import { labelCstMathchMode } from '../../../utils/labels';
interface MatchModePickerProps { interface MatchModePickerProps {
value: CstMatchMode value: CstMatchMode
@ -27,7 +27,7 @@ function MatchModePicker({ value, onChange }: MatchModePickerProps) {
tabIndex={-1} tabIndex={-1}
onClick={pickerMenu.toggle} onClick={pickerMenu.toggle}
> >
{getCstCompareLabel(value)} {labelCstMathchMode(value)}
</span> </span>
{ pickerMenu.isActive && { pickerMenu.isActive &&
<Dropdown> <Dropdown>

View File

@ -1,5 +1,6 @@
import { IExpressionParse, IRSErrorDescription, SyntaxTree } from '../../../models/rslang'; import { IExpressionParse, IRSErrorDescription, SyntaxTree } from '../../../models/rslang';
import { getRSErrorMessage, getRSErrorPrefix } from '../../../utils/staticUI'; import { describeRSError } from '../../../utils/labels';
import { getRSErrorPrefix } from '../../../utils/misc';
interface ParsingResultProps { interface ParsingResultProps {
data: IExpressionParse data: IExpressionParse
@ -22,7 +23,7 @@ function ParsingResult({ data, onShowAST, onShowError }: ParsingResultProps) {
return ( return (
<p key={`error-${index}`} className='cursor-pointer text-warning' onClick={() => onShowError(error)}> <p key={`error-${index}`} className='cursor-pointer text-warning' onClick={() => onShowError(error)}>
<span className='mr-1 font-semibold underline'>{error.isCritical ? 'Ошибка' : 'Предупреждение'} {getRSErrorPrefix(error)}:</span> <span className='mr-1 font-semibold underline'>{error.isCritical ? 'Ошибка' : 'Предупреждение'} {getRSErrorPrefix(error)}:</span>
<span> {getRSErrorMessage(error)}</span> <span> {describeRSError(error)}</span>
</p> </p>
); );
})} })}

View File

@ -1,25 +1,25 @@
import { TokenID } from '../../../models/rslang'; import { TokenID } from '../../../models/rslang';
import { getRSButtonData } from '../../../utils/staticUI' import { describeToken, labelToken } from '../../../utils/labels';
interface RSTokenButtonProps { interface RSTokenButtonProps {
id: TokenID token: TokenID
disabled?: boolean disabled?: boolean
onInsert: (token: TokenID, key?: string) => void onInsert: (token: TokenID, key?: string) => void
} }
function RSTokenButton({ id, disabled, onInsert }: RSTokenButtonProps) { function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps) {
const data = getRSButtonData(id); const label = labelToken(token);
const width = data.text.length > 3 ? 'w-[4rem]' : 'w-[2rem]'; const width = label.length > 3 ? 'w-[4rem]' : 'w-[2rem]';
return ( return (
<button <button
type='button' type='button'
disabled={disabled} disabled={disabled}
onClick={() => onInsert(id)} onClick={() => onInsert(token)}
title={data.tooltip} title={describeToken(token)}
tabIndex={-1} tabIndex={-1}
className={`px-1 cursor-pointer border rounded-none h-7 ${width} clr-outline clr-hover clr-btn-clear`} className={`px-1 cursor-pointer border rounded-none h-7 ${width} clr-outline clr-hover clr-btn-clear`}
> >
{data.text && <span className='whitespace-nowrap'>{data.text}</span>} {label && <span className='whitespace-nowrap'>{label}</span>}
</button> </button>
); );
} }

View File

@ -4,7 +4,8 @@ import { useConceptTheme } from '../../../context/ThemeContext';
import { ExpressionStatus } from '../../../models/rsform'; import { ExpressionStatus } from '../../../models/rsform';
import { type IConstituenta, inferStatus } from '../../../models/rsform'; import { type IConstituenta, inferStatus } from '../../../models/rsform';
import { IExpressionParse, ParsingStatus } from '../../../models/rslang'; import { IExpressionParse, ParsingStatus } from '../../../models/rslang';
import { getCstStatusBgColor, mapStatusInfo } from '../../../utils/staticUI'; import { colorbgCstStatus } from '../../../utils/color';
import { describeExpressionStatus, labelExpressionStatus } from '../../../utils/labels';
interface StatusBarProps { interface StatusBarProps {
isModified?: boolean isModified?: boolean
@ -25,13 +26,12 @@ function StatusBar({ isModified, constituenta, parseData }: StatusBarProps) {
return inferStatus(constituenta?.parse?.status, constituenta?.parse?.valueClass); return inferStatus(constituenta?.parse?.status, constituenta?.parse?.valueClass);
}, [isModified, constituenta, parseData]); }, [isModified, constituenta, parseData]);
const data = mapStatusInfo.get(status)!;
return ( return (
<div title={data.tooltip} <div title={describeExpressionStatus(status)}
className='text-sm h-[1.6rem] w-[10rem] font-semibold inline-flex border items-center select-none justify-center align-middle' className='text-sm h-[1.6rem] w-[10rem] font-semibold inline-flex border items-center select-none justify-center align-middle'
style={{backgroundColor: getCstStatusBgColor(status, colors)}} style={{backgroundColor: colorbgCstStatus(status, colors)}}
> >
Статус: [ {data.text} ] Статус: [ {labelExpressionStatus(status)} ]
</div> </div>
) )
} }

View File

@ -9,8 +9,10 @@ import { DependencyMode } from '../../../models/miscelanious';
import { CstMatchMode } from '../../../models/miscelanious'; import { CstMatchMode } from '../../../models/miscelanious';
import { applyGraphFilter } from '../../../models/miscelanious'; import { applyGraphFilter } from '../../../models/miscelanious';
import { CstType, extractGlobals, IConstituenta, matchConstituenta } from '../../../models/rsform'; import { CstType, extractGlobals, IConstituenta, matchConstituenta } from '../../../models/rsform';
import { createMockConstituenta } from '../../../models/rsform';
import { colorfgCstStatus } from '../../../utils/color';
import { prefixes } from '../../../utils/constants'; import { prefixes } from '../../../utils/constants';
import { getCstDescription, getCstStatusFgColor, getMockConstituenta } from '../../../utils/staticUI'; import { describeConstituenta } from '../../../utils/labels';
import ConstituentaTooltip from './ConstituentaTooltip'; import ConstituentaTooltip from './ConstituentaTooltip';
import DependencyModePicker from './DependencyModePicker'; import DependencyModePicker from './DependencyModePicker';
import MatchModePicker from './MatchModePicker'; import MatchModePicker from './MatchModePicker';
@ -74,7 +76,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
if (diff.length > 0) { if (diff.length > 0) {
diff.forEach( diff.forEach(
(alias, index) => filtered.push( (alias, index) => filtered.push(
getMockConstituenta( createMockConstituenta(
schema.id, schema.id,
-index, -index,
alias, alias,
@ -124,8 +126,8 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
className='min-w-[3.1rem] max-w-[3.1rem] px-1 text-center rounded-md whitespace-nowrap' className='min-w-[3.1rem] max-w-[3.1rem] px-1 text-center rounded-md whitespace-nowrap'
style={{ style={{
borderWidth: '1px', borderWidth: '1px',
borderColor: getCstStatusFgColor(cst.status, colors), borderColor: colorfgCstStatus(cst.status, colors),
color: getCstStatusFgColor(cst.status, colors), color: colorfgCstStatus(cst.status, colors),
fontWeight: 600, fontWeight: 600,
backgroundColor: isMockCst(cst) ? colors.bgWarning : colors.bgInput backgroundColor: isMockCst(cst) ? colors.bgWarning : colors.bgInput
}} }}
@ -136,7 +138,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
</>); </>);
} }
}), }),
columnHelper.accessor(cst => getCstDescription(cst), { columnHelper.accessor(cst => describeConstituenta(cst), {
id: 'description', id: 'description',
header: 'Описание', header: 'Описание',
size: 500, size: 500,

View File

@ -1,4 +1,6 @@
// ======== ID based fast Graph implementation ============= /**
* Represents single node of a {@link Graph}, as implemented by storing outgoing and incoming connections.
*/
export class GraphNode { export class GraphNode {
id: number; id: number;
outputs: number[]; outputs: number[];
@ -36,6 +38,11 @@ export class GraphNode {
} }
} }
/**
* Represents a Graph.
*
* This class is optimized for TermGraph use case and not supposed to be used as generic graph implementation.
*/
export class Graph { export class Graph {
nodes: Map<number, GraphNode> = new Map(); nodes: Map<number, GraphNode> = new Map();

View File

@ -1,5 +1,8 @@
// =========== Modules contains all dynamic color definitions ========== // =========== Modules contains all dynamic color definitions ==========
import { CstClass, ExpressionStatus } from '../models/rsform'
import { ISyntaxTreeNode, TokenID } from '../models/rslang'
// ============= MAIN COLOR THEMES ========== // ============= MAIN COLOR THEMES ==========
export interface IColorTheme { export interface IColorTheme {
@ -269,3 +272,115 @@ export const bracketsDarkT = {
color: darkT.fgSelected color: darkT.fgSelected
}, },
}; };
// =========== Misc colors ======================
export function colorbgSyntaxTree(node: ISyntaxTreeNode, colors: IColorTheme): string {
switch (node.typeID) {
case TokenID.PUNC_DEFINE:
case TokenID.PUNC_STRUCT:
case TokenID.ID_LOCAL:
return colors.bgGreen;
case TokenID.ID_GLOBAL:
case TokenID.ID_FUNCTION:
case TokenID.ID_PREDICATE:
case TokenID.ID_RADICAL:
case TokenID.LIT_INTEGER:
case TokenID.LIT_EMPTYSET:
case TokenID.LIT_INTSET:
return colors.bgTeal;
case TokenID.FORALL:
case TokenID.EXISTS:
case TokenID.NOT:
case TokenID.AND:
case TokenID.OR:
case TokenID.IMPLICATION:
case TokenID.EQUIVALENT:
case TokenID.GREATER:
case TokenID.LESSER:
case TokenID.EQUAL:
case TokenID.NOTEQUAL:
case TokenID.GREATER_OR_EQ:
case TokenID.LESSER_OR_EQ:
case TokenID.IN:
case TokenID.NOTIN:
case TokenID.SUBSET_OR_EQ:
case TokenID.SUBSET:
case TokenID.NOTSUBSET:
return colors.bgOrange;
case TokenID.NT_TUPLE:
case TokenID.NT_ENUMERATION:
case TokenID.BIGPR:
case TokenID.SMALLPR:
case TokenID.FILTER:
case TokenID.PLUS:
case TokenID.MINUS:
case TokenID.MULTIPLY:
case TokenID.BOOLEAN:
case TokenID.DECART:
case TokenID.INTERSECTION:
case TokenID.UNION:
case TokenID.SET_MINUS:
case TokenID.SYMMINUS:
case TokenID.REDUCE:
case TokenID.CARD:
case TokenID.BOOL:
case TokenID.DEBOOL:
return colors.bgBlue;
case TokenID.NT_FUNC_DEFINITION:
case TokenID.NT_DECLARATIVE_EXPR:
case TokenID.NT_IMPERATIVE_EXPR:
case TokenID.NT_RECURSIVE_FULL:
case TokenID.NT_ENUM_DECL:
case TokenID.NT_TUPLE_DECL:
case TokenID.NT_ARG_DECL:
case TokenID.NT_FUNC_CALL:
case TokenID.NT_ARGUMENTS:
case TokenID.NT_IMP_DECLARE:
case TokenID.NT_IMP_ASSIGN:
case TokenID.NT_IMP_LOGIC:
case TokenID.NT_RECURSIVE_SHORT:
return '';
case TokenID.PUNC_ASSIGN:
case TokenID.PUNC_ITERATE:
return colors.bgRed;
}
// node
return colors.bgRed;
}
export function colorbgCstStatus(status: ExpressionStatus, colors: IColorTheme): string {
switch (status) {
case ExpressionStatus.VERIFIED: return colors.bgGreen;
case ExpressionStatus.INCORRECT: return colors.bgRed;
case ExpressionStatus.INCALCULABLE: return colors.bgOrange;
case ExpressionStatus.PROPERTY: return colors.bgTeal;
case ExpressionStatus.UNKNOWN: return colors.bgBlue;
case ExpressionStatus.UNDEFINED: return colors.bgBlue;
}
}
export function colorfgCstStatus(status: ExpressionStatus, colors: IColorTheme): string {
switch (status) {
case ExpressionStatus.VERIFIED: return colors.fgGreen;
case ExpressionStatus.INCORRECT: return colors.fgRed;
case ExpressionStatus.INCALCULABLE: return colors.fgOrange;
case ExpressionStatus.PROPERTY: return colors.fgTeal;
case ExpressionStatus.UNKNOWN: return colors.fgBlue;
case ExpressionStatus.UNDEFINED: return colors.fgBlue;
}
}
export function colorbgCstClass(cstClass: CstClass, colors: IColorTheme): string {
switch (cstClass) {
case CstClass.BASIC: return colors.bgGreen;
case CstClass.DERIVED: return colors.bgBlue;
case CstClass.STATEMENT: return colors.bgRed;
case CstClass.TEMPLATE: return colors.bgTeal;
}
}

View File

@ -0,0 +1,514 @@
// =========== Modules contains all text descriptors ==========
import { Grammeme,IGramData } from '../models/language';
import { CstMatchMode, DependencyMode, HelpTopic } from '../models/miscelanious';
import { CstClass, CstType, ExpressionStatus, IConstituenta } from '../models/rsform';
import { IFunctionArg, IRSErrorDescription, ISyntaxTreeNode, ParsingStatus, RSErrorType, TokenID } from '../models/rslang';
export function describeConstituenta(cst: IConstituenta): string {
if (cst.cst_type === CstType.STRUCTURED) {
return (
cst.term_resolved || cst.term_raw ||
cst.definition_resolved || cst.definition_raw ||
cst.convention ||
cst.definition_formal
);
} else {
return (
cst.term_resolved || cst.term_raw ||
cst.definition_resolved || cst.definition_raw ||
cst.definition_formal ||
cst.convention
);
}
}
export function labelConstituenta(cst: IConstituenta) {
return `${cst.alias}: ${describeConstituenta(cst)}`;
}
export function labelToken(id: TokenID): string {
switch (id) {
case TokenID.BOOLEAN: return '()';
case TokenID.DECART: return '×';
case TokenID.PUNC_PL: return '( )';
case TokenID.PUNC_SL: return '[ ]';
case TokenID.FORALL: return '∀';
case TokenID.EXISTS: return '∃';
case TokenID.NOT: return '¬';
case TokenID.AND: return '&';
case TokenID.OR: return '';
case TokenID.IMPLICATION: return '⇒';
case TokenID.EQUIVALENT: return '⇔';
case TokenID.LIT_EMPTYSET: return '∅';
case TokenID.LIT_INTSET: return 'Z';
case TokenID.EQUAL: return '=';
case TokenID.NOTEQUAL: return '≠';
case TokenID.GREATER_OR_EQ: return '≥';
case TokenID.LESSER_OR_EQ: return '≤';
case TokenID.IN: return '∈';
case TokenID.NOTIN: return '∉';
case TokenID.SUBSET_OR_EQ: return '⊆';
case TokenID.SUBSET: return '⊂';
case TokenID.NOTSUBSET: return '⊄';
case TokenID.INTERSECTION: return '∩';
case TokenID.UNION: return '';
case TokenID.SET_MINUS: return '\\';
case TokenID.SYMMINUS: return '∆';
case TokenID.NT_DECLARATIVE_EXPR: return 'D{}';
case TokenID.NT_IMPERATIVE_EXPR: return 'I{}';
case TokenID.NT_RECURSIVE_FULL: return 'R{}';
case TokenID.BIGPR: return 'Pr1()';
case TokenID.SMALLPR: return 'pr1()';
case TokenID.FILTER: return 'Fi1[]()';
case TokenID.REDUCE: return 'red()';
case TokenID.CARD: return 'card()';
case TokenID.BOOL: return 'bool()';
case TokenID.DEBOOL: return 'debool()';
case TokenID.PUNC_ASSIGN: return ':=';
case TokenID.PUNC_ITERATE: return ':∈';
}
return `no label: ${id}`;
}
export function describeToken(id: TokenID): string {
switch (id) {
case TokenID.BOOLEAN: return 'Булеан [Alt + E]';
case TokenID.DECART: return 'Декартово произведение [Shift + 8 / Alt + Shift + E]';
case TokenID.PUNC_PL: return 'Скобки вокруг выражения [Alt + Shift + 9 ]';
case TokenID.PUNC_SL: return 'Скобки вокруг выражения [Alt + [ ]';
case TokenID.FORALL: return 'Квантор всеобщности [`]';
case TokenID.EXISTS: return 'Квантор существования [Shift + `]';
case TokenID.NOT: return 'Отрицание [Alt + `]';
case TokenID.AND: return 'Конъюнкция [Alt + 3 ~ Shift + 7]';
case TokenID.OR: return 'Дизъюнкция [Alt + Shift + 3]';
case TokenID.IMPLICATION: return 'Импликация [Alt + 4]';
case TokenID.EQUIVALENT: return 'Эквивалентность [Alt + Shift + 4]';
case TokenID.LIT_EMPTYSET: return 'Пустое множество [Alt + X]';
case TokenID.LIT_INTSET: return 'Целые числа [Alt + Z]';
case TokenID.EQUAL: return 'Равенство';
case TokenID.NOTEQUAL: return 'Неравенство [Alt + Shift + `]';
case TokenID.GREATER_OR_EQ: return 'Больше или равно [Alt + Shift + 7]';
case TokenID.LESSER_OR_EQ: return 'Меньше или равно [Alt + Shift + 8]';
case TokenID.IN: return 'Быть элементом (принадлежит) [Alt + 1]';
case TokenID.NOTIN: return 'Не принадлежит [Alt + Shift + 1]';
case TokenID.SUBSET_OR_EQ: return 'Быть частью (нестрогое подмножество) [Alt + 2]';
case TokenID.SUBSET: return 'Строгое подмножество [Alt + 7]';
case TokenID.NOTSUBSET: return 'Не подмножество [Alt + Shift + 2]';
case TokenID.INTERSECTION: return 'Пересечение [Alt + A]';
case TokenID.UNION: return 'Объединение [Alt + S]';
case TokenID.SET_MINUS: return 'Разность множеств [Alt + 5]';
case TokenID.SYMMINUS: return 'Симметрическая разность [Alt + Shift + 5]';
case TokenID.NT_DECLARATIVE_EXPR: return 'Декларативная форма определения терма [Alt + D]';
case TokenID.NT_IMPERATIVE_EXPR: return 'Императивная форма определения терма [Alt + G]';
case TokenID.NT_RECURSIVE_FULL: return 'Рекурсивная (цикличная) форма определения терма [Alt + T]';
case TokenID.BIGPR: return 'Большая проекция [Alt + Q]';
case TokenID.SMALLPR: return 'Малая проекция [Alt + W]';
case TokenID.FILTER: return 'Фильтр [Alt + F]';
case TokenID.REDUCE: return 'Множество-сумма [Alt + R]';
case TokenID.CARD: return 'Мощность [Alt + C]';
case TokenID.BOOL: return 'Синглетон [Alt + B]';
case TokenID.DEBOOL: return 'Десинглетон [Alt + V]';
case TokenID.PUNC_ASSIGN: return 'Присвоение (императивный синтаксис) [Alt + Shift + 6]';
case TokenID.PUNC_ITERATE: return 'Перебор элементов множества (императивный синтаксис) [Alt + 6]';
}
return `no description: ${id}`;
}
export function labelCstMathchMode(mode: CstMatchMode): string {
switch (mode) {
case CstMatchMode.ALL: return 'везде';
case CstMatchMode.EXPR: return 'выраж';
case CstMatchMode.TERM: return 'термин';
case CstMatchMode.TEXT: return 'текст';
case CstMatchMode.NAME: return 'имя';
}
}
export function labelDependencyMode(mode: DependencyMode): string {
switch (mode) {
case DependencyMode.ALL: return 'вся схема';
case DependencyMode.EXPRESSION: return 'выражение';
case DependencyMode.OUTPUTS: return 'потребители';
case DependencyMode.INPUTS: return 'поставщики';
case DependencyMode.EXPAND_INPUTS: return 'влияющие';
case DependencyMode.EXPAND_OUTPUTS: return 'зависимые';
}
}
export const mapLableLayout: 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', 'Граф: Без перекрытия']
]);
export const mapLabelColoring: Map<string, string> =
new Map([
['none', 'Цвет: моно'],
['status', 'Цвет: статус'],
['type', 'Цвет: класс'],
]);
export function labelExpressionStatus(status: ExpressionStatus): string {
switch (status) {
case ExpressionStatus.VERIFIED: return 'ок';
case ExpressionStatus.INCORRECT: return 'ошибка';
case ExpressionStatus.INCALCULABLE: return 'невыч';
case ExpressionStatus.PROPERTY: return 'св-во';
case ExpressionStatus.UNKNOWN: return 'неизв';
case ExpressionStatus.UNDEFINED: return 'N/A';
}
}
export function describeExpressionStatus(status: ExpressionStatus): string {
switch (status) {
case ExpressionStatus.VERIFIED: return 'выражение корректно и вычислимо';
case ExpressionStatus.INCORRECT: return 'ошибка в выражении';
case ExpressionStatus.INCALCULABLE: return 'выражение не вычислимо';
case ExpressionStatus.PROPERTY: return 'можно проверить принадлежность, но нельзя получить значение';
case ExpressionStatus.UNKNOWN: return 'требует проверки выражения';
case ExpressionStatus.UNDEFINED: return 'произошла ошибка при проверке выражения';
}
}
export function labelHelpTopic(topic: HelpTopic): string {
switch (topic) {
case HelpTopic.MAIN: return 'Портал';
case HelpTopic.RSLANG: return 'Экспликация';
case HelpTopic.LIBRARY: return 'Библиотека';
case HelpTopic.RSFORM: return '- паспорт схемы';
case HelpTopic.CSTLIST: return '- список конституент';
case HelpTopic.CONSTITUENTA: return '- конституента';
case HelpTopic.GRAPH_TERM: return '- граф термов';
case HelpTopic.EXTEOR: return 'Экстеор';
case HelpTopic.API: return 'REST API';
}
}
export function describeHelpTopic(topic: HelpTopic): string {
switch (topic) {
case HelpTopic.MAIN: return 'Общая справка по порталу';
case HelpTopic.RSLANG: return 'Справка по языку родов структур и экспликации';
case HelpTopic.LIBRARY: return 'Описание работы с библиотекой схем';
case HelpTopic.RSFORM: return 'Описание работы с описанием схемы';
case HelpTopic.CSTLIST: return 'Описание работы со списком конституентт';
case HelpTopic.CONSTITUENTA: return 'Описание редактирования конституенты';
case HelpTopic.GRAPH_TERM: return 'Описание работы с графом термов схемы';
case HelpTopic.EXTEOR: return 'Справка по программе для экспликации "Экстеор" для Windows';
case HelpTopic.API: return 'Описание интерфейса для разработчиков';
}
}
export function labelCstType(type: CstType) {
switch (type) {
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 labelCstClass(cclass: CstClass): string {
switch (cclass) {
case CstClass.BASIC: return 'базовый';
case CstClass.DERIVED: return 'производный';
case CstClass.STATEMENT: return 'утверждение';
case CstClass.TEMPLATE: return 'шаблон';
}
}
export function describeCstClass(cclass: CstClass): string {
switch (cclass) {
case CstClass.BASIC: return 'неопределяемое понятие, требует конвенции';
case CstClass.DERIVED: return 'выводимое понятие, задаваемое определением';
case CstClass.STATEMENT: return 'утверждение формальной логики';
case CstClass.TEMPLATE: return 'параметризованный шаблон определения';
}
}
export function labelTypification({ isValid, resultType, args }: {
isValid: boolean;
resultType: string;
args: IFunctionArg[];
}): string {
if (!isValid) {
return 'N/A';
}
if (resultType === '' || resultType === 'LOGIC') {
resultType = 'Logical';
}
if (args.length === 0) {
return resultType;
}
const argsText = args.map(arg => arg.typification).join(', ');
return `${resultType} 🠔 [${argsText}]`;
}
export function labelCstTypification(cst: IConstituenta): string {
return labelTypification({
isValid: cst.parse.status === ParsingStatus.VERIFIED,
resultType: cst.parse.typification,
args: cst.parse.args
});
}
export function labelSyntaxTree(node: ISyntaxTreeNode): string {
switch (node.typeID) {
case TokenID.ID_LOCAL:
case TokenID.ID_GLOBAL:
case TokenID.ID_FUNCTION:
case TokenID.ID_PREDICATE:
case TokenID.ID_RADICAL:
return node.data.value as string;
case TokenID.LIT_INTEGER: return String(node.data.value as number);
case TokenID.BIGPR: return 'Pr' + (node.data.value as string[]).toString();
case TokenID.SMALLPR: return 'pr' + (node.data.value as string[]).toString();
case TokenID.FILTER: return 'Fi' + (node.data.value as string[]).toString();
case TokenID.PLUS: return '+';
case TokenID.MINUS: return '-';
case TokenID.MULTIPLY: return '*';
case TokenID.GREATER: return '>';
case TokenID.LESSER: return '<';
case TokenID.NT_TUPLE: return 'TUPLE';
case TokenID.NT_ENUMERATION: return 'ENUM';
case TokenID.NT_ENUM_DECL: return 'ENUM_DECLARATION';
case TokenID.NT_TUPLE_DECL: return 'TUPLE_DECLARATION';
case TokenID.PUNC_DEFINE: return 'DEFINITION';
case TokenID.PUNC_STRUCT: return 'STRUCTURE_DEFITION';
case TokenID.NT_ARG_DECL: return 'ARG';
case TokenID.NT_FUNC_CALL: return 'CALL';
case TokenID.NT_ARGUMENTS: return 'ARGS';
case TokenID.NT_FUNC_DEFINITION: return 'FUNCTION_DEFINITION';
case TokenID.NT_IMP_DECLARE: return 'IDECLARE';
case TokenID.NT_IMP_ASSIGN: return 'IASSIGN';
case TokenID.NT_IMP_LOGIC: return 'ICHECK';
case TokenID.NT_RECURSIVE_SHORT: return labelToken(TokenID.NT_RECURSIVE_FULL);
case TokenID.BOOLEAN:
case TokenID.DECART:
case TokenID.FORALL:
case TokenID.EXISTS:
case TokenID.NOT:
case TokenID.AND:
case TokenID.OR:
case TokenID.IMPLICATION:
case TokenID.EQUIVALENT:
case TokenID.LIT_EMPTYSET:
case TokenID.LIT_INTSET:
case TokenID.EQUAL:
case TokenID.NOTEQUAL:
case TokenID.GREATER_OR_EQ:
case TokenID.LESSER_OR_EQ:
case TokenID.IN:
case TokenID.NOTIN:
case TokenID.SUBSET_OR_EQ:
case TokenID.SUBSET:
case TokenID.NOTSUBSET:
case TokenID.INTERSECTION:
case TokenID.UNION:
case TokenID.SET_MINUS:
case TokenID.SYMMINUS:
case TokenID.NT_DECLARATIVE_EXPR:
case TokenID.NT_IMPERATIVE_EXPR:
case TokenID.NT_RECURSIVE_FULL:
case TokenID.REDUCE:
case TokenID.CARD:
case TokenID.BOOL:
case TokenID.DEBOOL:
case TokenID.PUNC_ASSIGN:
case TokenID.PUNC_ITERATE:
return labelToken(node.typeID);
}
// node
return 'UNKNOWN ' + String(node.typeID);
}
export function labelGrammeme(gram: IGramData): string {
switch (gram.type) {
case Grammeme.NOUN: return 'ЧР: сущ';
case Grammeme.VERB: return 'ЧР: глагол';
case Grammeme.INFN: return 'ЧР: глагол инф';
case Grammeme.ADJF: return 'ЧР: прил';
case Grammeme.PRTF: return 'ЧР: прич';
case Grammeme.ADJS: return 'ЧР: кр прил';
case Grammeme.PRTS: return 'ЧР: кр прич';
case Grammeme.COMP: return 'ЧР: компаратив';
case Grammeme.GRND: return 'ЧР: деепричастие';
case Grammeme.NUMR: return 'ЧР: число';
case Grammeme.ADVB: return 'ЧР: наречие';
case Grammeme.NPRO: return 'ЧР: местоимение';
case Grammeme.PRED: return 'ЧР: предикатив';
case Grammeme.PREP: return 'ЧР: предлог';
case Grammeme.CONJ: return 'ЧР: союз';
case Grammeme.PRCL: return 'ЧР: частица';
case Grammeme.INTJ: return 'ЧР: междометие';
case Grammeme.Abbr: return 'ЧР: аббревиатура';
case Grammeme.sing: return 'Число: един';
case Grammeme.plur: return 'Число: множ';
case Grammeme.nomn: return 'Падеж: имен';
case Grammeme.gent: return 'Падеж: род';
case Grammeme.datv: return 'Падеж: дат';
case Grammeme.accs: return 'Падеж: вин';
case Grammeme.ablt: return 'Падеж: твор';
case Grammeme.loct: return 'Падеж: пред';
case Grammeme.masc: return 'Род: муж';
case Grammeme.femn: return 'Род: жен';
case Grammeme.neut: return 'Род: ср';
case Grammeme.perf: return 'Совершенный: да';
case Grammeme.impf: return 'Совершенный: нет';
case Grammeme.tran: return 'Переходный: да';
case Grammeme.intr: return 'Переходный: нет';
case Grammeme.pres: return 'Время: наст';
case Grammeme.past: return 'Время: прош';
case Grammeme.futr: return 'Время: буд';
case Grammeme.per1: return 'Лицо: 1';
case Grammeme.per2: return 'Лицо: 2';
case Grammeme.per3: return 'Лицо: 3';
case Grammeme.impr: return 'Повелительный: да';
case Grammeme.indc: return 'Повелительный: нет';
case Grammeme.incl: return 'Включающий: да';
case Grammeme.excl: return 'Включающий: нет';
case Grammeme.pssv: return 'Страдательный: да';
case Grammeme.actv: return 'Страдательный: нет';
case Grammeme.anim: return 'Одушевленный: да';
case Grammeme.inan: return 'Одушевленный: нет';
case Grammeme.Infr: return 'Стиль: неформальный';
case Grammeme.Slng: return 'Стиль: жаргон';
case Grammeme.Arch: return 'Стиль: устаревший';
case Grammeme.Litr: return 'Стиль: литературный';
case Grammeme.UNKN: return `Неизв: ${gram.data}`;
}
}
export function describeRSError(error: IRSErrorDescription): string {
switch (error.errorType) {
case RSErrorType.syntax:
return 'Неопределенная синтаксическая ошибка';
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]}`;
case RSErrorType.localUndeclared:
return `Использование необъявленной переменной: ${error.params[0]}`;
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 `Функция не интерпретируется для данных аргументов`;
case RSErrorType.globalNonemptyBase:
return `Непустое выражение базисного/константного множества`;
case RSErrorType.globalUnexpectedType:
return `Типизация выражения не соответствует типу конституенты`;
}
return 'UNKNOWN ERROR';
}

View File

@ -0,0 +1,72 @@
// Module: miscellaneous static functions to generate UI resources
import { CstType, IConstituenta, IRSForm } from '../models/rsform';
import { IRSErrorDescription } from '../models/rslang';
import { resolveErrorClass, RSErrorClass } from '../models/rslang';
import { labelCstType } from './labels';
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.cst_type === CstType.STRUCTURED ? '::=' : ':==');
}
export function getCstTypeShortcut(type: CstType) {
const prefix = labelCstType(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 function createAliasFor(type: CstType, schema: IRSForm): string {
const prefix = getCstTypePrefix(type);
if (!schema.items || schema.items.length <= 0) {
return `${prefix}1`;
}
const index = schema.items.reduce((prev, cst, index) => {
if (cst.cst_type !== type) {
return prev;
}
index = Number(cst.alias.slice(1 - cst.alias.length)) + 1;
return Math.max(prev, index);
}, 1);
return `${prefix}${index}`;
}
export function cloneTitle(schema: IRSForm): string {
if (!schema.title.includes('[клон]')) {
return schema.title + ' [клон]';
} else {
return (schema.title + '+');
}
}
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;
}
}

View File

@ -1,10 +1,11 @@
// Module: Selector maps // Module: Selector maps
import { LayoutTypes } from 'reagraph'; import { LayoutTypes } from 'reagraph';
import { Grammeme } from '../models/language'; import { Grammeme, IGramData } from '../models/language';
import { CstType } from '../models/rsform'; import { CstType } from '../models/rsform';
import { ColoringScheme } from '../pages/RSFormPage/EditorTermGraph'; import { ColoringScheme } from '../pages/RSFormPage/EditorTermGraph';
import { getCstTypeLabel } from './staticUI'; import { labelGrammeme } from './labels';
import { labelCstType } from './labels';
export const SelectorGraphLayout: { value: LayoutTypes, label: string }[] = [ export const SelectorGraphLayout: { value: LayoutTypes, label: string }[] = [
@ -31,55 +32,37 @@ export const SelectorGraphColoring: { value: ColoringScheme, label: string }[] =
export const SelectorCstType = ( export const SelectorCstType = (
Object.values(CstType)).map( Object.values(CstType)).map(
typeStr => ({ typeStr => ({
value: typeStr as CstType, value: typeStr as CstType,
label: getCstTypeLabel(typeStr as CstType) label: labelCstType(typeStr as CstType)
}) })
); );
export const SelectorGrammems: { value: Grammeme, label: string }[] = [ export interface IGrammemeOption {
{ value: Grammeme.sing, label: 'Число: един' }, value: Grammeme
{ value: Grammeme.plur, label: 'Число: множ' }, label: string
}
{ value: Grammeme.nomn, label: 'Падеж: имен' }, export const SelectorGrammems: IGrammemeOption[] =
{ value: Grammeme.gent, label: 'Падеж: род' }, [
{ value: Grammeme.datv, label: 'Падеж: дат' }, Grammeme.NOUN, Grammeme.VERB,
{ value: Grammeme.accs, label: 'Падеж: вин' },
{ value: Grammeme.ablt, label: 'Падеж: твор' },
{ value: Grammeme.loct, label: 'Падеж: пред' },
{ value: Grammeme.NOUN, label: 'ЧР: сущ' }, Grammeme.sing, Grammeme.plur,
{ value: Grammeme.VERB, label: 'ЧР: глагол' }, Grammeme.nomn, Grammeme.gent, Grammeme.datv,
{ value: Grammeme.INFN, label: 'ЧР: глагол инф' }, Grammeme.accs, Grammeme.ablt, Grammeme.loct,
{ value: Grammeme.ADJF, label: 'ЧР: прил' },
{ value: Grammeme.ADJS, label: 'ЧР: кр прил' },
{ value: Grammeme.PRTF, label: 'ЧР: прич' },
{ value: Grammeme.PRTS, label: 'ЧР: кр прич' },
{ value: Grammeme.perf, label: 'Совершенный: да' }, Grammeme.INFN, Grammeme.ADJF, Grammeme.PRTF,
{ value: Grammeme.impf, label: 'Совершенный: нет' }, Grammeme.ADJS, Grammeme.PRTS,
{ value: Grammeme.tran, label: 'Переходный: да' }, Grammeme.perf, Grammeme.impf,
{ value: Grammeme.intr, label: 'Переходный: нет' }, Grammeme.tran, Grammeme.intr,
Grammeme.pres, Grammeme.past, Grammeme.futr,
{ value: Grammeme.pres, label: 'Время: наст' }, Grammeme.per1, Grammeme.per2, Grammeme.per3,
{ value: Grammeme.past, label: 'Время: прош' }, Grammeme.impr, Grammeme.indc,
{ value: Grammeme.futr, label: 'Время: буд' }, Grammeme.incl, Grammeme.excl,
Grammeme.pssv, Grammeme.actv,
{ value: Grammeme.per1, label: 'Лицо: 1' }, ].map(
{ value: Grammeme.per2, label: 'Лицо: 2' }, gram => ({
{ value: Grammeme.per3, label: 'Лицо: 3' }, value: gram,
label: labelGrammeme({type: gram, data: ''} as IGramData)
{ value: Grammeme.impr, label: 'Повелительный: да' }, }));
{ value: Grammeme.indc, label: 'Повелительный: нет' },
{ value: Grammeme.incl, label: 'Включающий: да' },
{ value: Grammeme.excl, label: 'Включающий: нет' },
{ value: Grammeme.pssv, label: 'Страдательный: да' },
{ value: Grammeme.actv, label: 'Страдательный: нет' },
];
// { value: Grammeme.masc, label: 'Род: муж' },
// { value: Grammeme.femn, label: 'Род: жен' },
// { value: Grammeme.neut, label: 'Род: ср' },

View File

@ -1,740 +0,0 @@
import { DependencyMode } from '../models/miscelanious';
import { HelpTopic } from '../models/miscelanious';
import { CstMatchMode } from '../models/miscelanious';
import { ExpressionStatus } from '../models/rsform';
import { CstClass, CstType, IConstituenta, IRSForm } from '../models/rsform';
import { IFunctionArg, IRSErrorDescription, ISyntaxTreeNode, ParsingStatus, ValueClass } from '../models/rslang';
import { resolveErrorClass, RSErrorClass, RSErrorType, TokenID } from '../models/rslang';
import { IColorTheme } from './color';
export interface IDescriptor {
text: string
tooltip: string
}
export function getCstDescription(cst: IConstituenta): string {
if (cst.cst_type === CstType.STRUCTURED) {
return (
cst.term_resolved || cst.term_raw ||
cst.definition_resolved || cst.definition_raw ||
cst.convention ||
cst.definition_formal
);
} else {
return (
cst.term_resolved || cst.term_raw ||
cst.definition_resolved || cst.definition_raw ||
cst.definition_formal ||
cst.convention
);
}
}
export function getCstLabel(cst: IConstituenta) {
return `${cst.alias}: ${getCstDescription(cst)}`;
}
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.cst_type === CstType.STRUCTURED ? '::=' : ':==');
}
export function getRSButtonData(id: TokenID): IDescriptor {
switch (id) {
case TokenID.BOOLEAN: return {
text: '()',
tooltip: 'Булеан [Alt + E]'
};
case TokenID.DECART: return {
text: '×',
tooltip: 'Декартово произведение [Shift + 8 / Alt + Shift + E]'
};
case TokenID.PUNC_PL: return {
text: '( )',
tooltip: 'Скобки вокруг выражения [Alt + Shift + 9 ]'
};
case TokenID.PUNC_SL: return {
text: '[ ]',
tooltip: 'Скобки вокруг выражения [Alt + [ ]'
};
case TokenID.FORALL: return {
text: '∀',
tooltip: 'Квантор всеобщности [`]'
};
case TokenID.EXISTS: return {
text: '∃',
tooltip: 'Квантор существования [Shift + `]'
};
case TokenID.NOT: return {
text: '¬',
tooltip: 'Отрицание [Alt + `]'
};
case TokenID.AND: return {
text: '&',
tooltip: 'Конъюнкция [Alt + 3 ~ Shift + 7]'
};
case TokenID.OR: return {
text: '',
tooltip: 'дизъюнкция [Alt + Shift + 3]'
};
case TokenID.IMPLICATION: return {
text: '⇒',
tooltip: 'импликация [Alt + 4]'
};
case TokenID.EQUIVALENT: return {
text: '⇔',
tooltip: 'эквивалентность [Alt + Shift + 4]'
};
case TokenID.LIT_EMPTYSET: return {
text: '∅',
tooltip: 'пустое множество [Alt + X]'
};
case TokenID.LIT_INTSET: return {
text: 'Z',
tooltip: 'целые числа [Alt + Z]'
};
case TokenID.EQUAL: return {
text: '=',
tooltip: 'равенство'
};
case TokenID.NOTEQUAL: return {
text: '≠',
tooltip: 'неравенство [Alt + Shift + `]'
};
case TokenID.GREATER_OR_EQ: return {
text: '≥',
tooltip: 'больше или равно [Alt + Shift + 7]'
};
case TokenID.LESSER_OR_EQ: return {
text: '≤',
tooltip: 'меньше или равно [Alt + Shift + 8]'
};
case TokenID.IN: return {
text: '∈',
tooltip: 'быть элементом (принадлежит) [Alt + 1]'
};
case TokenID.NOTIN: return {
text: '∉',
tooltip: 'не принадлежит [Alt + Shift + 1]'
};
case TokenID.SUBSET_OR_EQ: return {
text: '⊆',
tooltip: 'быть частью (нестрогое подмножество) [Alt + 2]'
};
case TokenID.SUBSET: return {
text: '⊂',
tooltip: 'строгое подмножество [Alt + 7]'
};
case TokenID.NOTSUBSET: return {
text: '⊄',
tooltip: 'не подмножество [Alt + Shift + 2]'
};
case TokenID.INTERSECTION: return {
text: '∩',
tooltip: 'пересечение [Alt + A]'
};
case TokenID.UNION: return {
text: '',
tooltip: 'объединение [Alt + S]'
};
case TokenID.SET_MINUS: return {
text: '\\',
tooltip: 'Разность множеств [Alt + 5]'
};
case TokenID.SYMMINUS: return {
text: '∆',
tooltip: 'Симметрическая разность [Alt + Shift + 5]'
};
case TokenID.NT_DECLARATIVE_EXPR: return {
text: 'D{}',
tooltip: 'Декларативная форма определения терма [Alt + D]'
};
case TokenID.NT_IMPERATIVE_EXPR: return {
text: 'I{}',
tooltip: 'императивная форма определения терма [Alt + G]'
};
case TokenID.NT_RECURSIVE_FULL: return {
text: 'R{}',
tooltip: 'рекурсивная (цикличная) форма определения терма [Alt + T]'
};
case TokenID.BIGPR: return {
text: 'Pr1()',
tooltip: 'большая проекция [Alt + Q]'
};
case TokenID.SMALLPR: return {
text: 'pr1()',
tooltip: 'малая проекция [Alt + W]'
};
case TokenID.FILTER: return {
text: 'Fi1[]()',
tooltip: 'фильтр [Alt + F]'
};
case TokenID.REDUCE: return {
text: 'red()',
tooltip: 'множество-сумма [Alt + R]'
};
case TokenID.CARD: return {
text: 'card()',
tooltip: 'мощность [Alt + C]'
};
case TokenID.BOOL: return {
text: 'bool()',
tooltip: 'синглетон [Alt + B]'
};
case TokenID.DEBOOL: return {
text: 'debool()',
tooltip: 'десинглетон [Alt + V]'
};
case TokenID.PUNC_ASSIGN: return {
text: ':=',
tooltip: 'присвоение (императивный синтаксис) [Alt + Shift + 6]'
};
case TokenID.PUNC_ITERATE: return {
text: ':∈',
tooltip: 'перебор элементов множества (императивный синтаксис) [Alt + 6]'
};
}
return {
text: 'undefined',
tooltip: 'undefined'
}
}
export function getCstTypeLabel(type: CstType) {
switch (type) {
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 function getCstCompareLabel(mode: CstMatchMode): string {
switch(mode) {
case CstMatchMode.ALL: return 'везде';
case CstMatchMode.EXPR: return 'выраж';
case CstMatchMode.TERM: return 'термин';
case CstMatchMode.TEXT: return 'текст';
case CstMatchMode.NAME: return 'имя';
}
}
export function getDependencyLabel(mode: DependencyMode): string {
switch(mode) {
case DependencyMode.ALL: return 'вся схема';
case DependencyMode.EXPRESSION: return 'выражение';
case DependencyMode.OUTPUTS: return 'потребители';
case DependencyMode.INPUTS: return 'поставщики';
case DependencyMode.EXPAND_INPUTS: return 'влияющие';
case DependencyMode.EXPAND_OUTPUTS: return 'зависимые';
}
}
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', 'Граф: Без перекрытия']
]);
export const mapColoringLabels: Map<string, string> = new Map([
['none', 'Цвет: моно'],
['status', 'Цвет: статус'],
['type', 'Цвет: класс'],
]);
export function getCstStatusBgColor(status: ExpressionStatus, colors: IColorTheme): string {
switch (status) {
case ExpressionStatus.VERIFIED: return colors.bgGreen;
case ExpressionStatus.INCORRECT: return colors.bgRed;
case ExpressionStatus.INCALCULABLE: return colors.bgOrange;
case ExpressionStatus.PROPERTY: return colors.bgTeal;
case ExpressionStatus.UNKNOWN: return colors.bgBlue;
case ExpressionStatus.UNDEFINED: return colors.bgBlue;
}
}
export function getCstStatusFgColor(status: ExpressionStatus, colors: IColorTheme): string {
switch (status) {
case ExpressionStatus.VERIFIED: return colors.fgGreen;
case ExpressionStatus.INCORRECT: return colors.fgRed;
case ExpressionStatus.INCALCULABLE: return colors.fgOrange;
case ExpressionStatus.PROPERTY: return colors.fgTeal;
case ExpressionStatus.UNKNOWN: return colors.fgBlue;
case ExpressionStatus.UNDEFINED: return colors.fgBlue;
}
}
export const mapStatusInfo: Map<ExpressionStatus, IDescriptor> = new Map([
[ ExpressionStatus.VERIFIED, {
text: 'ок',
tooltip: 'выражение корректно и вычислимо'
}],
[ ExpressionStatus.INCORRECT, {
text: 'ошибка',
tooltip: 'ошибка в выражении'
}],
[ ExpressionStatus.INCALCULABLE, {
text: 'невыч',
tooltip: 'выражение не вычислимо'
}],
[ ExpressionStatus.PROPERTY, {
text: 'св-во',
tooltip: 'можно проверить принадлежность, но нельзя получить значение'
}],
[ ExpressionStatus.UNKNOWN, {
text: 'неизв',
tooltip: 'требует проверки выражения'
}],
[ ExpressionStatus.UNDEFINED, {
text: 'N/A',
tooltip: 'произошла ошибка при проверке выражения'
}]
]);
export const mapTopicInfo: Map<HelpTopic, IDescriptor> = new Map([
[ HelpTopic.MAIN, {
text: 'Портал',
tooltip: 'Общая справка по порталу'
}],
[ HelpTopic.RSLANG, {
text: 'Рода структур',
tooltip: 'Справка по языку родов структур и экспликации'
}],
[ HelpTopic.LIBRARY, {
text: 'Библиотека',
tooltip: 'Интерфейс работы с библиотекой схем'
}],
[ HelpTopic.RSFORM, {
text: '- паспорт схемы',
tooltip: 'Интерфейс работы с описанием схемы'
}],
[ HelpTopic.CSTLIST, {
text: '- список конституент',
tooltip: 'Интерфейс работы со списком конституент'
}],
[ HelpTopic.CONSTITUENTA, {
text: '- конституента',
tooltip: 'Интерфейс редактирования конституенты'
}],
[ HelpTopic.GRAPH_TERM, {
text: '- граф термов',
tooltip: 'Интерфейс работ с графом термов схемы'
}],
[ HelpTopic.EXTEOR, {
text: 'Экстеор',
tooltip: 'Справка по программе Экстеор'
}],
[ HelpTopic.API, {
text: 'REST API',
tooltip: 'Документация интерфейса для разработчиков'
}],
]);
export function getCstClassColor(cstClass: CstClass, colors: IColorTheme): string {
switch (cstClass) {
case CstClass.BASIC: return colors.bgGreen;
case CstClass.DERIVED: return colors.bgBlue;
case CstClass.STATEMENT: return colors.bgRed;
case CstClass.TEMPLATE: return colors.bgTeal;
}
}
export const mapCstClassInfo: Map<CstClass, IDescriptor> = new Map([
[ CstClass.BASIC, {
text: 'базовый',
tooltip: 'неопределяемое понятие, требует конвенции'
}],
[ CstClass.DERIVED, {
text: 'производный',
tooltip: 'выводимое понятие, задаваемое определением'
}],
[ CstClass.STATEMENT, {
text: 'утверждение',
tooltip: 'неопределяемое понятие, требует конвенции'
}],
[ CstClass.TEMPLATE, {
text: 'шаблон',
tooltip: 'параметризованный шаблон определения'
}],
]);
export function createAliasFor(type: CstType, schema: IRSForm): string {
const prefix = getCstTypePrefix(type);
if (!schema.items || schema.items.length <= 0) {
return `${prefix}1`;
}
const index = schema.items.reduce((prev, cst, index) => {
if (cst.cst_type !== type) {
return prev;
}
index = Number(cst.alias.slice(1 - cst.alias.length)) + 1;
return Math.max(prev, index);
}, 1);
return `${prefix}${index}`;
}
export function getMockConstituenta(schema: number, id: number, alias: string, type: CstType, comment: string): IConstituenta {
return {
id: id,
order: -1,
schema: schema,
alias: alias,
convention: comment,
cst_type: type,
term_raw: '',
term_resolved: '',
term_forms: [],
definition_formal: '',
definition_raw: '',
definition_resolved: '',
status: ExpressionStatus.INCORRECT,
is_template: false,
cst_class: CstClass.DERIVED,
parse: {
status: ParsingStatus.INCORRECT,
valueClass: ValueClass.INVALID,
typification: 'N/A',
syntaxTree: '',
args: []
}
};
}
export function getCloneTitle(schema: IRSForm): string {
if (!schema.title.includes('[клон]')) {
return schema.title + ' [клон]';
} else {
return (schema.title + '+');
}
}
export function getTypificationLabel({isValid, resultType, args}: {
isValid: boolean,
resultType: string,
args: IFunctionArg[]
}): string {
if (!isValid) {
return 'N/A';
}
if (resultType === '' || resultType === 'LOGIC') {
resultType = 'Logical';
}
if (args.length === 0) {
return resultType;
}
const argsText = args.map(arg => arg.typification).join(', ');
return `${resultType} 🠔 [${argsText}]`;
}
export function getCstTypificationLabel(cst: IConstituenta): string {
return getTypificationLabel({
isValid: cst.parse.status === ParsingStatus.VERIFIED,
resultType: cst.parse.typification,
args: cst.parse.args
});
}
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 'Неопределенная синтаксическая ошибка';
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]}`;
case RSErrorType.localUndeclared:
return `Использование необъявленной переменной: ${error.params[0]}`;
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 `Функция не интерпретируется для данных аргументов`;
case RSErrorType.globalNonemptyBase:
return `Непустое выражение базисного/константного множества`;
case RSErrorType.globalUnexpectedType:
return `Типизация выражения не соответствует типу конституенты`;
}
return 'UNKNOWN ERROR';
}
export function getASTNodeLabel(node: ISyntaxTreeNode): string {
switch(node.typeID) {
case TokenID.ID_LOCAL:
case TokenID.ID_GLOBAL:
case TokenID.ID_FUNCTION:
case TokenID.ID_PREDICATE:
case TokenID.ID_RADICAL:
return node.data.value as string;
case TokenID.LIT_INTEGER: return String(node.data.value as number);
case TokenID.BIGPR: return 'Pr' + (node.data.value as string[]).toString();
case TokenID.SMALLPR: return 'pr' + (node.data.value as string[]).toString();
case TokenID.FILTER: return 'Fi' + (node.data.value as string[]).toString();
case TokenID.PLUS: return '+'
case TokenID.MINUS: return '-'
case TokenID.MULTIPLY: return '*'
case TokenID.GREATER: return '>'
case TokenID.LESSER: return '<'
case TokenID.NT_TUPLE: return 'TUPLE'
case TokenID.NT_ENUMERATION: return 'ENUM'
case TokenID.NT_ENUM_DECL: return 'ENUM_DECLARATION'
case TokenID.NT_TUPLE_DECL: return 'TUPLE_DECLARATION'
case TokenID.PUNC_DEFINE: return 'DEFINITION'
case TokenID.PUNC_STRUCT: return 'STRUCTURE_DEFITION'
case TokenID.NT_ARG_DECL: return 'ARG'
case TokenID.NT_FUNC_CALL: return 'CALL'
case TokenID.NT_ARGUMENTS: return 'ARGS'
case TokenID.NT_FUNC_DEFINITION: return 'FUNCTION_DEFINITION'
case TokenID.NT_IMP_DECLARE: return 'IDECLARE'
case TokenID.NT_IMP_ASSIGN: return 'IASSIGN'
case TokenID.NT_IMP_LOGIC: return 'ICHECK'
case TokenID.NT_RECURSIVE_SHORT: return getRSButtonData(TokenID.NT_RECURSIVE_FULL).text;
case TokenID.BOOLEAN:
case TokenID.DECART:
case TokenID.FORALL:
case TokenID.EXISTS:
case TokenID.NOT:
case TokenID.AND:
case TokenID.OR:
case TokenID.IMPLICATION:
case TokenID.EQUIVALENT:
case TokenID.LIT_EMPTYSET:
case TokenID.LIT_INTSET:
case TokenID.EQUAL:
case TokenID.NOTEQUAL:
case TokenID.GREATER_OR_EQ:
case TokenID.LESSER_OR_EQ:
case TokenID.IN:
case TokenID.NOTIN:
case TokenID.SUBSET_OR_EQ:
case TokenID.SUBSET:
case TokenID.NOTSUBSET:
case TokenID.INTERSECTION:
case TokenID.UNION:
case TokenID.SET_MINUS:
case TokenID.SYMMINUS:
case TokenID.NT_DECLARATIVE_EXPR:
case TokenID.NT_IMPERATIVE_EXPR:
case TokenID.NT_RECURSIVE_FULL:
case TokenID.REDUCE:
case TokenID.CARD:
case TokenID.BOOL:
case TokenID.DEBOOL:
case TokenID.PUNC_ASSIGN:
case TokenID.PUNC_ITERATE:
return getRSButtonData(node.typeID).text;
}
// node
return 'UNKNOWN ' + String(node.typeID);
}
export function getASTNodeColor(node: ISyntaxTreeNode, colors: IColorTheme): string {
switch(node.typeID) {
case TokenID.PUNC_DEFINE:
case TokenID.PUNC_STRUCT:
case TokenID.ID_LOCAL:
return colors.bgGreen;
case TokenID.ID_GLOBAL:
case TokenID.ID_FUNCTION:
case TokenID.ID_PREDICATE:
case TokenID.ID_RADICAL:
case TokenID.LIT_INTEGER:
case TokenID.LIT_EMPTYSET:
case TokenID.LIT_INTSET:
return colors.bgTeal;
case TokenID.FORALL:
case TokenID.EXISTS:
case TokenID.NOT:
case TokenID.AND:
case TokenID.OR:
case TokenID.IMPLICATION:
case TokenID.EQUIVALENT:
case TokenID.GREATER:
case TokenID.LESSER:
case TokenID.EQUAL:
case TokenID.NOTEQUAL:
case TokenID.GREATER_OR_EQ:
case TokenID.LESSER_OR_EQ:
case TokenID.IN:
case TokenID.NOTIN:
case TokenID.SUBSET_OR_EQ:
case TokenID.SUBSET:
case TokenID.NOTSUBSET:
return colors.bgOrange;
case TokenID.NT_TUPLE:
case TokenID.NT_ENUMERATION:
case TokenID.BIGPR:
case TokenID.SMALLPR:
case TokenID.FILTER:
case TokenID.PLUS:
case TokenID.MINUS:
case TokenID.MULTIPLY:
case TokenID.BOOLEAN:
case TokenID.DECART:
case TokenID.INTERSECTION:
case TokenID.UNION:
case TokenID.SET_MINUS:
case TokenID.SYMMINUS:
case TokenID.REDUCE:
case TokenID.CARD:
case TokenID.BOOL:
case TokenID.DEBOOL:
return colors.bgBlue;
case TokenID.NT_FUNC_DEFINITION:
case TokenID.NT_DECLARATIVE_EXPR:
case TokenID.NT_IMPERATIVE_EXPR:
case TokenID.NT_RECURSIVE_FULL:
case TokenID.NT_ENUM_DECL:
case TokenID.NT_TUPLE_DECL:
case TokenID.NT_ARG_DECL:
case TokenID.NT_FUNC_CALL:
case TokenID.NT_ARGUMENTS:
case TokenID.NT_IMP_DECLARE:
case TokenID.NT_IMP_ASSIGN:
case TokenID.NT_IMP_LOGIC:
case TokenID.NT_RECURSIVE_SHORT:
return '';
case TokenID.PUNC_ASSIGN:
case TokenID.PUNC_ITERATE:
return colors.bgRed;
}
// node
return colors.bgRed;
}

View File

@ -1,5 +1,11 @@
COMPOSE_FILE="docker-compose-prod.yml"
BACKUP_SCRIPT="./scripts/prod/CreateBackup.sh"
git reset --hard git reset --hard
git pull git pull
/bin/bash ./scripts/prod/CreateBackup.sh
docker compose --file "docker-compose-prod.yml" up --build --detach /bin/bash "${BACKUP_SCRIPT}"
docker image prune --all --force
docker compose --file "${COMPOSE_FILE}" up --build --detach
docker image prune --all --force
docker compose --file "${COMPOSE_FILE}" restart