ConceptPortal-public/rsconcept/frontend/src/models/rsform.ts

332 lines
9.1 KiB
TypeScript
Raw Normal View History

2023-09-11 20:31:54 +03:00
import { Graph } from '../utils/Graph'
2023-10-04 18:46:52 +03:00
import { TextMatcher } from '../utils/utils'
2023-09-11 20:31:54 +03:00
import { ILibraryUpdateData } from './library'
import { ILibraryItem } from './library'
import { CstMatchMode } from './miscelanious'
2023-11-06 02:20:16 +03:00
import { IArgumentInfo, ParsingStatus, ValueClass } from './rslang'
2023-07-29 03:31:21 +03:00
export enum CstType {
BASE = 'basic',
STRUCTURED = 'structure',
TERM = 'term',
AXIOM = 'axiom',
FUNCTION = 'function',
PREDICATE = 'predicate',
CONSTANT = 'constant',
THEOREM = 'theorem'
}
2023-11-04 01:29:21 +03:00
// CstType constant for category dividers in TemplateSchemas. TODO: create separate sctructure for templates
export const CATEGORY_CST_TYPE = CstType.THEOREM;
2023-08-16 00:39:16 +03:00
export enum CstClass {
BASIC = 'basic',
DERIVED = 'derived',
STATEMENT = 'statement',
TEMPLATE = 'template'
}
2023-09-11 20:31:54 +03:00
// Constituenta expression status
export enum ExpressionStatus {
2023-09-26 00:24:50 +03:00
VERIFIED = 'verified',
2023-09-11 20:31:54 +03:00
INCORRECT = 'incorrect',
2023-09-26 00:24:50 +03:00
INCALCULABLE = 'incalculable',
2023-10-02 23:43:29 +03:00
PROPERTY = 'property',
2023-09-26 00:24:50 +03:00
UNDEFINED = 'undefined',
UNKNOWN = 'unknown',
2023-09-11 20:31:54 +03:00
}
export interface TermForm {
text: string
tags: string
2023-07-20 17:11:03 +03:00
}
2023-09-11 20:31:54 +03:00
// ====== Constituenta ==========
export interface IConstituentaMeta {
id: number
schema: number
order: number
alias: string
convention: string
cst_type: CstType
definition_formal: string
definition_raw: string
definition_resolved: string
term_raw: string
term_resolved: string
term_forms: TermForm[]
}
export interface IConstituenta
extends IConstituentaMeta {
cst_class: CstClass
status: ExpressionStatus
is_template: boolean
parse: {
status: ParsingStatus
valueClass: ValueClass
typification: string
syntaxTree: string
2023-11-06 02:20:16 +03:00
args: IArgumentInfo[]
}
}
export interface IConstituentaList {
items: number[]
}
export interface ICstCreateData
extends Pick<
IConstituentaMeta,
'alias' | 'cst_type' | 'definition_raw' | 'term_raw' |
'convention' | 'definition_formal' | 'term_forms'
> {
insert_after: number | null
}
export interface ICstMovetoData extends IConstituentaList {
move_to: number
}
export interface ICstUpdateData
2023-09-25 14:17:52 +03:00
extends Pick<IConstituentaMeta, 'id'>,
Partial<Pick<IConstituentaMeta, | 'alias' | 'convention' | 'definition_formal' | 'definition_raw' | 'term_raw' | 'term_forms'>> {}
export interface ICstRenameData
extends Pick<IConstituentaMeta, 'id' | 'alias' | 'cst_type' > {}
export interface ICstCreatedResponse {
new_cst: IConstituentaMeta
schema: IRSFormData
}
// ========== RSForm ============
2023-07-20 17:11:03 +03:00
export interface IRSFormStats {
2023-07-25 20:27:29 +03:00
count_all: number
count_errors: number
count_property: number
count_incalc: number
count_termin: number
2023-08-27 15:39:49 +03:00
count_definition: number
count_convention: number
2023-07-25 20:27:29 +03:00
count_base: number
count_constant: number
count_structured: number
count_axiom: number
count_term: number
count_function: number
count_predicate: number
count_theorem: number
2023-07-20 17:11:03 +03:00
}
2023-08-25 22:51:20 +03:00
export interface IRSForm
extends ILibraryItem {
items: IConstituenta[]
stats: IRSFormStats
2023-07-29 21:23:18 +03:00
graph: Graph
2023-08-26 17:26:49 +03:00
subscribers: number[]
2023-07-20 17:11:03 +03:00
}
2023-07-30 00:47:07 +03:00
export interface IRSFormData extends Omit<IRSForm, 'stats' | 'graph'> {}
export interface IRSFormCreateData
2023-08-25 22:51:20 +03:00
extends ILibraryUpdateData {
2023-07-25 20:27:29 +03:00
file?: File
fileName?: string
2023-07-20 17:11:03 +03:00
}
2023-07-27 22:04:25 +03:00
export interface IRSFormUploadData {
load_metadata: boolean
file: File
fileName: string
}
2023-09-11 20:31:54 +03:00
// ========== API =================
export function extractGlobals(expression: string): Set<string> {
return new Set(expression.match(/[XCSADFPT]\d+/g) ?? []);
}
2023-09-11 20:31:54 +03:00
export function loadRSFormData(schema: IRSFormData): IRSForm {
const result = schema as IRSForm
2023-07-29 21:23:18 +03:00
result.graph = new Graph;
if (!result.items) {
result.stats = {
2023-07-25 20:27:29 +03:00
count_all: 0,
count_errors: 0,
count_property: 0,
count_incalc: 0,
count_termin: 0,
2023-08-27 15:39:49 +03:00
count_definition: 0,
count_convention: 0,
2023-07-25 20:27:29 +03:00
count_base: 0,
count_constant: 0,
count_structured: 0,
count_axiom: 0,
count_term: 0,
count_function: 0,
count_predicate: 0,
count_theorem: 0
2023-07-20 17:11:03 +03:00
}
return result;
2023-07-25 20:27:29 +03:00
}
result.stats = {
2023-07-29 21:23:18 +03:00
count_all: result.items.length || 0,
count_errors: result.items.reduce(
2023-07-25 20:27:29 +03:00
(sum, cst) => sum + (cst.parse?.status === ParsingStatus.INCORRECT ? 1 : 0) || 0, 0),
2023-07-29 21:23:18 +03:00
count_property: result.items.reduce(
2023-07-25 20:27:29 +03:00
(sum, cst) => sum + (cst.parse?.valueClass === ValueClass.PROPERTY ? 1 : 0) || 0, 0),
2023-07-29 21:23:18 +03:00
count_incalc: result.items.reduce(
2023-07-25 20:27:29 +03:00
(sum, cst) => sum +
((cst.parse?.status === ParsingStatus.VERIFIED && cst.parse?.valueClass === ValueClass.INVALID) ? 1 : 0) || 0, 0),
2023-07-29 21:23:18 +03:00
count_termin: result.items.reduce(
(sum, cst) => (sum + (cst.term_raw ? 1 : 0) || 0), 0),
2023-08-27 15:39:49 +03:00
count_definition: result.items.reduce(
(sum, cst) => (sum + (cst.definition_raw ? 1 : 0) || 0), 0),
2023-08-27 15:39:49 +03:00
count_convention: result.items.reduce(
(sum, cst) => (sum + (cst.convention ? 1 : 0) || 0), 0),
2023-07-25 20:27:29 +03:00
2023-07-29 21:23:18 +03:00
count_base: result.items.reduce(
(sum, cst) => sum + (cst.cst_type === CstType.BASE ? 1 : 0), 0),
2023-07-29 21:23:18 +03:00
count_constant: result.items?.reduce(
(sum, cst) => sum + (cst.cst_type === CstType.CONSTANT ? 1 : 0), 0),
2023-07-29 21:23:18 +03:00
count_structured: result.items?.reduce(
(sum, cst) => sum + (cst.cst_type === CstType.STRUCTURED ? 1 : 0), 0),
2023-07-29 21:23:18 +03:00
count_axiom: result.items?.reduce(
(sum, cst) => sum + (cst.cst_type === CstType.AXIOM ? 1 : 0), 0),
2023-07-29 21:23:18 +03:00
count_term: result.items.reduce(
(sum, cst) => sum + (cst.cst_type === CstType.TERM ? 1 : 0), 0),
2023-07-29 21:23:18 +03:00
count_function: result.items.reduce(
(sum, cst) => sum + (cst.cst_type === CstType.FUNCTION ? 1 : 0), 0),
2023-07-29 21:23:18 +03:00
count_predicate: result.items.reduce(
(sum, cst) => sum + (cst.cst_type === CstType.PREDICATE ? 1 : 0), 0),
2023-07-29 21:23:18 +03:00
count_theorem: result.items.reduce(
(sum, cst) => sum + (cst.cst_type === CstType.THEOREM ? 1 : 0), 0)
2023-07-25 20:27:29 +03:00
}
2023-07-29 21:23:18 +03:00
result.items.forEach(cst => {
cst.status = inferStatus(cst.parse.status, cst.parse.valueClass);
cst.is_template = inferTemplate(cst.definition_formal);
cst.cst_class = inferClass(cst.cst_type, cst.is_template);
2023-07-29 21:23:18 +03:00
result.graph.addNode(cst.id);
const dependencies = extractGlobals(cst.definition_formal);
2023-07-29 21:23:18 +03:00
dependencies.forEach(value => {
2023-07-29 23:00:03 +03:00
const source = schema.items.find(cst => cst.alias === value)
if (source) {
result.graph.addEdge(source.id, cst.id);
2023-07-29 21:23:18 +03:00
}
});
});
return result;
2023-07-20 17:11:03 +03:00
}
export function matchConstituenta(target: IConstituenta, query: string, mode: CstMatchMode): boolean {
2023-10-04 18:46:52 +03:00
const matcher = new TextMatcher(query);
if ((mode === CstMatchMode.ALL || mode === CstMatchMode.NAME) &&
2023-10-04 18:46:52 +03:00
matcher.test(target.alias)) {
2023-07-25 20:27:29 +03:00
return true;
}
if ((mode === CstMatchMode.ALL || mode === CstMatchMode.TERM) &&
2023-10-04 18:46:52 +03:00
matcher.test(target.term_resolved)) {
2023-07-25 20:27:29 +03:00
return true;
}
if ((mode === CstMatchMode.ALL || mode === CstMatchMode.EXPR) &&
2023-10-04 18:46:52 +03:00
matcher.test(target.definition_formal)) {
2023-08-01 20:14:03 +03:00
return true;
}
if ((mode === CstMatchMode.ALL || mode === CstMatchMode.TEXT)) {
2023-10-04 18:46:52 +03:00
return (matcher.test(target.definition_resolved) || matcher.test(target.convention));
}
return false;
2023-08-01 20:14:03 +03:00
}
2023-09-11 20:31:54 +03:00
export function inferStatus(parse?: ParsingStatus, value?: ValueClass): ExpressionStatus {
if (!parse || !value) {
return ExpressionStatus.UNDEFINED;
}
if (parse === ParsingStatus.UNDEF) {
return ExpressionStatus.UNKNOWN;
2023-07-25 20:27:29 +03:00
}
2023-09-11 20:31:54 +03:00
if (parse === ParsingStatus.INCORRECT) {
return ExpressionStatus.INCORRECT;
}
if (value === ValueClass.INVALID) {
return ExpressionStatus.INCALCULABLE;
}
if (value === ValueClass.PROPERTY) {
return ExpressionStatus.PROPERTY;
}
return ExpressionStatus.VERIFIED;
2023-07-25 20:27:29 +03:00
}
2023-09-11 20:31:54 +03:00
export function inferTemplate(expression: string): boolean {
const match = expression.match(/R\d+/g);
return (match && match?.length > 0) ?? false;
}
export function inferClass(type: CstType, isTemplate: boolean): CstClass {
if (isTemplate) {
return CstClass.TEMPLATE;
}
2023-09-11 20:31:54 +03:00
switch (type) {
case CstType.BASE: return CstClass.BASIC;
case CstType.CONSTANT: return CstClass.BASIC;
case CstType.STRUCTURED: return CstClass.BASIC;
case CstType.TERM: return CstClass.DERIVED;
case CstType.FUNCTION: return CstClass.DERIVED;
case CstType.AXIOM: return CstClass.STATEMENT;
case CstType.PREDICATE: return CstClass.DERIVED;
case CstType.THEOREM: return CstClass.STATEMENT;
}
2023-09-11 20:31:54 +03:00
}
export function isMockCst(cst: IConstituenta) {
return cst.id <= 0;
}
2023-09-21 14:58:01 +03:00
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: []
}
};
}
2023-11-04 01:29:21 +03:00
export function applyFilterCategory(target: IConstituenta, schema: IRSFormData): IConstituenta[] {
const nextCategory = schema.items.find(
cst => (
cst.order > target.order &&
cst.cst_type === CATEGORY_CST_TYPE
)
);
return schema.items.filter(
cst => (
cst.order > target.order &&
(!nextCategory || cst.order <= nextCategory.order)
)
);
}