Compare commits

...

5 Commits

Author SHA1 Message Date
Ivan
0149f98c8b F: Add schemas coloring option for TermGraph
Some checks failed
Backend CI / build (3.12) (push) Has been cancelled
Frontend CI / build (22.x) (push) Has been cancelled
2024-09-14 17:11:26 +03:00
Ivan
d33f3e02b4 B: Fix buttons layers 2024-09-14 16:13:51 +03:00
Ivan
3555db3edf R: Add inherited cst source to API 2024-09-14 15:14:48 +03:00
Ivan
fc669b8b3a M: Shorten manuals landing page 2024-09-13 13:31:03 +03:00
Ivan
495493bbbb B: Fix incorrect local variable index parsing 2024-09-13 12:17:39 +03:00
32 changed files with 275 additions and 184 deletions

View File

@ -58,7 +58,6 @@ class TestChangeAttributes(EndpointTester):
self.operation3.refresh_from_db() self.operation3.refresh_from_db()
self.ks3 = RSForm(self.operation3.result) self.ks3 = RSForm(self.operation3.result)
@decl_endpoint('/api/library/{item}/set-owner', method='patch') @decl_endpoint('/api/library/{item}/set-owner', method='patch')
def test_set_owner(self): def test_set_owner(self):
data = {'user': self.user3.pk} data = {'user': self.user3.pk}

View File

