From 53187efd6ca596f19f575aafeda84ec1f2684295 Mon Sep 17 00:00:00 2001 From: IRBorisov <8611739+IRBorisov@users.noreply.github.com> Date: Mon, 14 Aug 2023 18:40:19 +0300 Subject: [PATCH] Implement full RSLang grammar --- rsconcept/frontend/package.json | 2 +- .../frontend/src/components/RSInput/index.tsx | 4 +- .../components/RSInput/rslang/highlight.ts | 11 +- .../components/RSInput/rslang/parser.terms.ts | 36 +++- .../components/RSInput/rslang/parser.test.ts | 26 +++ .../src/components/RSInput/rslang/parser.ts | 20 +- .../RSInput/rslang/rslangFull.grammar | 200 ++++++++++++++++++ .../{rslang.grammar => rslangLex.grammar} | 9 +- .../elements/ViewSideConstituents.tsx | 2 +- .../frontend/src/utils/print-lezer-tree.ts | 60 ++++++ 10 files changed, 342 insertions(+), 28 deletions(-) create mode 100644 rsconcept/frontend/src/components/RSInput/rslang/parser.test.ts create mode 100644 rsconcept/frontend/src/components/RSInput/rslang/rslangFull.grammar rename rsconcept/frontend/src/components/RSInput/rslang/{rslang.grammar => rslangLex.grammar} (74%) create mode 100644 rsconcept/frontend/src/utils/print-lezer-tree.ts diff --git a/rsconcept/frontend/package.json b/rsconcept/frontend/package.json index dd1e2f40..5a8d3fed 100644 --- a/rsconcept/frontend/package.json +++ b/rsconcept/frontend/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "scripts": { - "prepare": "lezer-generator src/components/RSInput/rslang/rslang.grammar -o src/components/RSInput/rslang/parser.ts", + "prepare": "lezer-generator src/components/RSInput/rslang/rslangFull.grammar -o src/components/RSInput/rslang/parser.ts", "test": "jest", "dev": "vite", "build": "tsc && vite build", diff --git a/rsconcept/frontend/src/components/RSInput/index.tsx b/rsconcept/frontend/src/components/RSInput/index.tsx index c77603c9..e6f5ea2f 100644 --- a/rsconcept/frontend/src/components/RSInput/index.tsx +++ b/rsconcept/frontend/src/components/RSInput/index.tsx @@ -40,8 +40,8 @@ const editorSetup: BasicSetupOptions = { const editorExtensions = [ EditorView.lineWrapping, - bracketMatching(), RSLanguage, + bracketMatching(), //cursorTooltip(), ]; @@ -74,6 +74,7 @@ function RSInput({ { tag: t.variableName, class: 'text-[#24821a]' }, // LocalID { tag: t.propertyName, class: '' }, // Radical { tag: t.keyword, class: 'text-[#001aff]' }, // keywords + { tag: t.literal, class: 'text-[#001aff]' }, // literals { tag: t.controlKeyword, class: 'font-semibold'}, // R | I | D { tag: t.unit, class: 'text-[0.75rem]' }, // indicies ] @@ -94,6 +95,7 @@ function RSInput({ { tag: t.variableName, class: 'text-[#69bf60]' }, // LocalID { tag: t.propertyName, class: '' }, // Radical { tag: t.keyword, class: 'text-[#808dff]' }, // keywords + { tag: t.literal, class: 'text-[#808dff]' }, // literals { tag: t.controlKeyword, class: 'font-semibold'}, // R | I | D { tag: t.unit, class: 'text-[0.75rem]' }, // indicies ] diff --git a/rsconcept/frontend/src/components/RSInput/rslang/highlight.ts b/rsconcept/frontend/src/components/RSInput/rslang/highlight.ts index 5a9eba86..69bf0a48 100644 --- a/rsconcept/frontend/src/components/RSInput/rslang/highlight.ts +++ b/rsconcept/frontend/src/components/RSInput/rslang/highlight.ts @@ -3,12 +3,17 @@ import {styleTags, tags} from '@lezer/highlight'; export const highlighting = styleTags({ Index: tags.unit, ComplexIndex: tags.unit, - Integer: tags.literal, - + Literal: tags.literal, + Radical: tags.propertyName, + Function: tags.name, + Predicate: tags.name, Global: tags.name, Local: tags.variableName, TextFunction: tags.keyword, - ConstructPrefix: tags.controlKeyword + Filter: tags.keyword, + PrefixR: tags.controlKeyword, + PrefixI: tags.controlKeyword, + PrefixD: tags.controlKeyword }); \ No newline at end of file diff --git a/rsconcept/frontend/src/components/RSInput/rslang/parser.terms.ts b/rsconcept/frontend/src/components/RSInput/rslang/parser.terms.ts index 915682e3..0d2a86b4 100644 --- a/rsconcept/frontend/src/components/RSInput/rslang/parser.terms.ts +++ b/rsconcept/frontend/src/components/RSInput/rslang/parser.terms.ts @@ -1,11 +1,35 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. export const Expression = 1, - TextFunction = 2, - ComplexIndex = 3, - ConstructPrefix = 4, - Integer = 5, + LogicPredicate = 2, + Literal = 3, + Local = 4, + Index = 5, Global = 6, Radical = 7, - Local = 8, - Index = 9 + BinaryOperation = 8, + Enumeration = 21, + Tuple = 22, + Boolean = 23, + Declarative = 25, + PrefixD = 27, + Variable = 28, + VariableComposite = 29, + PrefixI = 30, + Imperative = 31, + ImperativeBlocks = 32, + ImperativeIteration = 33, + ImperativeAssignment = 35, + ImperativeCondition = 37, + PrefixR = 38, + Recursion = 39, + FunctionCall = 41, + Function = 42, + TextFunctionExpression = 44, + TextFunction = 45, + ComplexIndex = 46, + Filter = 47, + Predicate = 58, + QuantorVariable = 62, + LogicBinary = 63, + FunctionDeclaration = 68 diff --git a/rsconcept/frontend/src/components/RSInput/rslang/parser.test.ts b/rsconcept/frontend/src/components/RSInput/rslang/parser.test.ts new file mode 100644 index 00000000..4c0e80c6 --- /dev/null +++ b/rsconcept/frontend/src/components/RSInput/rslang/parser.test.ts @@ -0,0 +1,26 @@ +import { printTree } from '../../../utils/print-lezer-tree'; +import { parser } from './parser'; + +const testData = [ + ['a1', '[Expression[Local[Index]]]'], + ['A1', '[Expression[Global]]'], + ['∅', '[Expression[Literal]]'], + ['Z', '[Expression[Literal]]'], + ['1', '[Expression[Literal]]'], + ['12=41', '[Expression[LogicPredicate[Literal][=][Literal]]]'], + ['0-5', '[Expression[BinaryOperation[Literal][-][Literal]]]'], + ['12+41', '[Expression[BinaryOperation[Literal][+][Literal]]]'], + ['a1∪Z', '[Expression[BinaryOperation[Local[Index]][∪][Literal]]]'], + ['ℬℬ(X1)', '[Expression[Boolean[ℬ][Boolean[ℬ][(][Global][)]]]]'], + ['P2[S1]', '[Expression[PredicateCall[Predicate][[][Global][]]]]'], + ['[σ∈R1×R1] F6[σ]', '[Expression[FunctionDeclaration[[][Local][∈][BinaryOperation[Radical][×][Radical]][]][FunctionCall[Function][[][Local][]]]]]'], + ['D{ξ∈red(S1) | ξ=ξ}', '[Expression[Declarative[PrefixD][{][Variable[Local]][∈][TextFunctionExpression[TextFunction][(][Global][)]][LogicPredicate[Local][=][Local]][}]]]'], +]; + +describe('Testing RSParser', () => { + it.each(testData)('Parse %p', + (input: string, expectedTree: string) => { + const tree = parser.parse(input); + expect(printTree(tree)).toBe(expectedTree); + }); +}); diff --git a/rsconcept/frontend/src/components/RSInput/rslang/parser.ts b/rsconcept/frontend/src/components/RSInput/rslang/parser.ts index d5a0dc71..669b29fb 100644 --- a/rsconcept/frontend/src/components/RSInput/rslang/parser.ts +++ b/rsconcept/frontend/src/components/RSInput/rslang/parser.ts @@ -3,16 +3,20 @@ import {LRParser} from "@lezer/lr" import {highlighting} from "./highlight.ts" export const parser = LRParser.deserialize({ version: 14, - states: "!^QVQPOOO}QPO'#C^OOQO'#C^'#C^O!SQQO'#CdOOQO'#Cj'#CjOOQO'#Cf'#CfQVQPOOOOQO,58x,58xOOQO,59O,59OOOQO-E6d-E6d", - stateData: "#a~O]OS~OSSOTSOUSOVSO_PO`POaPObQOcQOdQOeQOfRO~ORVO~OXWOSWXTWXUWXVWXZWX_WX`WXaWXbWXcWXdWXeWXfWX~Oa_T]UVSbcde`bf~", - goto: "n_PP`PPPPP`PdPPPjTSOUQUORXUTTOU", - nodeNames: "⚠ Expression TextFunction ComplexIndex ConstructPrefix Integer Global Radical Local Index", - maxTerm: 22, + states: "7|O!pQPOOOOQO'#C_'#C_O!wQPO'#C`O&bQPO'#DvOVQPO'#CdO&iQPO'#CqO'yQPO'#CsO(RQPO'#CuO(WQPO'#C{O(]QPO'#DTOOQO'#D}'#D}O(bQPO'#DVO(gQQO'#DZOOQO'#DZ'#DZO(lQQO'#D]O(qQPO'#DYO(vQPO'#DYOOQO'#Dx'#DxO({QPO'#DgO&iQPO'#DiO)QQPO'#DkOOQO'#E^'#E^O)YQPO'#EcOOQO'#Ec'#EcO)kQPOOOOQO'#Dw'#DwO)TQPO'#DrQOQPOOOOQO'#Ca'#CaOOQO,58z,58zO&iQPO,59OO&iQPO,59OO&iQPO,59OO&iQPO,59OO&iQPO,59OO&iQPO,59OO&iQPO,59OO&iQPO,59OO&iQPO,58xO)yQPO'#EOO+[QPO,59OO+fQPO'#EPO+kQPO,59^O+sQPO,5:zO,pQPO'#EOO&iQPO'#CdO,}QPO,59]OOQO'#EO'#EOO-qQPO,59aO&iQPO,59_OOQO,59_,59_O)QQPO,59aO&iQPO,59gO)QQPO,59oO&iQPO,59qOOQO,59u,59uOOQO,59w,59wO&iQPO,59tO&iQPO,59tO&iQPO,5:RO%WQPO'#C^O.OQPO'#E_OOQO,5:T,5:TOOQO'#Cx'#CxO)QQPO'#CxO.ZQPO,5:VOOQO'#Dl'#DlOVQPO,5:XOVQPO,5:XOVQPO,5:XOVQPO,5:XO.cQPO'#EeOOQO'#Ed'#EdO.hQPO,5:^OOQO1G.j1G.jO0sQPO1G.jO0zQPO1G.jO3UQPO1G.jO5`QPO1G.jO5gQPO1G.jO5nQPO1G.jO6WQPO1G.jO8PQPO1G.dO&iQPO,5:kOOQO1G.x1G.xOOQO1G0f1G0fOOQO1G.w1G.wO&iQPO1G.{O8yQPO1G.yO9QQPO1G.{O9VQPO1G/RO9^QPO1G/ZO9cQPO1G/]O9kQPO1G/`O9rQPO1G/`O9zQPO1G/mO:SQPO,5:yOOQO'#ES'#ESO:XQPO,59dO:aQPO'#CyO)QQPO,5:|O:fQPO1G/qOOQO1G/s1G/sOiQPO1G0kOOQO1G0j1G0jOOQO7+%d7+%dOVQPO<sQPO<zQPO'#DxO?UQPO'#DROOQO'#ET'#ETOOQO'#C|'#C|O?jQPO<QOOQOG23XG23XO@cQPOG23XO@tQPO1G/TOAOQPO1G/VOOQO1G/S1G/SOAYQPOG23gOAaQPOG23gOOQOG23lG23lOOQOLD(sLD(sOOQOLD)RLD)RO&iQPOLD)ROArQPO!$'LmOOQO!)9BX!)9BXO:fQPO,59OO:fQPO,59OO:fQPO,59OO:fQPO,59OO:fQPO,59OO:fQPO,59OO:fQPO,59OO:fQPO,59OOAyQPO1G.jOCfQPO1G.jOFxQPO1G.jOHvQPO1G.jOH}QPO1G.jOIUQPO1G.jOI]QPO1G.j", + stateData: "KZ~O!iOS~OUaOVaOaSOdTOhUOkVOnWOvXOzZO![bO!^cO!mPO!nPO!oPO!pQO!y[O!z[O!{]O!|]O!}]O#O]O#P^O#TdO~O{jO~PVO!mlOXSXYSXZSX[SX]SX^SX_SX`SXjSX!QSX!RSX!SSX!TSX!USX!VSX!WSX!XSX!YSX!gSX!tSXcSX!bSX!cSX!dSX!eSXbSX!uSXtSXxSX![SX!^SX#TSXrSX!xSX~OXnOYoOZpO[qO]rO^sO_tO`uOjvO!QvO!RvO!SvO!TvO!UvO!VvO!WvO!XvO!YvO~O!g!jX~P%WOUaOVaOa}OdTOhUOkVOnWOvXOzZO!mPO!nPO!oPO!pQO!y[O!z[O!{]O!|]O!}]O#O]O#P^O~Oa!ROhUO~Od!TO~Od!UO~Od!VO~O{!WO~O!O!XO~O!O!YO~Oa!ZO~O{![O~O{!]O~Oa!bO!pQO~O!b#VX!c#VX!d#VX!e#VX!g!jX~O!b!eO!c!fO!d!gO!e!hO~O!t!rX~P%WOX!lXY!lXZ!lX[!lX]!lX^!lX_!lX`!lXj!lX!Q!lX!R!lX!S!lX!T!lX!U!lX!V!lX!W!lX!X!lX!Y!lX~Ob!lO!t!lX~P*QO!t!uO~Ob!vO!t!rX~Ob!wO!b#VX!c#VX!d#VX!e#VX~OXnOYoOZpO[qO]rO^sO_tO`uO~Oc!rX!t!rXx!rX~P,UOc!xO!t!uO~OX!lXY!lXZ!lX[!lX]!lX^!lX_!lX`!lX~Oj!yOc!lX!t!lX~P-VO![bO!^cO#TdO~Oj#XO!t#WO~Oj#^O~Ox#`O!t#_O~OXnOZWi[Wi]Wi^Wi_Wi`WijWi!QWi!RWi!SWi!TWi!UWi!VWi!WWi!XWi!YWi!gWibWi!tWicWi!bWi!cWi!dWi!eWi!uWixWi![Wi!^Wi#TWi!xWi~OYWi~P.pOYoO~P.pOXnOYoOZpO`uO]Wi^Wi_WijWi!QWi!RWi!SWi!TWi!UWi!VWi!WWi!XWi!YWi!gWibWi!tWicWi!bWi!cWi!dWi!eWi!uWixWi![Wi!^Wi#TWi!xWi~O[Wi~P1ROXnOYoOZpO[qO_tO`uO^WijWi!QWi!RWi!SWi!TWi!UWi!VWi!WWi!XWi!YWi!gWibWi!tWicWi!bWi!cWi!dWi!eWi!uWixWi![Wi!^Wi#TWi!xWi~O]Wi~P3]O]rO~P3]O[qO~P1RO[Wi]Wi^Wi_Wi`Wi~OXnOYoOZpOjWi!QWi!RWi!SWi!TWi!UWi!VWi!WWi!XWi!YWi!gWibWi!tWicWi!bWi!cWi!dWi!eWi!uWixWi![Wi!^Wi#TWi!xWi~P5uO!bQi!cQi!dQi!eQi!gQibQi![Qi!^Qi#TQicQi!xQi!uQi~P,UOb#cO~P,UOj#dO~O!u#eO~P,UOt#fO~Ox#gO!t!uO~Ob#hO~P,UOx#iO!t!uO~Ox#jO!t!uO~Oa#kO~Ob#mO!t!vX~O!t#nO~OUaOVaOa}OdTOhUOkVOnWOvXOzZO!mPO!nPO!oPO!p#pO!y[O!z[O!{]O!|]O!}]O#O]O#P^O~O!b!eO!d!ai!e!ai!g!aib!aic!ai!x!ai!u!ai~O!c!ai~P;vO!c!fO~P;vO!b!eO!c!fO!d!gO!e!ai!g!aib!aic!ai!x!ai!u!ai~Ob!si!t!sic!six!si~P,UO!u#uO~P,UOa#}O~OX$gOY$hOZ$iO[$jO]$kO^$lO_$mO`$nO~P&iOx#Xi!t#Xi~P,UO!u$RO~P,UOr$SOt$TO~P*QOcuX!b#VX!c#VX!d#VX!e#VX!xuX~Oc$VO!x$UO~O!u$WO~P,UOc$YO!b#VX!c#VX!d#VX!e#VX~Ob$aO~P,UOc$bO!b#VX!c#VX!d#VX!e#VX~Ocqi!xqi~P,UOcsi!xsi~P,UOc$cO~P%WO!u$dO!b#VX!c#VX!d#VX!e#VX~Oc$fO~P,UOX$gOUWiVWiYWiZWiaWidWihWikWinWivWizWi!mWi!nWi!oWi!pWi!yWi!zWi!{Wi!|Wi!}Wi#OWi#PWi~P5uOX$gOY$hOUWiVWiZWiaWidWihWikWinWivWizWi!mWi!nWi!oWi!pWi!yWi!zWi!{Wi!|Wi!}Wi#OWi#PWi~P5uOX$gOY$hOZ$iO`$nOUWiVWi]Wi^Wi_WiaWidWihWikWinWivWizWi!mWi!nWi!oWi!pWi!yWi!zWi!{Wi!|Wi!}Wi#OWi#PWi~O[Wi~PEROX$gOY$hOZ$iO[$jO_$mO`$nOUWiVWi^WiaWidWihWikWinWivWizWi!mWi!nWi!oWi!pWi!yWi!zWi!{Wi!|Wi!}Wi#OWi#PWi~O]Wi~PGPO]$kO~PGPO[$jO~PEROX$gOY$hOZ$iOUWiVWiaWidWihWikWinWivWizWi!mWi!nWi!oWi!pWi!yWi!zWi!{Wi!|Wi!}Wi#OWi#PWi~P5uO#P!y![zUV!{!|!}#O!z!pvnkn~", + goto: "3Y#YPP#Z#n$t&[PP&_PPPPPPPPPPPP'g'g(mP'gPP)v*YP'g*]*`P*`P*`P'gP#nPP#n*dP+jPPPPPPPPP,pP,pP,p-Q-TPPPP-dPPP-g-m.YPPPP#n0t1UPP1`1cPPPPPPPP1i1{2RP2e2h3P3SjiOS!e!f!g!h#`#e#k#u$R$U$WT!_c#q#XaOSTcnopqrstuv}!R!U!W!Z![!]!e!f!g!h!u!y#X#^#`#d#e#f#k#q#u#}$R$S$T$U$W$d$g$h$i$j$k$l$m$n#QaOScnopqrstuv}!R!U!W!Z![!]!e!f!g!h!u!y#X#^#`#d#f#k#q#u#}$R$S$T$W$d$g$h$i$j$k$l$m$nQ!QT[!ad!T!V!b#W#nS!ij#_T#w#e$URmQ#SaOTcnopqrstuv!R!U!W!Z![!]!e!f!g!h!u!y#X#^#`#d#e#f#k#q#u#}$R$S$T$U$W$d$g$h$i$j$k$l$m$nTxS}#XYOSTcnopqrstuv}!R!U!W!Z![!]!e!f!g!h!u!y#X#^#`#d#e#f#k#q#u#}$R$S$T$U$W$d$g$h$i$j$k$l$m$n#WYOSTcnopqrstuv}!R!U!W!Z![!]!e!f!g!h!u!y#X#^#`#d#e#f#k#q#u#}$R$S$T$U$W$d$g$h$i$j$k$l$m$nR!SUQ!ddQ!{!TQ!}!VQ#T!bQ#o#WR$O#nR#U!bR#{#eT#y#e$U#X_OSTcnopqrstuv}!R!U!W!Z![!]!e!f!g!h!u!y#X#^#`#d#e#f#k#q#u#}$R$S$T$U$W$d$g$h$i$j$k$l$m$n#X`OSTcnopqrstuv}!R!U!W!Z![!]!e!f!g!h!u!y#X#^#`#d#e#f#k#q#u#}$R$S$T$U$W$d$g$h$i$j$k$l$m$nmeOS!_!e!f!g!h#`#e#k#u$R$U$WR!cdkiOS!e!f!g!h#`#e#k#u$R$U$WRkOQkOR#t#`SfO#`Wg!e!f!g!hS{S#kS#x#e$UQ$Q#uQ$Z$RR$`$WSRO#`QwSY|T}!W![!]f!^c!e!f!g!h#e#k#q#u$R$US!ln$gQ!moQ!npQ!oqQ!prQ!qsQ!rtQ!suQ!tvQ!z!RQ!|!UQ#P!ZQ#a!uQ#b!yQ#q#XQ#r#^Q#v#dQ#|#fQ$X#}Q$[$SQ$]$TQ$_$WQ$e$dQ$o$hQ$p$iQ$q$jQ$r$kQ$s$lQ$t$mR$u$nSyS}Q!OTQ#O!WQ#Q![R#R!]SzS}X!PT!W![!]R#V!bQ#z#eR$^$UjiOS!e!f!g!h#`#e#k#u$R$U$WR#S!_Q!`cR$P#qjgOS!e!f!g!h#`#e#k#u$R$U$WR#l#SR!ddbhOS#`#e#k#u$R$U$WQ#Y!eQ#Z!fQ#[!gR#]!hR!kjQ!jjR#s#_", + nodeNames: "⚠ Expression LogicPredicate Literal Local Index Global Radical BinaryOperation + - * ∪ \\ ∆ ∩ × ( ) } { Enumeration Tuple Boolean ℬ Declarative ∈ PrefixD Variable VariableComposite PrefixI Imperative ImperativeBlocks ImperativeIteration :∈ ImperativeAssignment := ImperativeCondition PrefixR Recursion ] FunctionCall Function [ TextFunctionExpression TextFunction ComplexIndex Filter ∉ ⊆ ⊄ ⊂ > ≥ ≤ ≠ = PredicateCall Predicate LogicNegation ¬ LogicQuantor QuantorVariable LogicBinary ⇔ ⇒ ∨ & FunctionDeclaration", + maxTerm: 101, + nodeProps: [ + ["closedBy", 17,")",20,"}"], + ["openedBy", 18,"(",19,"{"] + ], propSources: [highlighting], skippedNodes: [0], - repeatNodeCount: 1, - tokenData: ".p~RqX^#Ypq#Y!Q!R%m!R![%u!c!d&b!e!f&b!f!g&p!h!i&x!k!l'W!r!s']!t!u'k!u!v&b!v!w&b!z!{&b#R#S'{#T#U'{#U#V(W#V#W)j#W#X*y#X#d'{#d#e-P#e#f'{#f#g-o#g#o'{#y#z#Y$f$g#Y5i6S'{#BY#BZ#Y$IS$I_#Y$I|$JO#Y$JT$JU#Y$KV$KW#Y&FU&FV#Y~#_Z]~X^#Ypq#Y!Q![$Q#y#z#Y$f$g#Y#BY#BZ#Y$IS$I_#Y$I|$JO#Y$JT$JU#Y$KV$KW#Y&FU&FV#Y~$VZT~X^$xpq$x!Q![$Q#y#z$x$f$g$x#BY#BZ$x$IS$I_$x$I|$JO$x$JT$JU$x$KV$KW$x&FU&FV$x~$}YT~X^$xpq$x#y#z$x$f$g$x#BY#BZ$x$IS$I_$x$I|$JO$x$JT$JU$x$KV$KW$x&FU&FV$xQ%rPXQ!Q![%mR%|QRPXQ|}&S!Q![%mP&VP!R![&YP&_PRP|}&S~&eP!Q![&h~&mPU~!Q![&h~&uPS~!Q![&h~&{Q!Q![&h#]#^'R~'WOa~~']OS~~'`Q!Q![&h#f#g'f~'kO_~~'pPS~!Q!['s~'xPV~!Q!['s~(QQf~#T#o'{5i6S'{~(]Sf~#T#c'{#c#d(i#d#o'{5i6S'{~(nSf~#T#c'{#c#d(z#d#o'{5i6S'{~)PSf~#T#`'{#`#a)]#a#o'{5i6S'{~)dQc~f~#T#o'{5i6S'{~)oRf~#T#U)x#U#o'{5i6S'{~)}Sf~#T#f'{#f#g*Z#g#o'{5i6S'{~*`Sf~#T#W'{#W#X*l#X#o'{5i6S'{~*sQb~f~#T#o'{5i6S'{~+OSf~#T#X'{#X#Y+[#Y#o'{5i6S'{~+aSf~#T#U'{#U#V+m#V#o'{5i6S'{~+rSf~#T#c'{#c#d,O#d#o'{5i6S'{~,TSf~#T#c'{#c#d,a#d#o'{5i6S'{~,fSf~#T#`'{#`#a,r#a#o'{5i6S'{~,yQd~f~#T#o'{5i6S'{~-USf~#T#f'{#f#g-b#g#o'{5i6S'{~-iQ`~f~#T#o'{5i6S'{~-tSf~#T#X'{#X#Y.Q#Y#o'{5i6S'{~.VSf~#T#W'{#W#X.c#X#o'{5i6S'{~.jQe~f~#T#o'{5i6S'{", + repeatNodeCount: 0, + tokenData: "4X~R!iX^%ppq%pvw&exy&jyz&oz{&t{|&y|}'O}!O'T!Q!R'Y!R!['b![!]'}!]!^(b!_!`(g!`!a(l!c!d(q!e!f(q!f!g)P!h!i)X!k!l)o!r!s)t!t!u*[!u!v(q!v!w(q!z!{(q!|!}*l!}#O*q#O#P*v#P#Q*{#R#S+Q#T#U+Q#U#V+]#V#W,o#W#X.O#X#d+Q#d#e0U#e#f+Q#f#g0t#g#o+Q#o#p1u#p#q1z#q#r2P#y#z%p$f$g%p$r$s2U%o%p2Z5i6S+Q#BY#BZ%p$IS$I_%p$I|$JO%p$JT$JU%p$KV$KW%p% l% m2`%%Y%%Z2e%%[%%]2j%&Y%&Z2o%&]%&^2o%&_%&`2t%&`%&a2y%&b%&c3O%&c%&d3T%'S%'T3Y%'T%'U3_%'U%'V3d%(^%(_3i%(b%(c3n%(c%(d3s%)Q%)R3x%)S%)T3}%)U%)V4S&FU&FV%p~%uY!i~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!e~~&oOa~~&tOb~~&yOZ~~'OOX~~'TO!t~~'YOY~P'_P!mP!Q!['YR'iQ!OQ!mP|}'o!Q!['YQ'rP!R!['uQ'zP!OQ|}'o~(QQ!_!`(W%&b%&c(]~(]Ot~~(bOr~~(gO!x~~(lO!Y~~(qO!U~~(tP!Q![(w~(|PU~!Q![(w~)UPk~!Q![(w~)[Q!Q![)b#]#^)j~)gPz~!Q![)b~)oO#P~~)tOn~~)wQ!Q![)}#f#g*V~*SP![~!Q![)}~*[O!y~~*aPv~!Q![*d~*iPV~!Q![*d~*qO!o~~*vO{~~*{O]~~+QOx~~+VQ!p~#T#o+Q5i6S+Q~+bS!p~#T#c+Q#c#d+n#d#o+Q5i6S+Q~+sS!p~#T#c+Q#c#d,P#d#o+Q5i6S+Q~,US!p~#T#`+Q#`#a,b#a#o+Q5i6S+Q~,iQ!|~!p~#T#o+Q5i6S+Q~,tR!p~#T#U,}#U#o+Q5i6S+Q~-SS!p~#T#f+Q#f#g-`#g#o+Q5i6S+Q~-eS!p~#T#W+Q#W#X-q#X#o+Q5i6S+Q~-xQ!{~!p~#T#o+Q5i6S+Q~.TS!p~#T#X+Q#X#Y.a#Y#o+Q5i6S+Q~.fS!p~#T#U+Q#U#V.r#V#o+Q5i6S+Q~.wS!p~#T#c+Q#c#d/T#d#o+Q5i6S+Q~/YS!p~#T#c+Q#c#d/f#d#o+Q5i6S+Q~/kS!p~#T#`+Q#`#a/w#a#o+Q5i6S+Q~0OQ!}~!p~#T#o+Q5i6S+Q~0ZS!p~#T#f+Q#f#g0g#g#o+Q5i6S+Q~0nQ!z~!p~#T#o+Q5i6S+Q~0yS!p~#T#X+Q#X#Y1V#Y#o+Q5i6S+Q~1[S!p~#T#W+Q#W#X1h#X#o+Q5i6S+Q~1oQ#O~!p~#T#o+Q5i6S+Q~1zOd~~2PO!u~~2UOc~~2ZO!^~~2`O`~~2eOh~~2jO!c~~2oO!b~~2tO#T~~2yO!n~~3OO^~~3TOj~~3YO!Q~~3_O!d~~3dO_~~3iO[~~3nO!X~~3sO!W~~3xO!V~~3}O!T~~4SO!S~~4XO!R~", tokenizers: [0, 1], topRules: {"Expression":[0,1]}, - tokenPrec: 94 + tokenPrec: 1926 }) diff --git a/rsconcept/frontend/src/components/RSInput/rslang/rslangFull.grammar b/rsconcept/frontend/src/components/RSInput/rslang/rslangFull.grammar new file mode 100644 index 00000000..3674026d --- /dev/null +++ b/rsconcept/frontend/src/components/RSInput/rslang/rslangFull.grammar @@ -0,0 +1,200 @@ +@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, + p1, p2 +} + +@top Expression { + term_or_logic | + FunctionDeclaration +} + +@skip { space } + +@tokens { + space { @whitespace+ } + ComplexIndex { $[1-9](","$[1-9])* } + integer { $[0-9]+ } + emptySet { "∅" } + integerSet { "Z" } + + bigPr { "Pr" } + smallPr { "pr" } + filter { "Fi" } + card { "card" } + bool { "bool" } + debool { "debool" } + red { "red" } + + quantifier { $[∀∃] } + + Global { $[XCSDAT]$[0-9]+ } + Function { "F"$[0-9]+ } + Predicate { "P"$[0-9]+ } + Radical { "R"$[0-9]+ } + local { $[_a-zα-ω]($[a-zα-ω])* } + PrefixR { "R" } + PrefixI { "I" } + PrefixD { "D" } + + "¬" + "⇔" "⇒" "∨" "&" + "ℬ" + "+" "-" "*" "∪" "\\" "∆" "∩" "×" + "∈" "∉" "⊆" "⊄" "⊂" ">" "≥" "≤" "≠" "=" + ":∈" ":=" + + "[" "]" + "{" "}" + "(" ")" + + @precedence { filter bigPr Predicate Function Global Radical PrefixR PrefixI PrefixD } + @precedence { card bool debool red smallPr local } +} + +Index { integer } +Local { + !p1 local | + !p2 local Index +} + +Literal { integer | emptySet | integerSet } + +TextFunction { + bigPr ComplexIndex | + smallPr ComplexIndex | + card | bool | debool | red +} + +Filter { filter ComplexIndex } + +term_or_logic { logic | term } + +FunctionDeclaration { "[" arg_declaration "]" term_or_logic } +arg_declaration { + declaration | + arg_declaration "," declaration +} +declaration { Local "∈" term } + +logic { + LogicPredicate | + logicUnary | + LogicBinary +} +logic_all { logic | logic_par } +logic_par { "(" logic ")" } +logic_no_binary { + LogicPredicate + logicUnary + logic_par +} +logicUnary { + PredicateCall { Predicate "[" term_enum "]" } | + LogicNegation { !not "¬" logic_no_binary } | + LogicQuantor { quantifier QuantorVariable "∈" term logic_no_binary } +} + +LogicPredicate { + term "∈" term | + term "∉" term | + term "⊆" term | + term "⊄" term | + term "⊂" term | + term ">" term | + term "≥" term | + term "≤" term | + term "≠" term | + term "=" term +} + +LogicBinary { + logic_all !log_equiv "⇔" logic_all | + logic_all !log_impl "⇒" logic_all | + logic_all !log_or "∨" logic_all | + logic_all !log_and "&" logic_all +} + +QuantorVariable { Variable | quant_var_enum } +quant_var_enum { QuantorVariable "," Variable } +Variable { Local | "(" VariableComposite ")" } +VariableComposite { var_all "," Variable } +var_all { Variable | VariableComposite } + +term { + Literal | Local | Global | Radical | + BinaryOperation | + typed_constructors | + FunctionCall | + TextFunctionExpression +} +FunctionCall { Function "[" term_enum "]" } + +TextFunctionExpression { + TextFunction "(" term ")" | + Filter "[" term_enum "]" "(" term ")" +} + +BinaryOperation { + term !plus "+" term | + term !minus "-" term | + term !times "*" term | + term !set_union "∪" term | + term !set_minus "\\" term | + term !set_symminus "∆" term | + term !set_intersect "∩" term | + term !set_decart "×" term | + "(" BinaryOperation ")" +} + +typed_constructors { + Enumeration | + Tuple | + Boolean | + Declarative | + Imperative | + Recursion +} +Enumeration { "{" term_enum "}"} +Tuple { "(" term_enum_min2 ")"} +Boolean { + !set_bool "ℬ" "(" term ")" | + !set_bool "ℬ" Boolean +} + +term_enum { term | term_enum_min2 } +term_enum_min2 { term_enum "," term } + +Declarative { + "{" Local "∈" term "|" logic "}" | + PrefixD "{" Variable "∈" term "|" logic "}" +} +Recursion { + PrefixR "{" Variable ":=" term ("|" logic)? "|" term "}" +} +Imperative { + PrefixI "{" term "|" ImperativeBlocks "}" +} +ImperativeBlocks { + imp_block | + ImperativeBlocks ";" imp_block +} +imp_block { + ImperativeIteration | + ImperativeAssignment | + ImperativeCondition +} +ImperativeIteration { Local ":∈" term } +ImperativeAssignment { Local ":=" term } +ImperativeCondition { logic } + +@detectDelim + +@external propSource highlighting from "./highlight.ts" \ No newline at end of file diff --git a/rsconcept/frontend/src/components/RSInput/rslang/rslang.grammar b/rsconcept/frontend/src/components/RSInput/rslang/rslangLex.grammar similarity index 74% rename from rsconcept/frontend/src/components/RSInput/rslang/rslang.grammar rename to rsconcept/frontend/src/components/RSInput/rslang/rslangLex.grammar index d53c3412..fbf7d579 100644 --- a/rsconcept/frontend/src/components/RSInput/rslang/rslang.grammar +++ b/rsconcept/frontend/src/components/RSInput/rslang/rslangLex.grammar @@ -51,11 +51,4 @@ token { @detectDelim -@external propSource highlighting from "./highlight.ts" - -//@asciiLetter matches $[a-zA-Z] -//@asciiLowercase matches $[a-z] -//@asciiUppercase is equivalent to $[A-Z] -//@digit matches $[0-9] -//@whitespace matches any character the Unicode standard defines as whitespace. -//@eof matches the end of the input \ No newline at end of file +@external propSource highlighting from "./highlight.ts" \ No newline at end of file diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx index debff828..00e5727c 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx @@ -152,7 +152,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }: }, [noNavigation, baseHeight]); return (<> -
+
void + onEnter: (node: CursorNode) => false | void + onLeave?: (node: CursorNode) => false | void +} + +export function traverseTree(tree: Tree, { beforeEnter, onEnter, onLeave, }: TreeTraversalOptions) { + const cursor = tree.cursor(); + for (;;) { + let node = cursorNode(cursor) + let leave = false + const enter = !node.type.isAnonymous + if (enter && beforeEnter) beforeEnter(cursor) + node.isLeaf = !cursor.firstChild() + if (enter) { + leave = true + if (onEnter(node) === false) return + } + if (!node.isLeaf) continue + for (;;) { + node = cursorNode(cursor, node.isLeaf) + if (leave && onLeave) if (onLeave(node) === false) return; + leave = cursor.type.isAnonymous + node.isLeaf = false + if (cursor.nextSibling()) break; + if (!cursor.parent()) return; + leave = true + } + } +} + +export function printTree(tree: Tree): string { + const state = { + output: "", + prefixes: [] as string[] + } + traverseTree(tree, { + onEnter: node => { + state.output += "["; + state.output += node.type.name; + }, + onLeave: () => { + state.output += "]"; + }, + }) + return state.output; +}