Implement full RSLang grammar

This commit is contained in:
IRBorisov 2023-08-14 18:40:19 +03:00
parent 377c1e0d2b
commit 53187efd6c
10 changed files with 342 additions and 28 deletions

View File

@ -4,7 +4,7 @@
"version": "1.0.0", "version": "1.0.0",
"type": "module", "type": "module",
"scripts": { "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", "test": "jest",
"dev": "vite", "dev": "vite",
"build": "tsc && vite build", "build": "tsc && vite build",

View File

@ -40,8 +40,8 @@ const editorSetup: BasicSetupOptions = {
const editorExtensions = [ const editorExtensions = [
EditorView.lineWrapping, EditorView.lineWrapping,
bracketMatching(),
RSLanguage, RSLanguage,
bracketMatching(),
//cursorTooltip(), //cursorTooltip(),
]; ];
@ -74,6 +74,7 @@ function RSInput({
{ tag: t.variableName, class: 'text-[#24821a]' }, // LocalID { tag: t.variableName, class: 'text-[#24821a]' }, // LocalID
{ tag: t.propertyName, class: '' }, // Radical { tag: t.propertyName, class: '' }, // Radical
{ tag: t.keyword, class: 'text-[#001aff]' }, // keywords { 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.controlKeyword, class: 'font-semibold'}, // R | I | D
{ tag: t.unit, class: 'text-[0.75rem]' }, // indicies { tag: t.unit, class: 'text-[0.75rem]' }, // indicies
] ]
@ -94,6 +95,7 @@ function RSInput({
{ tag: t.variableName, class: 'text-[#69bf60]' }, // LocalID { tag: t.variableName, class: 'text-[#69bf60]' }, // LocalID
{ tag: t.propertyName, class: '' }, // Radical { tag: t.propertyName, class: '' }, // Radical
{ tag: t.keyword, class: 'text-[#808dff]' }, // keywords { 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.controlKeyword, class: 'font-semibold'}, // R | I | D
{ tag: t.unit, class: 'text-[0.75rem]' }, // indicies { tag: t.unit, class: 'text-[0.75rem]' }, // indicies
] ]

View File

@ -3,12 +3,17 @@ import {styleTags, tags} from '@lezer/highlight';
export const highlighting = styleTags({ export const highlighting = styleTags({
Index: tags.unit, Index: tags.unit,
ComplexIndex: tags.unit, ComplexIndex: tags.unit,
Integer: tags.literal, Literal: tags.literal,
Radical: tags.propertyName, Radical: tags.propertyName,
Function: tags.name,
Predicate: tags.name,
Global: tags.name, Global: tags.name,
Local: tags.variableName, Local: tags.variableName,
TextFunction: tags.keyword, TextFunction: tags.keyword,
ConstructPrefix: tags.controlKeyword Filter: tags.keyword,
PrefixR: tags.controlKeyword,
PrefixI: tags.controlKeyword,
PrefixD: tags.controlKeyword
}); });

View File

@ -1,11 +1,35 @@
// This file was generated by lezer-generator. You probably shouldn't edit it. // This file was generated by lezer-generator. You probably shouldn't edit it.
export const export const
Expression = 1, Expression = 1,
TextFunction = 2, LogicPredicate = 2,
ComplexIndex = 3, Literal = 3,
ConstructPrefix = 4, Local = 4,
Integer = 5, Index = 5,
Global = 6, Global = 6,
Radical = 7, Radical = 7,
Local = 8, BinaryOperation = 8,
Index = 9 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

View File

@ -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]]]'],
['a1Z', '[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);
});
});

View File

@ -3,16 +3,20 @@ import {LRParser} from "@lezer/lr"
import {highlighting} from "./highlight.ts" import {highlighting} from "./highlight.ts"
export const parser = LRParser.deserialize({ export const parser = LRParser.deserialize({
version: 14, version: 14,
states: "!^QVQPOOO}QPO'#C^OOQO'#C^'#C^O!SQQO'#CdOOQO'#Cj'#CjOOQO'#Cf'#CfQVQPOOOOQO,58x,58xOOQO,59O,59OOOQO-E6d-E6d", 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/sO<bQPO1G/sO<iQPO1G/sO<pQPO1G/sO&iQPO,5;PO)TQPO,5;OOVQPO1G/xO=_QPO1G0VO=oQPO7+$gOOQO7+$e7+$eO&iQPO7+$gOVQPO7+$mO&iQPO7+$uOOQO7+$w7+$wOOQO7+$z7+$zO=vQPO7+$zOOQO7+%X7+%XOVQPO'#E`OOQO1G0e1G0eOOQO1G/O1G/OO)QQPO,59eOOQO1G0h1G0hOOQO'#C`'#C`O={QPO7+%]O>iQPO1G0kOOQO1G0j1G0jOOQO7+%d7+%dOVQPO<<HRO>sQPO<<HRO>zQPO'#DxO?UQPO'#DROOQO'#ET'#ETOOQO'#C|'#C|O?jQPO<<HXO?rQPO<<HaO&iQPO<<HfOOQO1G/P1G/POOQO<<Hw<<HwO?yQPOAN=mOVQPOAN=mO&iQPO,59iO&iQPO,59kOVQPO,59hOOQOAN=sAN=sOVQPOAN={O@[QPOAN>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: "#a~O]OS~OSSOTSOUSOVSO_PO`POaPObQOcQOdQOeQOfRO~ORVO~OXWOSWXTWXUWXVWXZWX_WX`WXaWXbWXcWXdWXeWXfWX~Oa_T]UVSbcde`bf~", 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: "n_PP`PPPPP`PdPPPjTSOUQUORXUTTOU", 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 TextFunction ComplexIndex ConstructPrefix Integer Global Radical Local Index", 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: 22, maxTerm: 101,
nodeProps: [
["closedBy", 17,")",20,"}"],
["openedBy", 18,"(",19,"{"]
],
propSources: [highlighting], propSources: [highlighting],
skippedNodes: [0], skippedNodes: [0],
repeatNodeCount: 1, repeatNodeCount: 0,
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'{", 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], tokenizers: [0, 1],
topRules: {"Expression":[0,1]}, topRules: {"Expression":[0,1]},
tokenPrec: 94 tokenPrec: 1926
}) })

View File

@ -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"

View File

@ -52,10 +52,3 @@ token {
@detectDelim @detectDelim
@external propSource highlighting from "./highlight.ts" @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

View File

@ -152,7 +152,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
}, [noNavigation, baseHeight]); }, [noNavigation, baseHeight]);
return (<> return (<>
<div className='px-2 py-1 sticky top-0 left-0 right-0 z-10 gap-1 flex items-center justify-between w-full bg-white border-b rounded clr-bg-pop clr-border'> <div className='sticky top-0 left-0 right-0 z-10 flex items-center justify-between w-full gap-1 px-2 py-1 bg-white border-b rounded clr-bg-pop clr-border'>
<MatchModePicker <MatchModePicker
value={filterMatch} value={filterMatch}
onChange={setFilterMatch} onChange={setFilterMatch}

View File

@ -0,0 +1,60 @@
import { NodeType, Tree, TreeCursor } from "@lezer/common"
export type CursorNode = {
type: NodeType
from: number
to: number
isLeaf: boolean
}
function cursorNode({ type, from, to }: TreeCursor, isLeaf = false): CursorNode {
return { type, from, to, isLeaf }
}
type TreeTraversalOptions = {
beforeEnter?: (cursor: TreeCursor) => 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;
}