@ -57,6 +57,33 @@ class TestChangeConstituents(EndpointTester):
self.ks3 = RSForm(self.operation3.result) self.ks3 = RSForm(self.operation3.result)
self.assertEqual(self.ks3.constituents().count(), 4) self.assertEqual(self.ks3.constituents().count(), 4)
@decl_endpoint('/api/rsforms/{item}/details', method='get')
def test_retrieve_inheritance(self):
response = self.executeOK(item=self.ks3.model.pk)
self.assertEqual(response.data['oss'], [{'id': self.owned.model.pk, 'alias': 'T1'}])
self.assertEqual(response.data['inheritance'], [
{
'child': Constituenta.objects.get(as_child__parent_id=self.ks1X1.pk).pk,
'child_source': self.ks3.model.pk,
'parent': self.ks1X1.pk, 'parent_source': self.ks1.model.pk
},
{
'child': Constituenta.objects.get(as_child__parent_id=self.ks1X2.pk).pk,
'child_source': self.ks3.model.pk,
'parent': self.ks1X2.pk, 'parent_source': self.ks1.model.pk
},
{
'child': Constituenta.objects.get(as_child__parent_id=self.ks2X1.pk).pk,
'child_source': self.ks3.model.pk,
'parent': self.ks2X1.pk, 'parent_source': self.ks2.model.pk
},
{
'child': Constituenta.objects.get(as_child__parent_id=self.ks2D1.pk).pk,
'child_source': self.ks3.model.pk,
'parent': self.ks2D1.pk, 'parent_source': self.ks2.model.pk
},
])
@decl_endpoint('/api/rsforms/{schema}/create-cst', method='post') @decl_endpoint('/api/rsforms/{schema}/create-cst', method='post')
def test_create_constituenta(self): def test_create_constituenta(self):
data = { data = {

View File

@ -4,6 +4,7 @@ from .basics import (
ASTNodeSerializer, ASTNodeSerializer,
ExpressionParseSerializer, ExpressionParseSerializer,
ExpressionSerializer, ExpressionSerializer,
InheritanceDataSerializer,
MultiFormSerializer, MultiFormSerializer,
ResolverSerializer, ResolverSerializer,
TextSerializer, TextSerializer,

View File

@ -122,6 +122,14 @@ class ReferenceSerializer(serializers.Serializer):
pos_output = TextPositionSerializer() pos_output = TextPositionSerializer()
class InheritanceDataSerializer(serializers.Serializer):
''' Serializer: inheritance data. '''
child = serializers.IntegerField()
child_source = serializers.IntegerField()
parent = serializers.IntegerField() # type: ignore
parent_source = serializers.IntegerField()
class ResolverSerializer(serializers.Serializer): class ResolverSerializer(serializers.Serializer):
''' Serializer: Resolver results serializer. ''' ''' Serializer: Resolver results serializer. '''
input = serializers.CharField() input = serializers.CharField()

View File

@ -17,7 +17,7 @@ from apps.oss.models import Inheritance
from shared import messages as msg from shared import messages as msg
from ..models import Constituenta, CstType, RSForm from ..models import Constituenta, CstType, RSForm
from .basics import CstParseSerializer from .basics import CstParseSerializer, InheritanceDataSerializer
from .io_pyconcept import PyConceptAdapter from .io_pyconcept import PyConceptAdapter
@ -103,7 +103,7 @@ class RSFormSerializer(serializers.ModelSerializer):
child=CstSerializer() child=CstSerializer()
) )
inheritance = serializers.ListField( inheritance = serializers.ListField(
child=serializers.ListField(child=serializers.IntegerField()) child=InheritanceDataSerializer()
) )
oss = serializers.ListField( oss = serializers.ListField(
child=LibraryItemReferenceSerializer() child=LibraryItemReferenceSerializer()
@ -116,8 +116,17 @@ class RSFormSerializer(serializers.ModelSerializer):
def to_representation(self, instance: LibraryItem) -> dict: def to_representation(self, instance: LibraryItem) -> dict:
result = self.to_base_data(instance) result = self.to_base_data(instance)
for link in Inheritance.objects.filter(Q(child__schema=instance) | Q(parent__schema=instance)): inheritances = Inheritance.objects \
result['inheritance'].append([link.child.pk, link.parent.pk]) .filter(Q(child__schema=instance) | Q(parent__schema=instance)) \
.select_related('parent__schema', 'child__schema') \
.only('parent__id', 'parent__schema__id', 'child__id', 'child__schema__id')
for link in inheritances:
result['inheritance'].append({
'child': link.child_id,
'child_source': link.child.schema_id,
'parent': link.parent_id,
'parent_source': link.parent.schema_id
})
return result return result
def to_base_data(self, instance: LibraryItem) -> dict: def to_base_data(self, instance: LibraryItem) -> dict:

View File

@ -1,7 +1,6 @@
import { styleTags, tags } from '@lezer/highlight'; import { styleTags, tags } from '@lezer/highlight';
export const highlighting = styleTags({ export const highlighting = styleTags({
'Index': tags.unit,
'ComplexIndex': tags.unit, 'ComplexIndex': tags.unit,
'Literal': tags.literal, 'Literal': tags.literal,

View File

@ -2,15 +2,14 @@
export const export const
Expression = 1, Expression = 1,
Local = 2, Local = 2,
Index = 3, Literal = 4,
Literal = 5, Global = 5,
Global = 6, Radical = 6,
Radical = 7, Filter = 19,
Filter = 20, ComplexIndex = 20,
ComplexIndex = 21, PrefixD = 25,
PrefixD = 26, PrefixI = 26,
PrefixI = 27, PrefixR = 28,
PrefixR = 29, Function = 30,
Function = 31, TextFunction = 31,
TextFunction = 32, Predicate = 44
Predicate = 45

View File

@ -3,7 +3,7 @@ import { printTree } from '@/utils/codemirror';
import { parser } from './parser'; import { parser } from './parser';
const testData = [ const testData = [
['a1', '[Expression[Local[Index]]]'], ['a1', '[Expression[Local]]'],
['A1', '[Expression[Global]]'], ['A1', '[Expression[Global]]'],
['∅', '[Expression[Literal]]'], ['∅', '[Expression[Literal]]'],
['Z', '[Expression[Literal]]'], ['Z', '[Expression[Literal]]'],
@ -15,7 +15,7 @@ const testData = [
['¬2=2', '[Expression[¬][Literal][=][Literal]]'], ['¬2=2', '[Expression[¬][Literal][=][Literal]]'],
['12+41', '[Expression[Literal][+][Literal]]'], ['12+41', '[Expression[Literal][+][Literal]]'],
['1+2*5', '[Expression[Literal][+][Literal][*][Literal]]'], ['1+2*5', '[Expression[Literal][+][Literal][*][Literal]]'],
['a1Z', '[Expression[Local[Index]][][Literal]]'], ['a1Z', '[Expression[Local][][Literal]]'],
['Pr1(X1)', '[Expression[TextFunction[ComplexIndex]][(][Global][)]]'], ['Pr1(X1)', '[Expression[TextFunction[ComplexIndex]][(][Global][)]]'],
['Pr11(X1)', '[Expression[TextFunction[ComplexIndex]][(][Global][)]]'], ['Pr11(X1)', '[Expression[TextFunction[ComplexIndex]][(][Global][)]]'],
['Pr11,21(X1)', '[Expression[TextFunction[ComplexIndex]][(][Global][)]]'], ['Pr11,21(X1)', '[Expression[TextFunction[ComplexIndex]][(][Global][)]]'],
@ -41,8 +41,9 @@ const testData = [
['∀ξ∈∅ 1=1', '[Expression[∀][Local][∈][Literal][Literal][=][Literal]]'], ['∀ξ∈∅ 1=1', '[Expression[∀][Local][∈][Literal][Literal][=][Literal]]'],
[ [
'∀ξ1∈β (ξ1≠∅ & ∀ξ2∈β ξ1∩ξ2=∅)', '∀ξ1∈β (ξ1≠∅ & ∀ξ2∈β ξ1∩ξ2=∅)',
'[Expression[∀][Local[Index]][∈][Local][(][Local[Index]][≠][Literal][&][∀][Local[Index]][∈][Local][Local[Index]][∩][Local[Index]][=][Literal][)]]' '[Expression[∀][Local][∈][Local][(][Local][≠][Literal][&][∀][Local][∈][Local][Local][∩][Local][=][Literal][)]]'
] ],
['∀α1∈α2 1=1', '[Expression[∀][Local][∈][Local][Literal][=][Literal]]']
]; ];
describe('Testing RSParser', () => { describe('Testing RSParser', () => {

View File

@ -3,16 +3,16 @@ import {LRParser} from "@lezer/lr"
import {highlighting} from "./highlight" import {highlighting} from "./highlight"
export const parser = LRParser.deserialize({ export const parser = LRParser.deserialize({
version: 14, version: 14,
states: "5lO!sQPOOO!zQPO'#C^OOQO'#Ca'#CaO%uQPO'#DqOOQO'#Dq'#DqO(SQPO'#DeOVQPO'#DrO(ZQPO'#DtO)kQPO'#DuO)sQQO'#DvO)xQPO'#DwO)}QPO'#DxO*SQPO'#DzOOQO'#Ds'#DsO*XQPO'#DsO+uQQO'#C|OOQO'#C|'#C|OOQO'#Dn'#DnO+zQPO'#DnO,PQPO'#DnO,UQPO'#DgOVQPO'#ESO,^QPO'#ESO,cQPO'#ESO,kQPO'#DeOOQO'#Df'#DfO,fQPO'#EVQOQPOOOOQO'#C_'#C_OOQO,58x,58xO(ZQPO,5:^O(ZQPO,5:^O(ZQPO,5:^O(ZQPO,5:^O(ZQPO,5:^O(ZQPO,5:^O(ZQPO,5:^O(ZQPO,5:^O(ZQPO,5:RO,|QPO'#DmO-TQPO,5:^O.hQPO,5:VO.pQPO'#DlO.uQPO,5:QO/WQPO,5:cO/yQPO'#DmO(ZQPO'#DrO0WQPO,5:`OOQO'#Dm'#DmO(ZQPO,5:aOOQO,5:a,5:aO0`QPO,5:bO,cQPO,5:cO(ZQPO,5:dO,cQPO,5:fOOQO,59h,59hO(ZQPO,5:YO(ZQPO,5:YO&uQPO'#DgOOQO,5:n,5:nO(ZQPO,5:nO(ZQPO'#DkOOQO'#Dh'#DhOOQO'#ET'#ETO0eQPO,5:nOVQPO,5:pOVQPO,5:pOVQPO,5:pOVQPO,5:pO0mQPO'#EXOOQO'#EW'#EWO0rQPO,5:qOOQO1G/x1G/xO2wQPO1G/xO3OQPO1G/xO5SQPO1G/xO7WQPO1G/xO7_QPO1G/xO7fQPO1G/xO8OQPO1G/xO9qQPO1G/mOOQO1G/q1G/qO(ZQPO,5:WOOQO1G/l1G/lO(ZQPO1G/}OOQO1G/z1G/zO:bQPO1G/{O(ZQPO1G/|O:iQPO1G/}O:nQPO1G0OO:uQPO1G0QO:zQPO1G/tO;SQPO1G/tO;ZQPO1G0YO,cQPO,5:oO;cQPO1G0YOOQO1G0[1G0[O=_QPO1G0[O=fQPO1G0[O=mQPO1G0[O(ZQPO,5:sO,fQPO,5:rOVQPO1G0]O>[QPO1G/rO>lQPO7+%iOOQO7+%g7+%gO>sQPO7+%hO(ZQPO7+%iOVQPO7+%jO(ZQPO7+%lOOQO7+%`7+%`OOQO7+%t7+%tOOQO1G0Z1G0ZOOQO'#C^'#C^O>{QPO7+%tO?iQPO1G0_OOQO1G0^1G0^OOQO7+%w7+%wOVQPO<<ITO?sQPO<<ISO?xQPO<<ITO@PQPO'#DyO@eQPO<<IUO@mQPO<<IWO@tQPO<<I`OAcQPOAN>oO(ZQPOAN>nOVQPOAN>oOVQPO,5:eOOQOAN>pAN>pOVQPOAN>rOOQOG24ZG24ZOAtQPOG24YOA{QPOG24ZOB^QPO1G0POBrQPOG24^OByQPOG24^OOQOLD)tLD)tOOQOLD)uLD)uOOQOLD)xLD)xO(ZQPOLD)xOC[QPO!$'MdOOQO!)9CO!)9COO;cQPO,5:^O;cQPO,5:^O;cQPO,5:^O;cQPO,5:^O;cQPO,5:^O;cQPO,5:^O;cQPO,5:^O;cQPO,5:^OCcQPO1G/xOE[QPO1G/xOIWQPO1G/xOKbQPO1G/xOKiQPO1G/xOKpQPO1G/xOKwQPO1G/x", states: "3UO!sQPOOOOQO'#C`'#C`O#lQPO'#DoOOQO'#Do'#DoO%yQPO'#DdOVQPO'#DpO'_QPO'#DrO'fQPO'#DsO'nQQO'#DtO'sQPO'#DuO'xQPO'#DvO'}QPO'#DxOOQO'#Dq'#DqO(SQPO'#DqO)pQQO'#C{OOQO'#C{'#C{OOQO'#Dk'#DkO)uQPO'#DkO)zQPO'#DkO*PQPO'#DfOVQPO'#EQO*XQPO'#EQO*^QPO'#EQO*fQPO'#DdOOQO'#De'#DeO*wQPO'#ETQOQPOOO*|QPO,5:[O*|QPO,5:[O*|QPO,5:[O*|QPO,5:[O*|QPO,5:[O*|QPO,5:[O*|QPO,5:[O*|QPO,5:[O*|QPO,5:QO+TQPO'#DjO+[QPO,5:[O,oQPO,5:SO,wQPO'#DiO,|QPO,5:PO-_QPO,5:aO.QQPO'#DjO*|QPO'#DpO._QPO,5:^OOQO'#Dj'#DjO*|QPO,5:_OOQO,5:_,5:_O.gQPO,5:`O*^QPO,5:aO*|QPO,5:bO*^QPO,5:dOOQO,59g,59gO*|QPO,5:VO*|QPO,5:VO$lQPO'#DfOOQO,5:l,5:lO*|QPO,5:lO*|QPO'#DhOOQO'#Dg'#DgOOQO'#ER'#ERO.lQPO,5:lOVQPO,5:nOVQPO,5:nOVQPO,5:nOVQPO,5:nO.tQPO'#EVOOQO'#EU'#EUO.yQPO,5:oOOQO1G/v1G/vO2jQPO1G/vO2qQPO1G/vO6aQPO1G/vO:PQPO1G/vO:WQPO1G/vO:_QPO1G/vO:fQPO1G/vO>QQPO1G/lOOQO1G/n1G/nO*|QPO,5:TOOQO1G/k1G/kO*|QPO1G/{OOQO1G/x1G/xO>qQPO1G/yO*|QPO1G/zO>xQPO1G/{O>}QPO1G/|O?UQPO1G0OO?ZQPO1G/qO?cQPO1G/qO?jQPO1G0WO*^QPO,5:mO*|QPO1G0WOOQO1G0Y1G0YO@^QPO1G0YO@eQPO1G0YO@lQPO1G0YO*|QPO,5:qO*wQPO,5:pOVQPO1G0ZOAZQPO1G/oOAkQPO7+%gOOQO7+%e7+%eOArQPO7+%fO*|QPO7+%gOVQPO7+%hO*|QPO7+%jOOQO7+%]7+%]OOQO7+%r7+%rOOQO1G0X1G0XOAzQPO7+%rOBhQPO1G0]OOQO1G0[1G0[OOQO7+%u7+%uOVQPO<<IROBrQPO<<IQOBwQPO<<IROCOQPO'#DwOCdQPO<<ISOClQPO<<IUOCsQPO<<I^ODbQPOAN>mO*|QPOAN>lOVQPOAN>mOVQPO,5:cOOQOAN>nAN>nOVQPOAN>pOOQOG24XG24XODsQPOG24WODzQPOG24XOE]QPO1G/}OEqQPOG24[OExQPOG24[OOQOLD)rLD)rOOQOLD)sLD)sOOQOLD)vLD)vO*|QPOLD)vOFZQPO!$'MbOOQO!)9B|!)9B|",
stateData: "NR~O!WOS~OSUOUSOVSOaVOcWOdXOjYOkZOm[OobO|eO}fO!OgO!PgO!]PO!^QO!cQO!dQO!o_O!p_O!q`O!r`O!s`O!t`O~OfjO~PVO!^lOWQXXQXYQXZQX[QX]QX^QX_QXhQXnQXqQXrQXsQXtQXuQXvQXwQXxQXyQXzQX{QX!UQX!uQXbQX!QQX!RQX!SQX!TQX`QXiQXgQXlQX~OW!eXX!eXY!eXZ!eX[!eX]!eX^!eX_!eX!u!eXb!eX~Oh!eXn![Xq![Xr!eXs!eXt!eXu!eXv!eXw!eXx!eXy!eXz!eX{!eX!U!eX~P%TOWnOXoOYpOZqO[rO]sO^tO_uOhvOrvOsvOtvOuvOvvOwvOxvOyvOzvO{vO~O!U!XX~P&uOS!OOUSOVSOaVOcWOdXOjYOkZOm[OobO!]PO!^QO!cQO!dQO!o_O!p_O!q`O!r`O!s`O!t`O~OS!ROcWO~Oe!TO~Oa!UO~Oa!VO~Oa!WO~OW!gXX!gXY!gXZ!gX[!gX]!gX^!gX_!gXh!gXn![Xq![Xr!gXs!gXt!gXu!gXv!gXw!gXx!gXy!gXz!gX{!gX!U!gX!u!gXb!gX~Oe!XO~Of!YO~OS!ZO~OnvOqvO~Of!^O~OS!_O!]PO~O!Q!cO!R!dO!S!eO!T!fO!U!XX~O!u!aX~P&uO`!jOW!bXX!bXY!bXZ!bX[!bX]!bX^!bX_!bXh!bXr!bXs!bXt!bXu!bXv!bXw!bXx!bXy!bXz!bX{!bX!u!bX~O`!sO!u!aX~O!u!tO~O`!uO!Q!cO!R!dO!S!eO!T!fO~Oh!vO~P%TOWnOXoOYpOZqO[rO]sO^tO_uO~Ob!aX!u!aXg!aX~P/_Ob!wO!u!tO~Of!yO~Oh#RO!u#QO~Oh#WO~Og#YO!u#XO~OWnOY!fiZ!fi[!fi]!fi^!fi_!fih!fir!fis!fit!fiu!fiv!fiw!fix!fiy!fiz!fi{!fi!U!fi`!fi!u!fib!fi!Q!fi!R!fi!S!fi!T!fii!fig!fil!fi~OX!fi~P0zOXoO~P0zOWnOXoOYpO_uO[!fi]!fi^!fih!fir!fis!fit!fiu!fiv!fiw!fix!fiy!fiz!fi{!fi!U!fi`!fi!u!fib!fi!Q!fi!R!fi!S!fi!T!fii!fig!fil!fi~OZ!fi~P3VOWnOXoOYpOZqO^tO_uO]!fih!fir!fis!fit!fiu!fiv!fiw!fix!fiy!fiz!fi{!fi!U!fi`!fi!u!fib!fi!Q!fi!R!fi!S!fi!T!fii!fig!fil!fi~O[!fi~P5ZO[rO~P5ZOZqO~P3VOZ!fi[!fi]!fi^!fi_!fi~OWnOXoOYpOh!fir!fis!fit!fiu!fiv!fiw!fix!fiy!fiz!fi{!fi!U!fi`!fi!u!fib!fi!Q!fi!R!fi!S!fi!T!fii!fig!fil!fi~P7mO!Q!Zi!R!Zi!S!Zi!T!Zi!U!Zi`!Zib!Zil!Zii!Zi~P/_O`#]O~P/_Oh#_O~Oi#`O~P/_On#aO~Og#bO!u!tO~O`#bO~P/_Og#cO!u!tO~OS!OOUSOVSOaVOcWOdXOjYOkZOm[OobO!]#eO!^QO!cQO!dQO!o_O!p_O!q`O!r`O!s`O!t`O~O!Q!cO!S!xi!T!xi!U!xi`!xib!xil!xii!xi~O!R!xi~P<sO!R!dO~P<sO!Q!cO!R!dO!S!eO!T!xi!U!xi`!xib!xil!xii!xi~O`!`i!u!`ib!`ig!`i~P/_Oi#jO~P/_Og#kO!u!tO~OW$TOX$UOY$VOZ$WO[$XO]$YO^$ZO_$[O~PVOg!{i!u!{i~P/_OS#rO~Oi#sO~P/_O!Q!cO!R!dO!S!eO!T!fOb!mXl!mX~Ob#uOl#tO~Oi#vO~P/_O!Q!cO!R!dO!S!eO!T!fO!U!vy`!vyb!vyl!vyi!vy~Ob#wO!Q!cO!R!dO!S!eO!T!fO~O`#}O~P/_Ob$OO!Q!cO!R!dO!S!eO!T!fO~O!Q!cO!R!dO!S!eO!T!fOb!mil!mi~Ob$PO~P&uOi$QO!Q!cO!R!dO!S!eO!T!fO~Ob$SO~P/_OW$TOS!fiU!fiV!fiX!fiY!fia!fic!fid!fij!fik!fim!fio!fi|!fi}!fi!O!fi!P!fi!]!fi!^!fi!c!fi!d!fi!o!fi!p!fi!q!fi!r!fi!s!fi!t!fi~P7mOW$TOX$UOS!fiU!fiV!fiY!fia!fic!fid!fij!fik!fim!fio!fi|!fi}!fi!O!fi!P!fi!]!fi!^!fi!c!fi!d!fi!o!fi!p!fi!q!fi!r!fi!s!fi!t!fi~P7mOW$TOX$UOY$VO_$[OS!fiU!fiV!fi[!fi]!fi^!fia!fic!fid!fij!fik!fim!fio!fi|!fi}!fi!O!fi!P!fi!]!fi!^!fi!c!fi!d!fi!o!fi!p!fi!q!fi!r!fi!s!fi!t!fi~OZ!fi~PGTOW$TOX$UOY$VOZ$WO^$ZO_$[OS!fiU!fiV!fi]!fia!fic!fid!fij!fik!fim!fio!fi|!fi}!fi!O!fi!P!fi!]!fi!^!fi!c!fi!d!fi!o!fi!p!fi!q!fi!r!fi!s!fi!t!fi~O[!fi~PI_O[$XO~PI_OZ$WO~PGTOW$TOX$UOY$VOS!fiU!fiV!fia!fic!fid!fij!fik!fim!fio!fi|!fi}!fi!O!fi!P!fi!]!fi!^!fi!c!fi!d!fi!o!fi!p!fi!q!fi!r!fi!s!fi!t!fi~P7mOd!o}oUV!q!r!s!t!p!]mkjk~", stateData: "Fs~O!VOS~OQQORTOTROURO`UObVOcWOiXOjYOlZOnaO{dO|eO}fO!OfO!`PO!aPO!bPO!m^O!n^O!o_O!p_O!q_O!r_O~OeiO~PVOV!cXW!cXX!cXY!cXZ!cX[!cX]!cX^!cX!s!cXa!cX~Og!cXm!ZXp!ZXq!cXr!cXs!cXt!cXu!cXv!cXw!cXx!cXy!cXz!cX!T!cX~P!zOVkOWlOXmOYnOZoO[pO]qO^rOgsOqsOrsOssOtsOusOvsOwsOxsOysOzsO~O!T!WX~P$lOR{OTROURO`UObVOcWOiXOjYOlZOnaO!`PO!aPO!bPO!m^O!n^O!o_O!p_O!q_O!r_O~OQyO~P&QOR!OObVO~Od!QO~O`!RO~O`!SO~O`!TO~OV!eXW!eXX!eXY!eXZ!eX[!eX]!eX^!eXg!eXm!ZXp!ZXq!eXr!eXs!eXt!eXu!eXv!eXw!eXx!eXy!eXz!eX!T!eX!s!eXa!eX~Od!UO~Oe!VO~OR!WO~OmsOpsO~Oe!ZO~OQ!]OR![O~O!P!`O!Q!aO!R!bO!S!cO!T!WX~OQ!dO~OQRO~P&QO!s!^X~P$lO_!gOV!_XW!_XX!_XY!_XZ!_X[!_X]!_X^!_Xg!_Xq!_Xr!_Xs!_Xt!_Xu!_Xv!_Xw!_Xx!_Xy!_Xz!_X!s!_X~O_!pO!s!^X~O!s!qO~O_!rO!P!`O!Q!aO!R!bO!S!cO~Og!sO~P!zOVkOWlOXmOYnOZoO[pO]qO^rO~Oa!^X!s!^Xf!^X~P-fOa!tO!s!qO~Oe!vO~Og#OO!s!}O~Og#TO~Of#VO!s#UO~OVkOX!diY!diZ!di[!di]!di^!dig!diq!dir!dis!dit!diu!div!diw!dix!diy!diz!di!T!di_!di!s!dia!di!P!di!Q!di!R!di!S!dih!dif!diQ!diR!diT!diU!di`!dib!dic!dii!dij!dil!din!di{!di|!di}!di!O!di!`!di!a!di!b!di!m!di!n!di!o!di!p!di!q!di!r!dik!di~OW!di~P/ROWlO~P/ROVkOWlOXmO^rOZ!di[!di]!dig!diq!dir!dis!dit!diu!div!diw!dix!diy!diz!di!T!di_!di!s!dia!di!P!di!Q!di!R!di!S!dih!dif!diQ!diR!diT!diU!di`!dib!dic!dii!dij!dil!din!di{!di|!di}!di!O!di!`!di!a!di!b!di!m!di!n!di!o!di!p!di!q!di!r!dik!di~OY!di~P2xOVkOWlOXmOYnO]qO^rO[!dig!diq!dir!dis!dit!diu!div!diw!dix!diy!diz!di!T!di_!di!s!dia!di!P!di!Q!di!R!di!S!dih!dif!diQ!diR!diT!diU!di`!dib!dic!dii!dij!dil!din!di{!di|!di}!di!O!di!`!di!a!di!b!di!m!di!n!di!o!di!p!di!q!di!r!dik!di~OZ!di~P6hOZoO~P6hOYnO~P2xOVkOWlOXmOY!diZ!di[!di]!di^!dig!diq!dir!dis!dit!diu!div!diw!dix!diy!diz!di!T!di_!di!s!dia!di!P!di!Q!di!R!di!S!dih!dif!diQ!diR!diT!diU!di`!dib!dic!dii!dij!dil!din!di{!di|!di}!di!O!di!`!di!a!di!b!di!m!di!n!di!o!di!p!di!q!di!r!dik!di~O!P!Yi!Q!Yi!R!Yi!S!Yi!T!Yi_!Yia!Yik!Yih!Yi~P-fO_#YO~P-fOg#[O~Oh#]O~P-fOm#^O~Of#_O!s!qO~O_#_O~P-fOf#`O!s!qO~O!P!`O!R!vi!S!vi!T!vi_!via!vik!vih!vi~O!Q!vi~P?rO!Q!aO~P?rO!P!`O!Q!aO!R!bO!S!vi!T!vi_!via!vik!vih!vi~O_!]i!s!]ia!]if!]i~P-fOh#fO~P-fOf#gO!s!qO~OVkOWlOXmOYnOZoO[pO]qO^rO~PVOf!yi!s!yi~P-fOR#nO~Oh#oO~P-fO!P!`O!Q!aO!R!bO!S!cOa!kXk!kX~Oa#qOk#pO~Oh#rO~P-fO!P!`O!Q!aO!R!bO!S!cO!T!ty_!tya!tyk!tyh!ty~Oa#sO!P!`O!Q!aO!R!bO!S!cO~O_#yO~P-fOa#zO!P!`O!Q!aO!R!bO!S!cO~O!P!`O!Q!aO!R!bO!S!cOa!kik!ki~Oa#{O~P$lOh#|O!P!`O!Q!aO!R!bO!S!cO~Oa$OO~P-fOc!m|nTU!o!p!q!r!nQljij~",
goto: "0m!|PP!}$aP$dPPPPPPPPPPPPPPPPPPPPPPPPPP%hPPPPPPPPPPPPPPPPPPPPPP&l&r'l'|PP(j)v*R*dPP$d,x$d.O/S.O.O.O0Z.OPPPPPPP'l0^'l0a0d0glROUe!c!d!e!f#Y#`#f#j#s#t#v!dSnopqrstuv!O!R!V!Y!Z!^!_!t!v!y#R#W#_#a#r$Q$T$U$V$W$X$Y$Z$[Q|VW!`g!U!W#QT!gj#XRmP#TaOUVenopqrstuv!O!R!V!Y!Z!^!_!c!d!e!f!t!v!y#R#W#Y#_#`#a#f#j#r#s#t#v$Q$T$U$V$W$X$Y$Z$[#TcOUVenopqrstuv!O!R!V!Y!Z!^!_!c!d!e!f!t!v!y#R#W#Y#_#`#a#f#j#r#s#t#v$Q$T$U$V$W$X$Y$Z$[QkOR#i#YShO#YQ{UQ!]eQ#S!cQ#T!dQ#U!eQ#V!fQ#m#`Q#p#fQ#q#jQ#y#sQ#z#tR#|#vmiOUe!c!d!e!f#Y#`#f#j#s#t#vldOUe!c!d!e!f#Y#`#f#j#s#t#vQ!agQ!z!UQ!|!WR#d#Q!f]Vnopqrstuv!O!R!V!Y!Z!^!_!t!v!y#R#W#_#a#r$Q$T$U$V$W$X$Y$Z$[l^OUe!c!d!e!f#Y#`#f#j#s#t#vX!`g!U!W#QUyU!O!_X!QV!Y!^!yUzU!O!_Q!PVQ!}!YQ#P!^R#^!ySTO#YQwU[}V!O!Y!^!_!yd![e!c!d!e!f#`#f#j#s#tS!jn$TQ!koQ!lpQ!mqQ!nrQ!osQ!ptQ!quQ!rvQ!x!RQ!{!VQ#O!ZQ#Z!tQ#[!vQ#f#RQ#g#WQ#l#_Q#o#aQ#x#rQ#{#vQ$R$QQ$]$UQ$^$VQ$_$WQ$`$XQ$a$YQ$b$ZR$c$[#OaOVenopqrstuv!R!V!Y!Z!^!_!c!d!e!f!t!v!y#R#W#Y#_#`#a#f#j#r#s#t#v$Q$T$U$V$W$X$Y$Z$[TxU!O#T]OUVenopqrstuv!O!R!V!Y!Z!^!_!c!d!e!f!t!v!y#R#W#Y#_#`#a#f#j#r#s#t#v$Q$T$U$V$W$X$Y$Z$[#S]OUVenopqrstuv!O!R!V!Y!Z!^!_!c!d!e!f!t!v!y#R#W#Y#_#`#a#f#j#r#s#t#v$Q$T$U$V$W$X$Y$Z$[R!SWR#n#`R!bgRkOR!ijQ!hjR#h#X", goto: "-l!zPPPP!{PPPPPPPPPPPPPPPPPPPPPPPPPP#wPPPPPPPPPPPPPPPPPPPPPP$s$y%s&T&q'u(Q(cPPP!{*a!{+_,Z+_+_+_-Y+_PPPPPPP%s-]%s-`-c-f!s`OTUdklmnopqrs{!O!S!V!W!Z![!`!a!b!c!q!s!v#O#T#V#[#]#^#b#f#n#o#p#r#|!sbOTUdklmnopqrs{!O!S!V!W!Z![!`!a!b!c!q!s!v#O#T#V#[#]#^#b#f#n#o#p#r#|QjOR#e#VSgO#VQxTQ!YdQ#P!`Q#Q!aQ#R!bQ#S!cQ#i#]Q#l#bQ#m#fQ#u#oQ#v#pR#x#rmhOTd!`!a!b!c#V#]#b#f#o#p#rlcOTd!`!a!b!c#V#]#b#f#o#p#rQ!^fQ!w!RQ!y!TR#a!}!U[Uklmnopqrs{!O!S!V!W!Z![!q!s!v#O#T#[#^#n#|l]OTd!`!a!b!c#V#]#b#f#o#p#rX!]f!R!T!}UvT{![X}U!V!Z!vUwT{![Q|UQ!z!VQ!|!ZR#Z!vSSO#VQtT[zU{!V!Z![!vd!Xd!`!a!b!c#]#b#f#o#pQ!gkQ!hlQ!imQ!jnQ!koQ!lpQ!mqQ!nrQ!osQ!u!OQ!x!SQ!{!WQ#W!qQ#X!sQ#b#OQ#c#TQ#h#[Q#k#^Q#t#nQ#w#rR#}#|!n`OUdklmnopqrs!O!S!V!W!Z![!`!a!b!c!q!s!v#O#T#V#[#]#^#b#f#n#o#p#r#|TuT{!s[OTUdklmnopqrs{!O!S!V!W!Z![!`!a!b!c!q!s!v#O#T#V#[#]#^#b#f#n#o#p#r#|!r[OTUdklmnopqrs{!O!S!V!W!Z![!`!a!b!c!q!s!v#O#T#V#[#]#^#b#f#n#o#p#r#|R!PVR#j#]R!_fRjOR!fiQ!eiR#d#U",
nodeNames: "⚠ Expression Local Index ( Literal Global Radical + - * \\ ∆ ∩ × ) { } Filter ComplexIndex [ ] ∈ | PrefixD PrefixI ; PrefixR := Function TextFunction :∈ ∉ ⊆ ⊄ ⊂ > ≥ < ≤ ≠ = ¬ Predicate ∀ ∃ ⇔ ⇒ &", nodeNames: "⚠ Expression Local ( Literal Global Radical + - * \\ ∆ ∩ × ) { } Filter ComplexIndex [ ] ∈ | PrefixD PrefixI ; PrefixR := Function TextFunction :∈ ∉ ⊆ ⊄ ⊂ > ≥ < ≤ ≠ = ¬ Predicate ∀ ∃ ⇔ ⇒ &",
maxTerm: 89, maxTerm: 87,
propSources: [highlighting], propSources: [highlighting],
skippedNodes: [0], skippedNodes: [0],
repeatNodeCount: 0, repeatNodeCount: 0,
tokenData: "4i~R!jX^%spq%svw&hxy&myz&rz{&w{|&||}'R}!O'W!Q!R']!R!['e![!](T!]!^(h!^!_(m!_!`(r!`!a(w!c!d(|!e!f(|!f!g)[!h!i)d!k!l)z!r!s*P!t!u*g!u!v(|!v!w(|!z!{(|!|!}*w!}#O*|#O#P+R#P#Q+W#R#S+]#T#U+]#U#V+h#V#W,z#W#X.Z#X#d+]#d#e0a#e#f+]#f#g1P#g#o+]#o#p2Q#p#q2V#q#r2[#y#z%s$f$g%s$r$s2a%o%p2f5i6S+]#BY#BZ%s$IS$I_%s$I|$JO%s$JT$JU%s$KV$KW%s% l% m2k%%Y%%Z2p%%[%%]2u%&Y%&Z2z%&]%&^3P%&_%&`3U%&`%&a3Z%&b%&c3`%&c%&d3e%'S%'T3j%'T%'U3o%'U%'V3t%(^%(_3y%(b%(c4O%(c%(d4T%)Q%)R4Y%)S%)T4_%)U%)V4d&FU&FV%s~%xY!W~X^%spq%s#y#z%s$f$g%s#BY#BZ%s$IS$I_%s$I|$JO%s$JT$JU%s$KV$KW%s&FU&FV%s~&mO!T~~&rOS~~&wO`~~&|OY~~'ROW~~'WO!u~~']OX~P'bP!^P!Q![']R'lQeQ!^P|}'r!Q!['eQ'uP!R!['xQ'}QeQ|}'r!Q!['x~(WQ!_!`(^%&b%&c(c~(cOn~~(hOq~~(mOl~~(rOx~~(wO{~~(|Ov~~)PP!Q![)S~)XPU~!Q![)S~)aPj~!Q![)S~)gQ!Q![)m#]#^)u~)rPo~!Q![)m~)zOd~~*POk~~*SQ!Q![*Y#f#g*b~*_P}~!Q![*Y~*gO!o~~*lPm~!Q![*o~*tPV~!Q![*o~*|O!d~~+ROf~~+WO[~~+]Og~~+bQ!]~#T#o+]5i6S+]~+mS!]~#T#c+]#c#d+y#d#o+]5i6S+]~,OS!]~#T#c+]#c#d,[#d#o+]5i6S+]~,aS!]~#T#`+]#`#a,m#a#o+]5i6S+]~,tQ!r~!]~#T#o+]5i6S+]~-PR!]~#T#U-Y#U#o+]5i6S+]~-_S!]~#T#f+]#f#g-k#g#o+]5i6S+]~-pS!]~#T#W+]#W#X-|#X#o+]5i6S+]~.TQ!q~!]~#T#o+]5i6S+]~.`S!]~#T#X+]#X#Y.l#Y#o+]5i6S+]~.qS!]~#T#U+]#U#V.}#V#o+]5i6S+]~/SS!]~#T#c+]#c#d/`#d#o+]5i6S+]~/eS!]~#T#c+]#c#d/q#d#o+]5i6S+]~/vS!]~#T#`+]#`#a0S#a#o+]5i6S+]~0ZQ!s~!]~#T#o+]5i6S+]~0fS!]~#T#f+]#f#g0r#g#o+]5i6S+]~0yQ!p~!]~#T#o+]5i6S+]~1US!]~#T#X+]#X#Y1b#Y#o+]5i6S+]~1gS!]~#T#W+]#W#X1s#X#o+]5i6S+]~1zQ!t~!]~#T#o+]5i6S+]~2VOa~~2[Oi~~2aOb~~2fO|~~2kO_~~2pOc~~2uO!R~~2zO!Q~~3PO!O~~3UO!P~~3ZO!c~~3`O]~~3eOh~~3jOr~~3oO!S~~3tO^~~3yOZ~~4OOz~~4TOy~~4YOw~~4_Ou~~4dOt~~4iOs~", tokenData: "6P~R!jX^%spq%svw&hxy&myz&rz{&w{|&||}'R}!O'W!Q!R']!R!['e![!](T!]!^(h!^!_(m!_!`(r!`!a(w!c!d(|!e!f(|!f!g)[!h!i)d!k!l)z!r!s*P!t!u*g!u!v(|!v!w(|!z!{(|!|!}*w!}#O*|#O#P+R#P#Q+W#R#S+]#T#U+]#U#V+s#V#W-c#W#X/O#X#d+]#d#e1h#e#f+]#f#g2^#g#o+]#o#p3h#p#q3m#q#r3r#y#z%s$f$g%s$r$s3w%o%p3|5i6S+]#BY#BZ%s$IS$I_%s$I|$JO%s$JT$JU%s$KV$KW%s% l% m4R%%Y%%Z4W%%[%%]4]%&Y%&Z4b%&]%&^4g%&_%&`4l%&`%&a4q%&b%&c4v%&c%&d4{%'S%'T5Q%'T%'U5V%'U%'V5[%(^%(_5a%(b%(c5f%(c%(d5k%)Q%)R5p%)S%)T5u%)U%)V5z&FU&FV%s~%xY!V~X^%spq%s#y#z%s$f$g%s#BY#BZ%s$IS$I_%s$I|$JO%s$JT$JU%s$KV$KW%s&FU&FV%s~&mO!S~~&rOR~~&wO_~~&|OX~~'ROV~~'WO!s~~']OW~P'bP!`P!Q![']R'lQdQ!`P|}'r!Q!['eQ'uP!R!['xQ'}QdQ|}'r!Q!['x~(WQ!_!`(^%&b%&c(c~(cOm~~(hOp~~(mOk~~(rOw~~(wOz~~(|Ou~~)PP!Q![)S~)XPT~!Q![)S~)aPi~!Q![)S~)gQ!Q![)m#]#^)u~)rPn~!Q![)m~)zOc~~*POj~~*SQ!Q![*Y#f#g*b~*_P|~!Q![*Y~*gO!m~~*lPl~!Q![*o~*tPU~!Q![*o~*|O!b~~+ROe~~+WOZ~~+]Of~~+bRQ~!Q![+k#T#o+]5i6S+]~+pPQ~!Q![+k~+xTQ~!Q![+k#T#c+]#c#d,X#d#o+]5i6S+]~,^TQ~!Q![+k#T#c+]#c#d,m#d#o+]5i6S+]~,rTQ~!Q![+k#T#`+]#`#a-R#a#o+]5i6S+]~-YR!p~Q~!Q![+k#T#o+]5i6S+]~-hSQ~!Q![+k#T#U-t#U#o+]5i6S+]~-yTQ~!Q![+k#T#f+]#f#g.Y#g#o+]5i6S+]~._TQ~!Q![+k#T#W+]#W#X.n#X#o+]5i6S+]~.uR!o~Q~!Q![+k#T#o+]5i6S+]~/TTQ~!Q![+k#T#X+]#X#Y/d#Y#o+]5i6S+]~/iTQ~!Q![+k#T#U+]#U#V/x#V#o+]5i6S+]~/}TQ~!Q![+k#T#c+]#c#d0^#d#o+]5i6S+]~0cTQ~!Q![+k#T#c+]#c#d0r#d#o+]5i6S+]~0wTQ~!Q![+k#T#`+]#`#a1W#a#o+]5i6S+]~1_R!q~Q~!Q![+k#T#o+]5i6S+]~1mTQ~!Q![+k#T#f+]#f#g1|#g#o+]5i6S+]~2TR!n~Q~!Q![+k#T#o+]5i6S+]~2cTQ~!Q![+k#T#X+]#X#Y2r#Y#o+]5i6S+]~2wTQ~!Q![+k#T#W+]#W#X3W#X#o+]5i6S+]~3_R!r~Q~!Q![+k#T#o+]5i6S+]~3mO`~~3rOh~~3wOa~~3|O{~~4RO^~~4WOb~~4]O!Q~~4bO!P~~4gO}~~4lO!O~~4qO!a~~4vO[~~4{Og~~5QOq~~5VO!R~~5[O]~~5aOY~~5fOy~~5kOx~~5pOv~~5uOt~~5zOs~~6POr~",
tokenizers: [0, 1], tokenizers: [0, 1],
topRules: {"Expression":[0,1]}, topRules: {"Expression":[0,1]},
tokenPrec: 2056 tokenPrec: 1720
}) })

View File

@ -17,8 +17,7 @@
log_and @left, log_and @left,
set_decart @left set_union @left set_intersect @left set_minus @left set_symminus @left, set_decart @left set_union @left set_intersect @left set_minus @left set_symminus @left,
set_bool @right, set_bool @right,
quant @right, quant @right
p1, p2
} }
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -43,7 +42,7 @@
Function { "F"$[0-9]+ } Function { "F"$[0-9]+ }
Predicate { "P"$[0-9]+ } Predicate { "P"$[0-9]+ }
Radical { "R"$[0-9]+ } Radical { "R"$[0-9]+ }
local { $[_a-zα-ω]($[a-zα-ω])* } Local { $[_a-zα-ω]($[a-zα-ω])*$[0-9]* }
PrefixR { "R" } PrefixR { "R" }
PrefixI { "I" } PrefixI { "I" }
PrefixD { "D" } PrefixD { "D" }
@ -77,7 +76,7 @@
debool debool
red red
smallPr smallPr
local Local
} }
} }
@ -110,13 +109,6 @@ arguments {
declaration { declaration {
Local "∈" setexpr Local "∈" setexpr
} }
Local {
!p1 local |
!p2 local Index
}
Index {
integer
}
variable { variable {
Local | Local |
tuple tuple

View File

@ -1,74 +0,0 @@
@detectDelim
@external propSource highlighting from "./highlight"
@top Expression { token* }
@skip { space }
@tokens {
space { @whitespace+ }
Index { $[0-9]+ }
ComplexIndex { $[1-9](","$[1-9])* }
Integer { space$[0-9]+space? }
bigPr { "Pr" }
smallPr { "pr" }
filter { "Fi" }
card { "card" }
bool { "bool" }
debool { "debool" }
red { "red" }
ConstructPrefix { "D" | "R" | "I" }
Global { $[XCSDAPTF]$[0-9]+ }
Radical { "R"$[0-9]+ }
local { $[_a-zα-ω]$[a-zα-ω]* }
"(" ")"
"[" "]"
"{" "}"
@precedence {
filter
bigPr
Global
Radical
ConstructPrefix
}
@precedence {
card
bool
debool
red
smallPr
local
}
@precedence {
Integer
space
}
}
TextFunction {
bigPr ComplexIndex |
smallPr ComplexIndex |
filter ComplexIndex |
card |
bool |
debool |
red
}
Local {
local Index?
}
token {
TextFunction |
ConstructPrefix |
Integer |
Global |
Radical |
Local
}

View File

@ -4,8 +4,8 @@ import TextURL from '@/components/ui/TextURL';
import Tooltip, { PlacesType } from '@/components/ui/Tooltip'; import Tooltip, { PlacesType } from '@/components/ui/Tooltip';
import { useConceptOptions } from '@/context/ConceptOptionsContext'; import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
import TopicPage from '@/pages/ManualsPage/TopicPage';
import TopicPage from '../../pages/ManualsPage/TopicPage';
import { IconHelp } from '../Icons'; import { IconHelp } from '../Icons';
import { CProps } from '../props'; import { CProps } from '../props';

View File

@ -39,16 +39,16 @@ function InfoConstituenta({ data, className, ...restProps }: InfoConstituentaPro
{data.definition_resolved} {data.definition_resolved}
</p> </p>
) : null} ) : null}
{data.parent_alias ? ( {data.spawner_alias ? (
<p> <p>
<b>Основание: </b> <b>Основание: </b>
{data.parent_alias} {data.spawner_alias}
</p> </p>
) : null} ) : null}
{data.children_alias.length > 0 ? ( {data.spawn_alias.length > 0 ? (
<p> <p>
<b>Порождает: </b> <b>Порождает: </b>
{data.children_alias.join(', ')} {data.spawn_alias.join(', ')}
</p> </p>
) : null} ) : null}
{data.convention ? ( {data.convention ? (

View File

@ -3,6 +3,7 @@
*/ */
import { Graph } from './Graph'; import { Graph } from './Graph';
import { LibraryItemID } from './library';
import { ConstituentaID, CstType, IConstituenta, IRSForm, IRSFormData, IRSFormStats } from './rsform'; import { ConstituentaID, CstType, IConstituenta, IRSForm, IRSFormData, IRSFormStats } from './rsform';
import { inferClass, inferStatus, inferTemplate, isBaseSet, isFunctional } from './rsformAPI'; import { inferClass, inferStatus, inferTemplate, isBaseSet, isFunctional } from './rsformAPI';
import { ParsingStatus, ValueClass } from './rslang'; import { ParsingStatus, ValueClass } from './rslang';
@ -59,27 +60,39 @@ export class RSFormLoader {
} }
private inferCstAttributes() { private inferCstAttributes() {
const inherit_children = new Set(this.schema.inheritance.map(item => item[0])); const schemaByCst = new Map<ConstituentaID, LibraryItemID>();
const inherit_parents = new Set(this.schema.inheritance.map(item => item[1])); const parents: LibraryItemID[] = [];
this.schema.inheritance.forEach(item => {
if (item.child_source === this.schema.id) {
schemaByCst.set(item.child, item.parent_source);
if (!parents.includes(item.parent_source)) {
parents.push(item.parent_source);
}
}
});
const inherit_children = new Set(this.schema.inheritance.map(item => item.child));
const inherit_parents = new Set(this.schema.inheritance.map(item => item.parent));
this.graph.topologicalOrder().forEach(cstID => { this.graph.topologicalOrder().forEach(cstID => {
const cst = this.cstByID.get(cstID)!; const cst = this.cstByID.get(cstID)!;
cst.status = inferStatus(cst.parse.status, cst.parse.valueClass); cst.status = inferStatus(cst.parse.status, cst.parse.valueClass);
cst.is_template = inferTemplate(cst.definition_formal); cst.is_template = inferTemplate(cst.definition_formal);
cst.cst_class = inferClass(cst.cst_type, cst.is_template); cst.cst_class = inferClass(cst.cst_type, cst.is_template);
cst.children = []; cst.spawn = [];
cst.children_alias = []; cst.spawn_alias = [];
cst.parent_schema = schemaByCst.get(cst.id);
cst.parent_schema_index = cst.parent_schema ? parents.indexOf(cst.parent_schema) + 1 : 0;
cst.is_inherited = inherit_children.has(cst.id); cst.is_inherited = inherit_children.has(cst.id);
cst.is_inherited_parent = inherit_parents.has(cst.id); cst.has_inherited_children = inherit_parents.has(cst.id);
cst.is_simple_expression = this.inferSimpleExpression(cst); cst.is_simple_expression = this.inferSimpleExpression(cst);
if (!cst.is_simple_expression || cst.cst_type === CstType.STRUCTURED) { if (!cst.is_simple_expression || cst.cst_type === CstType.STRUCTURED) {
return; return;
} }
cst.parent = this.inferParent(cst); cst.spawner = this.inferParent(cst);
if (cst.parent) { if (cst.spawner) {
const parent = this.cstByID.get(cst.parent)!; const parent = this.cstByID.get(cst.spawner)!;
cst.parent_alias = parent.alias; cst.spawner_alias = parent.alias;
parent.children.push(cst.id); parent.spawn.push(cst.id);
parent.children_alias.push(cst.alias); parent.spawn_alias.push(cst.alias);
} }
}); });
} }
@ -107,7 +120,7 @@ export class RSFormLoader {
if (sources.size !== 1 || sources.has(target.id)) { if (sources.size !== 1 || sources.has(target.id)) {
return undefined; return undefined;
} }
const parent_id = sources.values().next().value as ConstituentaID; const parent_id = sources.values().next().value!;
const parent = this.cstByID.get(parent_id); const parent = this.cstByID.get(parent_id);
if (parent && isBaseSet(parent.cst_type)) { if (parent && isBaseSet(parent.cst_type)) {
return undefined; return undefined;
@ -122,7 +135,7 @@ export class RSFormLoader {
node.inputs.forEach(id => { node.inputs.forEach(id => {
const parent = this.cstByID.get(id)!; const parent = this.cstByID.get(id)!;
if (!parent.is_template || !parent.is_simple_expression) { if (!parent.is_template || !parent.is_simple_expression) {
sources.add(parent.parent ?? id); sources.add(parent.spawner ?? id);
} }
}); });
return sources; return sources;
@ -133,7 +146,7 @@ export class RSFormLoader {
bodyDependencies.forEach(alias => { bodyDependencies.forEach(alias => {
const parent = this.cstByAlias.get(alias); const parent = this.cstByAlias.get(alias);
if (parent && (!parent.is_template || !parent.is_simple_expression)) { if (parent && (!parent.is_template || !parent.is_simple_expression)) {
sources.add(this.cstByID.get(parent.id)!.parent ?? parent.id); sources.add(this.cstByID.get(parent.id)!.spawner ?? parent.id);
} }
}); });
const needCheckHead = () => { const needCheckHead = () => {
@ -142,7 +155,7 @@ export class RSFormLoader {
} else if (sources.size !== 1) { } else if (sources.size !== 1) {
return false; return false;
} else { } else {
const base = this.cstByID.get(sources.values().next().value as ConstituentaID)!; const base = this.cstByID.get(sources.values().next().value!)!;
return !isFunctional(base.cst_type) || splitTemplateDefinition(base.definition_formal).head !== expression.head; return !isFunctional(base.cst_type) || splitTemplateDefinition(base.definition_formal).head !== expression.head;
} }
}; };
@ -151,7 +164,7 @@ export class RSFormLoader {
headDependencies.forEach(alias => { headDependencies.forEach(alias => {
const parent = this.cstByAlias.get(alias); const parent = this.cstByAlias.get(alias);
if (parent && !isBaseSet(parent.cst_type) && (!parent.is_template || !parent.is_simple_expression)) { if (parent && !isBaseSet(parent.cst_type) && (!parent.is_template || !parent.is_simple_expression)) {
sources.add(parent.parent ?? parent.id); sources.add(parent.spawner ?? parent.id);
} }
}); });
} }

View File

@ -48,7 +48,7 @@ export interface OssNodeInternal {
/** /**
* Represents graph node coloring scheme. * Represents graph node coloring scheme.
*/ */
export type GraphColoring = 'none' | 'status' | 'type'; export type GraphColoring = 'none' | 'status' | 'type' | 'schemas';
/** /**
* Represents graph node sizing scheme. * Represents graph node sizing scheme.

View File

@ -44,6 +44,6 @@ export function applyNodeSizing(target: IConstituenta, sizing: GraphSizing): num
} else if (sizing === 'complex') { } else if (sizing === 'complex') {
return target.is_simple_expression ? 1 : 2; return target.is_simple_expression ? 1 : 2;
} else { } else {
return target.parent ? 1 : 2; return target.spawner ? 1 : 2;
} }
} }

View File

@ -101,16 +101,35 @@ export interface IConstituentaData extends IConstituentaMeta {
* Represents Constituenta. * Represents Constituenta.
*/ */
export interface IConstituenta extends IConstituentaData { export interface IConstituenta extends IConstituentaData {
/** {@link CstClass} of this {@link IConstituenta}. */
cst_class: CstClass; cst_class: CstClass;
/** {@link ExpressionStatus} of this {@link IConstituenta}. */
status: ExpressionStatus; status: ExpressionStatus;
/** Indicates if this {@link IConstituenta} is a template. */
is_template: boolean; is_template: boolean;
/** Indicates if this {@link IConstituenta} has a simple expression. */
is_simple_expression: boolean; is_simple_expression: boolean;
/** Index of {@link LibraryItemID} that contains this cst (or inheritance parent).
* 0 - not inherited, 1 - inherited by 1st schema, 2 - inherited by 2nd schema, etc.
*/
parent_schema_index: number;
/** {@link LibraryItemID} that contains parent of this inherited {@link IConstituenta}. */
parent_schema?: LibraryItemID;
/** Indicates if this {@link IConstituenta} is inherited. */
is_inherited: boolean; is_inherited: boolean;
is_inherited_parent: boolean; /** Indicates if this {@link IConstituenta} has children that are inherited. */
parent?: ConstituentaID; has_inherited_children: boolean;
parent_alias?: string;
children: number[]; /** {@link IConstituenta} that spawned this one. */
children_alias: string[]; spawner?: ConstituentaID;
/** Alias of {@link IConstituenta} that spawned this one. */
spawner_alias?: string;
/** List of {@link IConstituenta} that are spawned by this one. */
spawn: number[];
/** List of aliases of {@link IConstituenta} that are spawned by this one. */
spawn_alias: string[];
} }
/** /**
@ -198,12 +217,22 @@ export interface IRSFormStats {
count_theorem: number; count_theorem: number;
} }
/**
* Represents inheritance data for {@link IRSForm}.
*/
export interface IInheritanceData {
child: ConstituentaID;
child_source: LibraryItemID;
parent: ConstituentaID;
parent_source: LibraryItemID;
}
/** /**
* Represents data for {@link IRSForm} provided by backend. * Represents data for {@link IRSForm} provided by backend.
*/ */
export interface IRSFormData extends ILibraryItemVersioned { export interface IRSFormData extends ILibraryItemVersioned {
items: IConstituentaData[]; items: IConstituentaData[];
inheritance: ConstituentaID[][]; inheritance: IInheritanceData[];
oss: ILibraryItemReference[]; oss: ILibraryItemReference[];
} }

View File

@ -117,9 +117,9 @@ export function inferClass(type: CstType, isTemplate: boolean = false): CstClass
export function createMockConstituenta(id: ConstituentaID, alias: string, comment: string): IConstituenta { export function createMockConstituenta(id: ConstituentaID, alias: string, comment: string): IConstituenta {
return { return {
id: id, id: id,
parent: id, spawner: id,
children: [], spawn: [],
children_alias: [], spawn_alias: [],
is_simple_expression: false, is_simple_expression: false,
schema: -1, schema: -1,
alias: alias, alias: alias,
@ -132,9 +132,10 @@ export function createMockConstituenta(id: ConstituentaID, alias: string, commen
definition_raw: '', definition_raw: '',
definition_resolved: '', definition_resolved: '',
status: ExpressionStatus.INCORRECT, status: ExpressionStatus.INCORRECT,
parent_schema_index: 0,
is_template: false, is_template: false,
is_inherited: false, is_inherited: false,
is_inherited_parent: false, has_inherited_children: false,
cst_class: CstClass.DERIVED, cst_class: CstClass.DERIVED,
parse: { parse: {
status: ParsingStatus.INCORRECT, status: ParsingStatus.INCORRECT,

View File

@ -1,5 +1,3 @@
import { urls } from '@/app/urls';
import { IconLibrary2, IconManuals, IconUser2 } from '@/components/Icons';
import LinkTopic from '@/components/ui/LinkTopic'; import LinkTopic from '@/components/ui/LinkTopic';
import TextURL from '@/components/ui/TextURL'; import TextURL from '@/components/ui/TextURL';
import { HelpTopic } from '@/models/miscellaneous'; import { HelpTopic } from '@/models/miscellaneous';
@ -22,20 +20,6 @@ function HelpMain() {
<LinkTopic text='Операционной схеме синтеза' topic={HelpTopic.CC_OSS} />. <LinkTopic text='Операционной схеме синтеза' topic={HelpTopic.CC_OSS} />.
</p> </p>
<h2>Разделы Портала</h2>
<li>
<IconLibrary2 size='1.25rem' className='inline-icon' /> <TextURL text='Библиотека' href={urls.library} />
библиотека концептуальных схем
</li>
<li>
<IconManuals size='1.25rem' className='inline-icon' /> <TextURL text='Справка' href={urls.manuals} />
справочные материалы
</li>
<li>
<IconUser2 size='1.25rem' className='inline-icon' /> <TextURL text='Профиль' href={urls.profile} /> данные
пользователя и смена пароля
</li>
<h2>Разделы Справки</h2> <h2>Разделы Справки</h2>
{[ {[
HelpTopic.THESAURUS, HelpTopic.THESAURUS,

View File

@ -249,7 +249,7 @@ function FormConstituenta({
icon={<IconSave size='1.25rem' />} icon={<IconSave size='1.25rem' />}
/> />
<Overlay position='top-[0.1rem] left-[0.4rem]' className='cc-icons'> <Overlay position='top-[0.1rem] left-[0.4rem]' className='cc-icons'>
{state.is_inherited_parent && !state.is_inherited ? ( {state.has_inherited_children && !state.is_inherited ? (
<Indicator <Indicator
icon={<IconPredecessor size='1.25rem' className='clr-text-primary' />} icon={<IconPredecessor size='1.25rem' className='clr-text-primary' />}
titleHtml='Внимание!</br> Конституента имеет потомков<br/> в операционной схеме синтеза' titleHtml='Внимание!</br> Конституента имеет потомков<br/> в операционной схеме синтеза'

View File

@ -165,7 +165,11 @@ function EditorRSExpression({
toggleControls={() => setShowControls(prev => !prev)} toggleControls={() => setShowControls(prev => !prev)}
/> />
<Overlay position='top-[-0.5rem]' className='pl-[8.5rem] xs:pl-[2rem] flex justify-center w-full gap-1'> <Overlay
position='top-[-0.5rem]'
layer='z-pop'
className='pl-[8.5rem] xs:pl-[2rem] flex justify-center w-full gap-1'
>
<StatusBar <StatusBar
processing={parser.processing} processing={parser.processing}
isModified={isModified} isModified={isModified}

View File

@ -15,7 +15,7 @@ function ToolbarRSExpression({ disabled, showControls, toggleControls, showAST }
const model = useRSForm(); const model = useRSForm();
return ( return (
<Overlay position='top-[-0.5rem] right-0' className='cc-icons'> <Overlay position='top-[-0.5rem] right-0' layer='z-sticky' className='cc-icons'>
{!disabled || model.processing ? ( {!disabled || model.processing ? (
<MiniButton <MiniButton
title='Отображение специальной клавиатуры' title='Отображение специальной клавиатуры'

View File

@ -261,6 +261,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
const selectors = useMemo( const selectors = useMemo(
() => ( () => (
<GraphSelectors <GraphSelectors
schema={controller.schema}
coloring={coloring} coloring={coloring}
layout={layout} layout={layout}
sizing={sizing} sizing={sizing}
@ -269,7 +270,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
setSizing={setSizing} setSizing={setSizing}
/> />
), ),
[coloring, layout, sizing, handleChangeLayout, setColoring, setSizing] [coloring, controller.schema, layout, sizing, handleChangeLayout, setColoring, setSizing]
); );
const viewHidden = useMemo( const viewHidden = useMemo(
() => ( () => (

View File

@ -3,10 +3,14 @@ import { GraphLayout } from '@/components/ui/GraphUI';
import Overlay from '@/components/ui/Overlay'; import Overlay from '@/components/ui/Overlay';
import SelectSingle from '@/components/ui/SelectSingle'; import SelectSingle from '@/components/ui/SelectSingle';
import { GraphColoring, GraphSizing, HelpTopic } from '@/models/miscellaneous'; import { GraphColoring, GraphSizing, HelpTopic } from '@/models/miscellaneous';
import { IRSForm } from '@/models/rsform';
import { mapLabelColoring, mapLabelLayout, mapLabelSizing } from '@/utils/labels'; import { mapLabelColoring, mapLabelLayout, mapLabelSizing } from '@/utils/labels';
import { SelectorGraphColoring, SelectorGraphLayout, SelectorGraphSizing } from '@/utils/selectors'; import { SelectorGraphColoring, SelectorGraphLayout, SelectorGraphSizing } from '@/utils/selectors';
import SchemasGuide from './SchemasGuide';
interface GraphSelectorsProps { interface GraphSelectorsProps {
schema?: IRSForm;
coloring: GraphColoring; coloring: GraphColoring;
layout: GraphLayout; layout: GraphLayout;
sizing: GraphSizing; sizing: GraphSizing;
@ -16,7 +20,7 @@ interface GraphSelectorsProps {
setSizing: (newValue: GraphSizing) => void; setSizing: (newValue: GraphSizing) => void;
} }
function GraphSelectors({ coloring, setColoring, layout, setLayout, sizing, setSizing }: GraphSelectorsProps) { function GraphSelectors({ schema, coloring, setColoring, layout, setLayout, sizing, setSizing }: GraphSelectorsProps) {
return ( return (
<div className='border rounded-b-none select-none clr-input rounded-t-md'> <div className='border rounded-b-none select-none clr-input rounded-t-md'>
<SelectSingle <SelectSingle
@ -30,6 +34,7 @@ function GraphSelectors({ coloring, setColoring, layout, setLayout, sizing, setS
<Overlay position='right-[2.5rem] top-[0.5rem]'> <Overlay position='right-[2.5rem] top-[0.5rem]'>
{coloring === 'status' ? <BadgeHelp topic={HelpTopic.UI_CST_STATUS} className='min-w-[25rem]' /> : null} {coloring === 'status' ? <BadgeHelp topic={HelpTopic.UI_CST_STATUS} className='min-w-[25rem]' /> : null}
{coloring === 'type' ? <BadgeHelp topic={HelpTopic.UI_CST_CLASS} className='min-w-[25rem]' /> : null} {coloring === 'type' ? <BadgeHelp topic={HelpTopic.UI_CST_CLASS} className='min-w-[25rem]' /> : null}
{coloring === 'schemas' && !!schema ? <SchemasGuide schema={schema} /> : null}
</Overlay> </Overlay>
<SelectSingle <SelectSingle
className='my-1' className='my-1'

View File

@ -0,0 +1,74 @@
import { useMemo } from 'react';
import { IconHelp } from '@/components/Icons';
import Tooltip from '@/components/ui/Tooltip';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { useLibrary } from '@/context/LibraryContext';
import { LibraryItemID } from '@/models/library';
import { IRSForm } from '@/models/rsform';
import { colorBgSchemas } from '@/styling/color';
import { globals, prefixes } from '@/utils/constants';
interface SchemasGuideProps {
schema: IRSForm;
}
function SchemasGuide({ schema }: SchemasGuideProps) {
const { colors } = useConceptOptions();
const library = useLibrary();
const schemas = useMemo(() => {
const processed = new Set<LibraryItemID>();
const aliases: string[] = [];
const indexes: number[] = [];
schema.items.forEach(cst => {
if (cst.parent_schema && !processed.has(cst.parent_schema)) {
const item = library.items.find(item => item.id === cst.parent_schema);
if (item) {
aliases.push(item.alias);
} else {
aliases.push(`Схема ${cst.parent_schema_index}`);
}
processed.add(cst.parent_schema);
indexes.push(cst.parent_schema_index);
}
});
const result: string[] = [];
for (let i = 1; i <= aliases.length; i++) {
const trueIndex = indexes.findIndex(index => index === i);
result.push(aliases[trueIndex]);
}
return result;
}, [schema, library.items]);
return (
<div tabIndex={-1} id={globals.graph_schemas} className='p-1'>
<IconHelp size='1.25rem' className='icon-primary' />
<Tooltip
anchorSelect={`#${globals.graph_schemas}`}
layer='z-modalTooltip'
place='right'
className='max-w-[25rem] break-words text-base'
>
<div>
<span
className='min-w-[0.6rem] min-h-[0.6rem] border inline-block mr-1 rounded-full'
style={{ backgroundColor: colorBgSchemas(0, colors) }}
/>
Текущая схема
</div>
{schemas.map((alias, index) => (
<div key={`${prefixes.schemas_list}${index}`}>
<span
className='min-w-[0.6rem] min-h-[0.6rem] border inline-block mr-1 rounded-full'
style={{ backgroundColor: colorBgSchemas(index + 1, colors) }}
/>
{alias}
</div>
))}
</Tooltip>
</div>
);
}
export default SchemasGuide;

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import { RefObject, useCallback, useLayoutEffect, useMemo } from 'react'; import { RefObject, useCallback, useLayoutEffect } from 'react';
import GraphUI, { import GraphUI, {
CollapseProps, CollapseProps,
@ -107,12 +107,8 @@ function TermGraph({
setSelections(newSelections); setSelections(newSelections);
}, [selectedIDs, setSelections, nodes]); }, [selectedIDs, setSelections, nodes]);
const canvasWidth = useMemo(() => {
return 'calc(100vw - 1rem)';
}, []);
return ( return (
<div className='relative outline-none' style={{ width: canvasWidth, height: mainHeight }}> <div className='relative outline-none w-[100dvw]' style={{ height: mainHeight }}>
<GraphUI <GraphUI
nodes={nodes} nodes={nodes}
edges={edges} edges={edges}

View File

@ -45,7 +45,7 @@ function useGraphFilter(schema: IRSForm | undefined, params: GraphFilterParams,
} }
if (!focusCst && params.foldDerived) { if (!focusCst && params.foldDerived) {
schema.items.forEach(cst => { schema.items.forEach(cst => {
if (cst.parent) { if (cst.spawner) {
graph.foldNode(cst.id); graph.foldNode(cst.id);
} }
}); });
@ -53,7 +53,7 @@ function useGraphFilter(schema: IRSForm | undefined, params: GraphFilterParams,
if (focusCst) { if (focusCst) {
const includes: ConstituentaID[] = [ const includes: ConstituentaID[] = [
focusCst.id, focusCst.id,
...focusCst.children, ...focusCst.spawn,
...(params.focusShowInputs ? schema.graph.expandInputs([focusCst.id]) : []), ...(params.focusShowInputs ? schema.graph.expandInputs([focusCst.id]) : []),
...(params.focusShowOutputs ? schema.graph.expandOutputs([focusCst.id]) : []) ...(params.focusShowOutputs ? schema.graph.expandOutputs([focusCst.id]) : [])
]; ];

View File

@ -109,13 +109,13 @@ function TableSideConstituents({
} }
}, },
{ {
when: (cst: IConstituenta) => !!activeCst && cst.parent === activeCst?.id && cst.id !== activeCst?.id, when: (cst: IConstituenta) => !!activeCst && cst.spawner === activeCst?.id && cst.id !== activeCst?.id,
style: { style: {
backgroundColor: colors.bgOrange50 backgroundColor: colors.bgOrange50
} }
}, },
{ {
when: (cst: IConstituenta) => activeCst?.id !== undefined && cst.children.includes(activeCst.id), when: (cst: IConstituenta) => activeCst?.id !== undefined && cst.spawn.includes(activeCst.id),
style: { style: {
backgroundColor: colors.bgGreen50 backgroundColor: colors.bgGreen50
} }

View File

@ -416,6 +416,23 @@ export function colorBgCstClass(cstClass: CstClass, colors: IColorTheme): string
} }
} }
/**
* Determines background color for {@link IConstituenta} depending on its parent schema index.
*/
export function colorBgSchemas(schema_index: number, colors: IColorTheme): string {
if (schema_index === 0) {
return colors.bgGreen;
}
// prettier-ignore
switch (schema_index % 4) {
case 1: return colors.bgPurple;
case 2: return colors.bgOrange;
case 3: return colors.bgTeal;
case 0: return colors.bgBlue;
}
return colors.bgBlue;
}
/** /**
* Determines background color for {@link GramData}. * Determines background color for {@link GramData}.
*/ */
@ -462,5 +479,8 @@ export function colorBgGraphNode(cst: IConstituenta, coloringScheme: GraphColori
if (coloringScheme === 'status') { if (coloringScheme === 'status') {
return colorBgCstStatus(cst.status, colors); return colorBgCstStatus(cst.status, colors);
} }
if (coloringScheme === 'schemas') {
return colorBgSchemas(cst.parent_schema_index, colors);
}
return ''; return '';
} }

View File

@ -215,15 +215,15 @@ export function domTooltipConstituenta(cst?: IConstituenta, canClick?: boolean):
dom.appendChild(convention); dom.appendChild(convention);
} }
if (cst.parent_alias) { if (cst.spawner_alias) {
const derived = document.createElement('p'); const derived = document.createElement('p');
derived.innerHTML = `<b>Основание:</b> ${cst.parent_alias}`; derived.innerHTML = `<b>Основание:</b> ${cst.spawner_alias}`;
dom.appendChild(derived); dom.appendChild(derived);
} }
if (cst.children_alias.length > 0) { if (cst.spawn_alias.length > 0) {
const children = document.createElement('p'); const children = document.createElement('p');
children.innerHTML = `<b>Порождает:</b> ${cst.children_alias.join(', ')}`; children.innerHTML = `<b>Порождает:</b> ${cst.spawn_alias.join(', ')}`;
dom.appendChild(children); dom.appendChild(children);
} }

View File

@ -143,7 +143,8 @@ export const globals = {
email_tooltip: 'email_tooltip', email_tooltip: 'email_tooltip',
main_scroll: 'main_scroll', main_scroll: 'main_scroll',
library_item_editor: 'library_item_editor', library_item_editor: 'library_item_editor',
constituenta_editor: 'constituenta_editor' constituenta_editor: 'constituenta_editor',
graph_schemas: 'graph_schemas_tooltip'
}; };
/** /**
@ -165,6 +166,7 @@ export const prefixes = {
cst_source_list: 'cst_source_list_', cst_source_list: 'cst_source_list_',
cst_delete_list: 'cst_delete_list_', cst_delete_list: 'cst_delete_list_',
cst_dependant_list: 'cst_dependant_list_', cst_dependant_list: 'cst_dependant_list_',
schemas_list: 'schemas_list_',
operation_list: 'operation_list_', operation_list: 'operation_list_',
csttype_list: 'csttype_', csttype_list: 'csttype_',
policy_list: 'policy_list_', policy_list: 'policy_list_',

View File

@ -315,7 +315,8 @@ export const mapLabelLayout = new Map<GraphLayout, string>([
export const mapLabelColoring = new Map<GraphColoring, string>([ export const mapLabelColoring = new Map<GraphColoring, string>([
['none', 'Цвет: Моно'], ['none', 'Цвет: Моно'],
['status', 'Цвет: Статус'], ['status', 'Цвет: Статус'],
['type', 'Цвет: Класс'] ['type', 'Цвет: Класс'],
['schemas', 'Цвет: Схемы']
]); ]);
/** /**