From 4383511a4ae58f03a0776479af51bcf5dbb8d1cf Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Thu, 26 Sep 2024 23:09:41 +0300 Subject: [PATCH] F: Add AST visualization for expression --- TODO.txt | 2 +- rsconcept/frontend/package.json | 2 +- .../RSInput/rslang/parserAST.terms.ts | 46 ++++ .../components/RSInput/rslang/parserAST.ts | 20 ++ .../RSInput/rslang/rslangAST.grammar | 247 ++++++++++++++++++ ...{rslangFull.grammar => rslangFast.grammar} | 0 .../EditorRSExpression/EditorRSExpression.tsx | 33 ++- .../ToolbarRSExpression.tsx | 3 +- rsconcept/frontend/src/styling/color.ts | 60 ++++- rsconcept/frontend/src/utils/codemirror.ts | 52 ++++ rsconcept/frontend/src/utils/constants.ts | 1 + rsconcept/frontend/src/utils/labels.ts | 3 + scripts/dev/PopulateDevData.ps1 | 4 - 13 files changed, 454 insertions(+), 19 deletions(-) create mode 100644 rsconcept/frontend/src/components/RSInput/rslang/parserAST.terms.ts create mode 100644 rsconcept/frontend/src/components/RSInput/rslang/parserAST.ts create mode 100644 rsconcept/frontend/src/components/RSInput/rslang/rslangAST.grammar rename rsconcept/frontend/src/components/RSInput/rslang/{rslangFull.grammar => rslangFast.grammar} (100%) diff --git a/TODO.txt b/TODO.txt index 9dd887c8..d9d5f241 100644 --- a/TODO.txt +++ b/TODO.txt @@ -63,12 +63,12 @@ https://yandex.cloud/ru/docs/smartcaptcha [Research] Research and consider integration - django-allauth - consider supporting popular auth providers -- drf-messages - skeleton loading https://react.dev/reference/react/Suspense - backend error message unification +- drf-messages https://drf-standardized-errors.readthedocs.io/en/latest/error_response.html - semantic json diff diff --git a/rsconcept/frontend/package.json b/rsconcept/frontend/package.json index b6a1e4e5..f281297f 100644 --- a/rsconcept/frontend/package.json +++ b/rsconcept/frontend/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "scripts": { - "generate": "lezer-generator src/components/RSInput/rslang/rslangFull.grammar -o src/components/RSInput/rslang/parser.ts && lezer-generator src/components/RefsInput/parse/refsText.grammar -o src/components/RefsInput/parse/parser.ts", + "generate": "lezer-generator src/components/RSInput/rslang/rslangFast.grammar -o src/components/RSInput/rslang/parser.ts && lezer-generator src/components/RSInput/rslang/rslangAST.grammar -o src/components/RSInput/rslang/parserAST.ts && lezer-generator src/components/RefsInput/parse/refsText.grammar -o src/components/RefsInput/parse/parser.ts", "test": "jest", "dev": "vite --host", "build": "tsc && vite build", diff --git a/rsconcept/frontend/src/components/RSInput/rslang/parserAST.terms.ts b/rsconcept/frontend/src/components/RSInput/rslang/parserAST.terms.ts new file mode 100644 index 00000000..964b3b8d --- /dev/null +++ b/rsconcept/frontend/src/components/RSInput/rslang/parserAST.terms.ts @@ -0,0 +1,46 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +export const + Expression = 1, + Logic = 2, + Logic_predicates = 3, + Variable = 4, + Local = 5, + Tuple = 8, + Setexpr_enum_min2 = 9, + Setexpr_enum = 10, + Setexpr = 11, + Literal = 12, + Integer = 13, + EmptySet = 14, + IntegerSet = 15, + Global = 16, + Radical = 17, + Setexpr_binary = 18, + Setexpr_generators = 27, + Enumeration = 30, + Boolean = 31, + Filter_expression = 33, + Filter = 34, + Declarative = 37, + PrefixD = 40, + PrefixI = 41, + Imperative = 42, + Imp_blocks = 43, + PrefixR = 45, + Recursion = 46, + Function = 48, + TextFunction = 49, + BigPr = 50, + SmallPr = 51, + Card = 52, + Bool = 53, + Debool = 54, + Red = 55, + Logic_unary = 68, + Predicate = 71, + Logic_quantor = 72, + Variable_pack = 74, + Logic_binary = 76, + Function_decl = 81, + Arguments = 82, + Declaration = 83 diff --git a/rsconcept/frontend/src/components/RSInput/rslang/parserAST.ts b/rsconcept/frontend/src/components/RSInput/rslang/parserAST.ts new file mode 100644 index 00000000..1250d271 --- /dev/null +++ b/rsconcept/frontend/src/components/RSInput/rslang/parserAST.ts @@ -0,0 +1,20 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +import {LRParser} from "@lezer/lr" +export const parser = LRParser.deserialize({ + version: 14, + states: "2xO!sQPOOOOQO'#Ch'#ChO#lQPO'#EWOOQO'#EW'#EWO%yQPO'#EVOVQPO'#CnO'_QPO'#CzO'fQPO'#C{O'nQPO'#C}O'sQPO'#DRO'xQPO'#DWO'}QPO'#D[OOQO'#Cw'#CwO(SQPO'#CwOOQO'#D_'#D_OOQO'#Cg'#CgO)pQPO'#CgO)uQPO'#CgO)zQPO'#C_OVQPO'#DsO*SQPO'#DvOOQO'#Dr'#DrO*[QPO'#DrO*aQPO'#EVOOQO'#C^'#C^O*rQPO'#EPQOQPOOO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,58yO+OQPO'#CfO+VQPO,59YO,jQPO,59OO,rQPO'#CeO,wQPO,58xO-YQPO,59mO-{QPO'#CfO*wQPO'#CnO.YQPO,59fOOQO'#Cf'#CfO*wQPO,59gOOQO,59g,59gO*wQPO,59iO*SQPO,59mO*wQPO,59rO*SQPO,59vO*wQPO,59RO*wQPO,59RO$lQPO'#C_OOQO,5:_,5:_O*wQPO'#CdOOQO'#C`'#C`OOQO'#Dx'#DxO.bQPO,5:bO*wQPO,5:^OVQPO,5:fOVQPO,5:fOVQPO,5:fOVQPO,5:fO.jQPO'#EROOQO'#EQ'#EQO.oQPO,5:kOOQO1G.t1G.tO2`QPO1G.tO2gQPO1G.tO6VQPO1G.tO9uQPO1G.tO9|QPO1G.tO:TQPO1G.tO:[QPO1G.tO=vQPO1G.eOOQO1G.j1G.jO*wQPO,59POOQO1G.d1G.dO*wQPO1G/XOOQO1G/Q1G/QO>gQPO1G/RO>nQPO1G/TO>vQPO1G/XO>{QPO1G/^O?SQPO1G/bO?XQPO1G.mO?aQPO1G.mO*SQPO,5:dO*wQPO1G/|O?hQPO1G/xOOQO1G0Q1G0QO@[QPO1G0QO@cQPO1G0QO@jQPO1G0QO*wQPO,5:mO*rQPO,5:lOVQPO1G0VOAXQPO1G.kOAiQPO7+$sOOQO7+$m7+$mOApQPO7+$oO*wQPO7+$sOVQPO7+$xO*wQPO7+$|OOQO7+$X7+$XOOQO1G0O1G0OOAuQPO7+%hOOQO7+%d7+%dOBcQPO1G0XOOQO1G0W1G0WOOQO7+%q7+%qOVQPO<OAN>OOVQPOAN>SOOQOG23eG23eOOQOG23aG23aODpQPOG23eOERQPO1G/_OEgQPOG23nOEnQPOG23nOOQOLD)PLD)POOQOLD)YLD)YO*wQPOLD)YOFPQPO!$'LtOOQO!)9B`!)9B`", + stateData: "Fi~O!xOS~OTQOVTO]PO^PO_PO`ROaROmUOpVOrWOxXOyYO}ZO!Q`O!S^O!T^O!U^O!V^O!W^O!X^O!hcO!ifO!kdO!mdO~OsiO~PVOc!zXd!zXe!zXf!zXg!zXh!zXi!zXj!zX!Y!zXl!zX~Ov!zX!PSX!ZSX![!zX!]!zX!^!zX!_!zX!`!zX!a!zX!b!zX!c!zX!d!zX!e!zX!v!zX~P!zOckOdlOemOfnOgoOhpOiqOjrOvsO![sO!]sO!^sO!_sO!`sO!asO!bsO!csO!dsO!esO~O!v!yX~P$lOV{O]PO^PO_PO`ROaROmUOpVOrWOxXOyYO}ZO!Q`O!S^O!T^O!U^O!V^O!W^O!X^O~OTyO~P&QOV!OOpVO~Os!QO~Om!RO~Om!SO~Om!TO~OckXdkXekXfkXgkXhkXikXjkXvkX!PSX!ZSX![kX!]kX!^kX!_kX!`kX!akX!bkX!ckX!dkX!ekX!vkX!YkXlkX~Os!UO~OV!VO~O!PsO!ZsO~OT!ZOV!YO~Os!^O~O!o!_O!p!`O!q!aO!r!bO!v!yX~OT!cO~OTRO~P&QO!YYX~P$lOU!fOcZXdZXeZXfZXgZXhZXiZXjZXvZX!YZX![ZX!]ZX!^ZX!_ZX!`ZX!aZX!bZX!cZX!dZX!eZX~OU!oO!YYX~O!Y!pO~OU!qO!o!_O!p!`O!q!aO!r!bO~Ov!rO~P!zOckOdlOemOfnOgoOhpOiqOjrO~OlYX!YYXtYX~P-aOl!sO!Y!pO~Ov!|O!Y!{O~Ov#SO~Ot#UO!Y#TO~OckOebifbigbihbiibijbivbi![bi!]bi!^bi!_bi!`bi!abi!bbi!cbi!dbi!ebi!vbiUbi!Ybilbi!obi!pbi!qbi!rbitbiwbiTbiVbi]bi^bi_bi`biabimbipbirbixbiybi}bi!Qbi!Sbi!Tbi!Ubi!Vbi!Wbi!Xbi!hbi!ibi!kbi!mbi|bi~Odbi~P.wOdlO~P.wOckOdlOemOjrOgbihbiibivbi![bi!]bi!^bi!_bi!`bi!abi!bbi!cbi!dbi!ebi!vbiUbi!Ybilbi!obi!pbi!qbi!rbitbiwbiTbiVbi]bi^bi_bi`biabimbipbirbixbiybi}bi!Qbi!Sbi!Tbi!Ubi!Vbi!Wbi!Xbi!hbi!ibi!kbi!mbi|bi~Ofbi~P2nOckOdlOemOfnOiqOjrOhbivbi![bi!]bi!^bi!_bi!`bi!abi!bbi!cbi!dbi!ebi!vbiUbi!Ybilbi!obi!pbi!qbi!rbitbiwbiTbiVbi]bi^bi_bi`biabimbipbirbixbiybi}bi!Qbi!Sbi!Tbi!Ubi!Vbi!Wbi!Xbi!hbi!ibi!kbi!mbi|bi~Ogbi~P6^OgoO~P6^OfnO~P2nOckOdlOemOfbigbihbiibijbivbi![bi!]bi!^bi!_bi!`bi!abi!bbi!cbi!dbi!ebi!vbiUbi!Ybilbi!obi!pbi!qbi!rbitbiwbiTbiVbi]bi^bi_bi`biabimbipbirbixbiybi}bi!Qbi!Sbi!Tbi!Ubi!Vbi!Wbi!Xbi!hbi!ibi!kbi!mbi|bi~O!oRi!pRi!qRi!rRi!vRiURilRi|RiwRi~P-aOU#XO~P-aOt#YO!Y!pO~Ov#ZO~Ow#[O~P-aO!P#]O~Ot#^O!Y!pO~OU#^O~P-aOt#aO!Y!pO~O!o!_O!q!ni!r!ni!v!niU!nil!ni|!niw!ni~O!p!ni~P?pO!p!`O~P?pO!o!_O!p!`O!q!aO!r!ni!v!niU!nil!ni|!niw!ni~OUXi!YXilXitXi~P-aOw#eO~P-aOV#fO~OckOdlOemOfnOgoOhpOiqOjrO~PVOt!ui!Y!ui~P-aOw#nO~P-aO!o!_O!p!`O!q!aO!r!bOl{X|{X~Ol#pO|#oO~Ow#qO~P-aO!o!_O!p!`O!q!aO!r!bO!v!jyU!jyl!jy|!jyw!jy~Ol#rO!o!_O!p!`O!q!aO!r!bO~OU#sO~P-aOl#xO!o!_O!p!`O!q!aO!r!bO~O!o!_O!p!`O!q!aO!r!bOl{i|{i~Ol#yO~P$lOw#zO!o!_O!p!`O!q!aO!r!bO~Ol#|O~P-aOr!S!i!Q`a!U!V!W!X!TT}yxy~", + goto: "-}!{PP!|#v$WPPP$t%x&T&f(dPPPPP)`PPPPPPPP(dPP*^+YP*^PPP*^PPPP*^,XPP*^PP,[PPPPPPPPPPPPPPPPPP#v-WPP-WP-hP#vPPPP-k-n-qPPP-w(dSgO#UQxTQ!XcQ#O!_Q#P!`Q#Q!aQ#R!bQ#h#[Q#k#`Q#l#eQ#t#nQ#u#oR#w#qmhOTc!_!`!a!b#U#[#`#e#n#o#qlbOTc!_!`!a!b#U#[#`#e#n#o#qQ![dQ!v!RQ!x!TR#_!{!U[Uklmnopqrs{!O!Q!S!U!V!Y!^!p!r!|#S#Z#]#f#zl]OTc!_!`!a!b#U#[#`#e#n#o#qX!Zd!R!T!{UvT{!YX}U!Q!U!^UwT{!YQ|UQ!u!QQ!y!UR!}!^SSO#UQtT[zU{!Q!U!Y!^d!Wc!_!`!a!b#[#`#e#n#oQ!fkQ!glQ!hmQ!inQ!joQ!kpQ!lqQ!mrQ!nsQ!t!OQ!w!SQ!z!VQ#V!pQ#W!rQ#`!|Q#b#SQ#g#ZQ#j#]Q#m#fQ#v#qR#{#z!s_OTUcklmnopqrs{!O!Q!S!U!V!Y!^!_!`!a!b!p!r!|#S#U#Z#[#]#`#e#f#n#o#q#z!n_OUcklmnopqrs!O!Q!S!U!V!Y!^!_!`!a!b!p!r!|#S#U#Z#[#]#`#e#f#n#o#q#zTuT{!s[OTUcklmnopqrs{!O!Q!S!U!V!Y!^!_!`!a!b!p!r!|#S#U#Z#[#]#`#e#f#n#o#q#z!r[OTUcklmnopqrs{!O!Q!S!U!V!Y!^!_!`!a!b!p!r!|#S#U#Z#[#]#`#e#f#n#o#q#zR!PVR#i#[!saOTUcklmnopqrs{!O!Q!S!U!V!Y!^!_!`!a!b!p!r!|#S#U#Z#[#]#`#e#f#n#o#q#zmeOTc!_!`!a!b#U#[#`#e#n#o#qR!]dRjOR!eiQ!diR#c#TQjOR#d#U", + nodeNames: "⚠ Expression Logic Logic_predicates Variable Local ) ( Tuple Setexpr_enum_min2 Setexpr_enum Setexpr Literal Integer EmptySet IntegerSet Global Radical Setexpr_binary + - * ∪ \\ ∆ ∩ × Setexpr_generators } { Enumeration Boolean ℬ Filter_expression Filter [ ] Declarative ∈ | PrefixD PrefixI Imperative Imp_blocks ; PrefixR Recursion := Function TextFunction BigPr SmallPr Card Bool Debool Red , :∈ ∉ ⊆ ⊄ ⊂ > ≥ < ≤ ≠ = Logic_unary Negation ¬ Predicate Logic_quantor ∀ Variable_pack ∃ Logic_binary ⇔ ⇒ ∨ & Function_decl Arguments Declaration", + maxTerm: 88, + nodeProps: [ + ["openedBy", 6,"(",28,"{"], + ["closedBy", 7,")",29,"}"] + ], + skippedNodes: [0], + repeatNodeCount: 0, + tokenData: "6g~R!iX^%ppq%pvw&exy&jyz&oz{&t{|&y|}'O}!O'T!Q!['Y![!]'b!]!^'u!^!_'z!_!`(P!`!a(U!c!d(Z!e!f(Z!f!g(i!h!i(q!k!l)e!r!s)j!t!u*^!u!v(Z!v!w(Z!z!{(Z!|!}*n!}#O*s#O#P*x#P#Q*}#R#S+S#T#U+S#U#V+j#V#W-Y#W#X.u#X#d+S#d#e1_#e#f+S#f#g2t#g#o+S#o#p4O#p#q4T#q#r4Y#y#z%p$f$g%p$r$s4_%o%p4d5i6S+S#BY#BZ%p$IS$I_%p$I|$JO%p$JT$JU%p$KV$KW%p% l% m4i%%Y%%Z4n%%[%%]4s%&Y%&Z4x%&]%&^4}%&_%&`5S%&`%&a5X%&b%&c5^%&c%&d5c%'S%'T5h%'T%'U5m%'U%'V5r%(^%(_5w%(b%(c5|%(c%(d6R%)Q%)R6W%)S%)T6]%)U%)V6b&FU&FV%p~%uY!x~X^%ppq%p#y#z%p$f$g%p#BY#BZ%p$IS$I_%p$I|$JO%p$JT$JU%p$KV$KW%p&FU&FV%p~&jO!r~~&oOV~~&tOU~~&yOe~~'OOc~~'TO!Y~~'YOd~~'_P]~!Q!['Y~'eQ!_!`'k%&b%&c'p~'pO!P~~'uO!Z~~'zO|~~(PO!b~~(UO!e~~(ZO!`~~(^P!Q![(a~(fP`~!Q![(a~(nPx~!Q![(a~(tQ!Q![(z#]#^)S~)PP!Q~!Q![(z~)VP!R![)Y~)_Qr~|})S!Q![)Y~)jOy~~)mQ!Q![)s#f#g){~)xP!i~!Q![)s~*OP!R![*R~*WQ!S~|}){!Q![*R~*cP}~!Q![*f~*kPa~!Q![*f~*sO_~~*xOs~~*}Og~~+SOt~~+XRT~!Q![+b#T#o+S5i6S+S~+gPT~!Q![+b~+oTT~!Q![+b#T#c+S#c#d,O#d#o+S5i6S+S~,TTT~!Q![+b#T#c+S#c#d,d#d#o+S5i6S+S~,iTT~!Q![+b#T#`+S#`#a,x#a#o+S5i6S+S~-PR!V~T~!Q![+b#T#o+S5i6S+S~-_ST~!Q![+b#T#U-k#U#o+S5i6S+S~-pTT~!Q![+b#T#f+S#f#g.P#g#o+S5i6S+S~.UTT~!Q![+b#T#W+S#W#X.e#X#o+S5i6S+S~.lR!U~T~!Q![+b#T#o+S5i6S+S~.zTT~!Q![+b#T#X+S#X#Y/Z#Y#o+S5i6S+S~/`TT~!Q![+b#T#U+S#U#V/o#V#o+S5i6S+S~/tTT~!Q![+b#T#c+S#c#d0T#d#o+S5i6S+S~0YTT~!Q![+b#T#c+S#c#d0i#d#o+S5i6S+S~0nTT~!Q![+b#T#`+S#`#a0}#a#o+S5i6S+S~1UR!W~T~!Q![+b#T#o+S5i6S+S~1dTT~!Q![+b#T#f+S#f#g1s#g#o+S5i6S+S~1xST~!Q!R+b!R![2U#T#o+S5i6S+S~2]Q!T~T~|}2c!Q![2U~2fP!R![2i~2nQ!T~|}2c!Q![2i~2yTT~!Q![+b#T#X+S#X#Y3Y#Y#o+S5i6S+S~3_TT~!Q![+b#T#W+S#W#X3n#X#o+S5i6S+S~3uR!X~T~!Q![+b#T#o+S5i6S+S~4TOm~~4YOw~~4_Ol~~4dO!h~~4iOj~~4nOp~~4sO!p~~4xO!o~~4}O!k~~5SO!m~~5XO^~~5^Oh~~5cOv~~5hO![~~5mO!q~~5rOi~~5wOf~~5|O!d~~6RO!c~~6WO!a~~6]O!_~~6bO!^~~6gO!]~", + tokenizers: [0], + topRules: {"Expression":[0,1]}, + tokenPrec: 1710 +}) diff --git a/rsconcept/frontend/src/components/RSInput/rslang/rslangAST.grammar b/rsconcept/frontend/src/components/RSInput/rslang/rslangAST.grammar new file mode 100644 index 00000000..62ad5512 --- /dev/null +++ b/rsconcept/frontend/src/components/RSInput/rslang/rslangAST.grammar @@ -0,0 +1,247 @@ +/////////////////////////////////////////////////////////// +// ------------- Generator Definitions -------------------- +/////////////////////////////////////////////////////////// +@detectDelim + +/////////////////////////////////////////////////////////// +// ------------- Precedence Definitions -------------------- +/////////////////////////////////////////////////////////// +@precedence { + plus @left minus @left, + times @left, + not @right, + log_equiv @left, + log_impl @left, + log_or @left, + log_and @left, + set_decart @left set_union @left set_intersect @left set_minus @left set_symminus @left, + set_bool @right, + quant @right +} + +/////////////////////////////////////////////////////////// +// ------------- Terminal Tokens -------------------------- +/////////////////////////////////////////////////////////// +@tokens { + space { @whitespace+ } + Integer { $[0-9]+ } + EmptySet { "∅" } + IntegerSet { "Z" } + + BigPr { "Pr"$[1-9]$[0-9]*(","$[1-9]$[0-9]*)* } + SmallPr { "pr"$[1-9]$[0-9]*(","$[1-9]$[0-9]*)* } + Filter { "Fi"$[1-9]$[0-9]*(","$[1-9]$[0-9]*)* } + Card { "card" } + Bool { "bool" } + Debool { "debool" } + Red { "red" } + + Global { $[XCSDAT]$[0-9]+ } + Function { "F"$[0-9]+ } + Predicate { "P"$[0-9]+ } + Radical { "R"$[0-9]+ } + Local { $[_a-zα-ω]($[a-zα-ω])*$[0-9]* } + PrefixR { "R" } + PrefixI { "I" } + PrefixD { "D" } + + "¬" + "∀" "∃" "⇔" "⇒" "∨" "&" + "ℬ" + "+" "-" "*" "∪" "\\" "∆" "∩" "×" + "∈" "∉" "⊆" "⊄" "⊂" ">" "≥" "≤" "<" "≠" "=" + ":∈" ":=" + + "," ";" "|" + "[" "]" + "{" "}" + "(" ")" + + @precedence { + Filter + BigPr + Predicate + Function + Global + Radical + PrefixR + PrefixI + PrefixD + } + @precedence { + Card + Bool + Debool + Red + SmallPr + Local + } +} + +@skip { space } + + +/////////////////////////////////////////////////////////////////////////////// +// ------------------------- Grammar Rules ------------------------------------ +/////////////////////////////////////////////////////////////////////////////// + +// ------------------------- Language Expression ------------------------------ +@top Expression { + logic_or_setexpr | + Function_decl +} +logic_or_setexpr { + Logic | + Setexpr +} +Function_decl { + "[" Arguments "]" logic_or_setexpr +} + + +// ------------------------- Variables and arguments ------------------------- +Arguments { + Declaration | + Arguments "," Declaration +} +Declaration { + Local "∈" Setexpr +} +Variable { + Local | + Tuple +} +Variable_pack { + Variable | + Variable_pack "," Variable +} + + +// ------------------------- Logic Expressions -------------------------------- +Logic { + Logic_predicates | + Logic_unary | + Logic_binary | + "(" Logic ")" +} + +Logic_predicates { + Variable ":∈" Setexpr | + Variable ":=" Setexpr | + Setexpr "∈" Setexpr | + Setexpr "∉" Setexpr | + Setexpr "⊆" Setexpr | + Setexpr "⊄" Setexpr | + Setexpr "⊂" Setexpr | + Setexpr ">" Setexpr | + Setexpr "≥" Setexpr | + Setexpr "<" Setexpr | + Setexpr "≤" Setexpr | + Setexpr "≠" Setexpr | + Setexpr "=" Setexpr +} + +Logic_unary { + Negation { !not "¬" Logic } | + Predicate "[" Setexpr_enum "]" | + Logic_quantor +} + +Logic_quantor { + "∀" Variable_pack "∈" Setexpr !quant Logic | + "∃" Variable_pack "∈" Setexpr !quant Logic +} + +Logic_binary { + Logic !log_equiv "⇔" Logic | + Logic !log_impl "⇒" Logic | + Logic !log_or "∨" Logic | + Logic !log_and "&" Logic +} + + +// ------------------------- Set Expressions ---------------------------------- +Setexpr { + Literal | + identifier | + Setexpr_binary | + Setexpr_generators | + Function "[" Setexpr_enum "]" | + TextFunction "(" Setexpr ")" +} +TextFunction { + BigPr | + SmallPr | + Card | + Bool | + Debool | + Red +} +Setexpr_enum { + Setexpr | + Setexpr_enum_min2 +} +Setexpr_enum_min2 { + Setexpr_enum "," Setexpr +} + +Literal { + Integer | + EmptySet | + IntegerSet +} +identifier { + Local | + Global | + Radical +} + +Setexpr_binary { + Setexpr !plus "+" Setexpr | + Setexpr !minus "-" Setexpr | + Setexpr !times "*" Setexpr | + Setexpr !set_union "∪" Setexpr | + Setexpr !set_minus "\\" Setexpr | + Setexpr !set_symminus "∆" Setexpr | + Setexpr !set_intersect "∩" Setexpr | + Setexpr !set_decart "×" Setexpr | + "(" Setexpr_binary ")" +} + +Setexpr_generators { + Enumeration | + Tuple | + Boolean | + Filter_expression | + Declarative | + Imperative | + Recursion +} +Enumeration { + "{" Setexpr_enum "}" +} +Tuple { + "(" Setexpr_enum_min2 ")" +} +Boolean { + !set_bool "ℬ" "(" Setexpr ")" | + !set_bool "ℬ" Boolean +} +Filter_expression { + Filter "[" Setexpr_enum "]" "(" Setexpr ")" +} + +Declarative { + "{" Local "∈" Setexpr "|" Logic "}" | + PrefixD "{" Variable "∈" Setexpr "|" Logic "}" +} +Recursion { + PrefixR "{" Variable ":=" Setexpr ("|" Logic)? "|" Setexpr "}" +} +Imperative { + PrefixI "{" Setexpr "|" Imp_blocks "}" +} +Imp_blocks { + Logic | + Imp_blocks ";" Logic +} diff --git a/rsconcept/frontend/src/components/RSInput/rslang/rslangFull.grammar b/rsconcept/frontend/src/components/RSInput/rslang/rslangFast.grammar similarity index 100% rename from rsconcept/frontend/src/components/RSInput/rslang/rslangFull.grammar rename to rsconcept/frontend/src/components/RSInput/rslang/rslangFast.grammar diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx index f06f1d00..1266dcf1 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/EditorRSExpression.tsx @@ -6,7 +6,9 @@ import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { toast } from 'react-toastify'; import BadgeHelp from '@/components/info/BadgeHelp'; +import { CProps } from '@/components/props'; import RSInput from '@/components/RSInput'; +import { parser as rslangParser } from '@/components/RSInput/rslang/parserAST'; import { RSTextWrapper } from '@/components/RSInput/textEditing'; import Overlay from '@/components/ui/Overlay'; import { useRSForm } from '@/context/RSFormContext'; @@ -18,6 +20,7 @@ import { ConstituentaID, IConstituenta } from '@/models/rsform'; import { getDefinitionPrefix } from '@/models/rsformAPI'; import { IExpressionParse, IRSErrorDescription, SyntaxTree } from '@/models/rslang'; import { TokenID } from '@/models/rslang'; +import { transformAST } from '@/utils/codemirror'; import { storage } from '@/utils/constants'; import { errors, labelTypification } from '@/utils/labels'; @@ -124,17 +127,25 @@ function EditorRSExpression({ setIsModified(true); }, []); - function handleShowAST() { - handleCheckExpression(parse => { - if (!parse.astText) { - toast.error(errors.astFailed); - } else { - setSyntaxTree(parse.ast); - // TODO: return prefix from parser API instead of prefixLength - setExpression(getDefinitionPrefix(activeCst) + value); - setShowAST(true); - } - }); + function handleShowAST(event: CProps.EventMouse) { + if (event.ctrlKey) { + const tree = rslangParser.parse(value); + const ast = transformAST(tree); + setSyntaxTree(ast); + setExpression(value); + setShowAST(true); + } else { + handleCheckExpression(parse => { + if (!parse.astText) { + toast.error(errors.astFailed); + } else { + setSyntaxTree(parse.ast); + // TODO: return prefix from parser API instead of prefixLength + setExpression(getDefinitionPrefix(activeCst) + value); + setShowAST(true); + } + }); + } } const controls = useMemo( diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/ToolbarRSExpression.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/ToolbarRSExpression.tsx index a80b3bc1..2fe50d41 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/ToolbarRSExpression.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/ToolbarRSExpression.tsx @@ -1,4 +1,5 @@ import { IconControls, IconTree } from '@/components/Icons'; +import { CProps } from '@/components/props'; import MiniButton from '@/components/ui/MiniButton'; import Overlay from '@/components/ui/Overlay'; import { useRSForm } from '@/context/RSFormContext'; @@ -8,7 +9,7 @@ interface ToolbarRSExpressionProps { showControls: boolean; toggleControls: () => void; - showAST: () => void; + showAST: (event: CProps.EventMouse) => void; } function ToolbarRSExpression({ disabled, showControls, toggleControls, showAST }: ToolbarRSExpressionProps) { diff --git a/rsconcept/frontend/src/styling/color.ts b/rsconcept/frontend/src/styling/color.ts index b9d84653..2e67fc06 100644 --- a/rsconcept/frontend/src/styling/color.ts +++ b/rsconcept/frontend/src/styling/color.ts @@ -6,6 +6,7 @@ import { GramData, Grammeme, NounGrams, PartOfSpeech, VerbGrams } from '@/models import { GraphColoring } from '@/models/miscellaneous'; import { CstClass, ExpressionStatus, IConstituenta } from '@/models/rsform'; import { ISyntaxTreeNode, TokenID } from '@/models/rslang'; +import { PARAMETER } from '@/utils/constants'; /** * Represents application color theme configuration. @@ -375,8 +376,65 @@ export function colorBgSyntaxTree(node: ISyntaxTreeNode, colors: IColorTheme): s case TokenID.ITERATE: return colors.bgRed; } + + switch (node.data.value) { + case 'Expression': + case 'Local': + return colors.bgGreen; + + case 'Global': + case 'Radical': + case 'Function': + case 'Predicate': + case 'Literal': + case 'Integer': + case 'EmptySet': + case 'IntegerSet': + return colors.bgTeal; + + case 'Logic': + case 'Logic_predicates': + case 'Variable': + case 'Tuple': + case 'Setexpr_enum_min2': + case 'Setexpr_enum': + case 'Setexpr': + case 'Setexpr_binary': + case 'Setexpr_generators': + case 'Enumeration': + case 'Boolean': + case 'Filter_expression': + case 'Filter': + case 'Declarative': + case 'Imperative': + case 'Imp_blocks': + case 'Recursion': + case 'TextFunction': + case 'Logic_unary': + case 'Logic_quantor': + case 'Variable_pack': + case 'Logic_binary': + case 'Function_decl': + case 'Arguments': + case 'Declaration': + return colors.bgBlue; + + case 'BigPr': + case 'SmallPr': + case 'Card': + case 'Bool': + case 'Debool': + case 'Red': + case 'PrefixD': + case 'PrefixI': + case 'PrefixR': + return colors.bgPurple; + + case PARAMETER.errorNodeLabel: + return colors.bgRed; + } // node - return colors.bgRed; + return colors.bgPurple; } /** diff --git a/rsconcept/frontend/src/utils/codemirror.ts b/rsconcept/frontend/src/utils/codemirror.ts index 5caaf5ef..1cbdff0c 100644 --- a/rsconcept/frontend/src/utils/codemirror.ts +++ b/rsconcept/frontend/src/utils/codemirror.ts @@ -13,8 +13,10 @@ import { IEntityReference, ISyntacticReference } from '@/models/language'; import { parseEntityReference, parseGrammemes, parseSyntacticReference } from '@/models/languageAPI'; import { IConstituenta } from '@/models/rsform'; import { isBasicConcept } from '@/models/rsformAPI'; +import { SyntaxTree } from '@/models/rslang'; import { colorFgGrammeme, IColorTheme } from '../styling/color'; +import { PARAMETER } from './constants'; import { describeConstituentaTerm, labelCstTypification, labelGrammeme } from './labels'; /** @@ -91,6 +93,56 @@ export function printTree(tree: Tree): string { return state.output; } +/** + * Transform Tree to {@link SyntaxTree}. + */ +export function transformAST(tree: Tree): SyntaxTree { + const result: SyntaxTree = []; + const parents: number[] = []; + const cursor = tree.cursor(); + let finished = false; + let leave = true; + while (!finished) { + let node = cursorNode(cursor); + node.isLeaf = !cursor.firstChild(); + + leave = true; + result.push({ + uid: result.length, + parent: parents.length > 0 ? parents[parents.length - 1] : result.length, + typeID: node.type.id, + start: node.from, + finish: node.to, + data: { + dataType: 'string', + value: node.type.name == '⚠' ? PARAMETER.errorNodeLabel : node.type.name + } + }); + parents.push(result.length - 1); + + if (!node.isLeaf) continue; + + for (;;) { + node = cursorNode(cursor, node.isLeaf); + if (leave) { + parents.pop(); + } + + leave = cursor.type.isAnonymous; + node.isLeaf = false; + if (cursor.nextSibling()) { + break; + } + if (!cursor.parent()) { + finished = true; + break; + } + leave = true; + } + } + return result; +} + /** * Retrieves a list of all nodes, containing given range and corresponding to a filter. */ diff --git a/rsconcept/frontend/src/utils/constants.ts b/rsconcept/frontend/src/utils/constants.ts index 8e4daca4..97e09d12 100644 --- a/rsconcept/frontend/src/utils/constants.ts +++ b/rsconcept/frontend/src/utils/constants.ts @@ -34,6 +34,7 @@ export const PARAMETER = { statSmallThreshold: 3, // characters - threshold for small labels - small font logicLabel: 'LOGIC', + errorNodeLabel: '[ERROR]', exteorVersion: '4.9.5', TOOLTIP_WIDTH: 'max-w-[29rem]' diff --git a/rsconcept/frontend/src/utils/labels.ts b/rsconcept/frontend/src/utils/labels.ts index 6ed02ec5..2b4e5f1d 100644 --- a/rsconcept/frontend/src/utils/labels.ts +++ b/rsconcept/frontend/src/utils/labels.ts @@ -622,6 +622,9 @@ export function labelSyntaxTree(node: ISyntaxTreeNode): string { return labelToken(node.typeID); } // node + if (node.data.value) { + return node.data.value as string; + } return 'UNKNOWN ' + String(node.typeID); } diff --git a/scripts/dev/PopulateDevData.ps1 b/scripts/dev/PopulateDevData.ps1 index d217ad07..109f7c58 100644 --- a/scripts/dev/PopulateDevData.ps1 +++ b/scripts/dev/PopulateDevData.ps1 @@ -3,10 +3,6 @@ $container= Read-Host -Prompt "Enter backend container name: " function PopulateDevData() { - ImportInitialData -} - -function ImportInitialData() { docker exec ` -it $container ` python3.12 manage.py loaddata ./fixtures/InitialData.json