Compare commits

..

5 Commits

Author SHA1 Message Date
4fc1a965eb it's alive 2025-11-03 13:45:01 -08:00
6cb4d69088 old syntax 2025-11-03 13:45:01 -08:00
75a304bf18 insanity 2025-11-03 13:45:01 -08:00
7cf7d7de48 what have i done 2025-11-03 13:45:01 -08:00
120244003c ./bin/shrimp parse file 2025-11-03 13:45:01 -08:00
12 changed files with 254 additions and 428 deletions

View File

@ -54,7 +54,6 @@ export class Compiler {
fnLabelCount = 0
ifLabelCount = 0
tryLabelCount = 0
loopLabelCount = 0
bytecode: Bytecode
pipeCounter = 0
@ -389,7 +388,9 @@ export class Compiler {
return instructions
}
case terms.Block: {
case terms.ThenBlock:
case terms.SingleLineThenBlock:
case terms.TryBlock: {
const children = getAllChildren(node)
const instructions: ProgramItem[] = []
@ -673,24 +674,6 @@ export class Compiler {
return instructions
}
case terms.WhileExpr: {
const [_while, test, _colon, block] = getAllChildren(node)
const instructions: ProgramItem[] = []
this.loopLabelCount++
const startLoop = `.loop_${this.loopLabelCount}:`
const endLoop = `.end_loop_${this.loopLabelCount}:`
instructions.push([`${startLoop}:`])
instructions.push(...this.#compileNode(test!, input))
instructions.push(['JUMP_IF_FALSE', endLoop])
instructions.push(...this.#compileNode(block!, input))
instructions.push(['JUMP', startLoop])
instructions.push([`${endLoop}:`])
return instructions
}
default:
throw new CompilerError(
`Compiler doesn't know how to handle a "${node.type.name}" node.`,

View File

@ -154,18 +154,18 @@ describe('compiler', () => {
end`).toEvaluateTo('white')
})
test('if else if', () => {
test('if elseif', () => {
expect(`if false:
boromir
else if true:
elseif true:
frodo
end`).toEvaluateTo('frodo')
})
test('if else if else', () => {
test('if elseif else', () => {
expect(`if false:
destroyed
else if true:
elseif true:
fire
else:
darkness
@ -173,9 +173,9 @@ describe('compiler', () => {
expect(`if false:
king
else if false:
elseif false:
elf
else if true:
elseif true:
dwarf
else:
scattered

View File

@ -39,7 +39,7 @@ const tagCall = (tagName: string, atNamed = {}, ...args: any[]) => {
const space = attrs.length ? ' ' : ''
const children = args
.reverse()
.map(a => a === TAG_TOKEN ? buffer.pop() : a)
.map(a => a === null ? buffer.pop() : a)
.reverse().join(' ')
.replaceAll(` ${NOSPACE_TOKEN} `, '')
@ -50,16 +50,13 @@ const tagCall = (tagName: string, atNamed = {}, ...args: any[]) => {
}
const tag = async (tagName: string, atNamed = {}, ...args: any[]) => {
if (typeof args[0] === 'function') {
if (typeof args[0] === 'function')
await tagBlock(tagName, atNamed, args[0])
} else {
else
tagCall(tagName, atNamed, ...args)
return TAG_TOKEN
}
}
const NOSPACE_TOKEN = '!!ribbit-nospace!!'
const TAG_TOKEN = '!!ribbit-tag!!'
const SELF_CLOSING = ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"]
describe('ribbit', () => {

View File

@ -1,48 +0,0 @@
import { describe } from 'bun:test'
import { expect, test } from 'bun:test'
describe('while', () => {
test('basic variable', () => {
expect(`
a = true
b = ''
while a:
a = false
b = done
end
b`)
.toEvaluateTo('done')
})
test('basic expression', () => {
expect(`
a = 0
while a < 10:
a += 1
end
a`)
.toEvaluateTo(10)
})
test('compound expression', () => {
expect(`
a = 1
b = 0
while a > 0 and b < 100:
b += 1
end
b`)
.toEvaluateTo(100)
})
test('returns value', () => {
expect(`
a = 0
ret = while a < 10:
a += 1
done
end
ret`)
.toEvaluateTo('done')
})
})

View File

@ -210,7 +210,7 @@ export const getIfExprParts = (node: SyntaxNode, input: string) => {
}
elseThenBlock = parts.at(-1)
} else if (child.type.id === terms.ElseIfExpr) {
const [_else, _if, conditional, _colon, thenBlock] = parts
const [_keyword, conditional, _colon, thenBlock] = parts
if (!conditional || !thenBlock) {
const names = parts.map((p) => p.type.name).join(', ')
const message = `ElseIfExpr expected conditional and thenBlock, got ${names}`
@ -309,7 +309,7 @@ export const getDotGetParts = (node: SyntaxNode, input: string) => {
export const getTryExprParts = (node: SyntaxNode, input: string) => {
const children = getAllChildren(node)
// First child is always 'try' keyword, second is colon, third is Block
// First child is always 'try' keyword, second is colon, third is TryBlock or statement
const [tryKeyword, _colon, tryBlock, ...rest] = children
if (!tryKeyword || !tryBlock) {

View File

@ -25,17 +25,8 @@
Underscore { "_" }
Regex { "//" (![/\\\n[] | "\\" ![\n] | "[" (![\n\\\]] | "\\" ![\n])* "]")+ ("//" $[gimsuy]*)? } // Stolen from the lezer JavaScript grammar
"|"[@name=operator]
}
end { @specialize[@name=keyword]<Identifier, "end"> }
while { @specialize[@name=keyword]<Identifier, "while"> }
if { @specialize[@name=keyword]<Identifier, "if"> }
else { @specialize[@name=keyword]<Identifier, "else"> }
try { @specialize[@name=keyword]<Identifier, "try"> }
catch { @specialize[@name=keyword]<Identifier, "catch"> }
finally { @specialize[@name=keyword]<Identifier, "finally"> }
throw { @specialize[@name=keyword]<Identifier, "throw"> }
null { @specialize[@name=Null]<Identifier, "null"> }
}
@external tokens tokenizer from "./tokenizer" { Identifier, AssignableIdentifier, Word, IdentifierBeforeDot }
@external specialize {Identifier} specializeKeyword from "./tokenizer" { Do }
@ -56,9 +47,9 @@ item {
newlineOrSemicolon // allow blank lines
}
consumeToTerminator {
PipeExpr |
WhileExpr |
FunctionCallWithBlock |
ambiguousFunctionCall |
TryExpr |
@ -80,16 +71,16 @@ pipeOperand {
FunctionCall | FunctionCallOrIdentifier
}
WhileExpr {
while (ConditionalOp | expression) colon Block end
}
Block {
consumeToTerminator | newlineOrSemicolon block
}
FunctionCallWithBlock {
ambiguousFunctionCall colon Block CatchExpr? FinallyExpr? end
singleLineFunctionCallWithBlock | multiLineFunctionCallWithBlock
}
singleLineFunctionCallWithBlock {
ambiguousFunctionCall colon consumeToTerminator CatchExpr? FinallyExpr? @specialize[@name=keyword]<Identifier, "end">
}
multiLineFunctionCallWithBlock {
ambiguousFunctionCall colon newlineOrSemicolon block CatchExpr? FinallyExpr? @specialize[@name=keyword]<Identifier, "end">
}
FunctionCallOrIdentifier {
@ -108,6 +99,7 @@ arg {
PositionalArg | NamedArg
}
PositionalArg {
expression | FunctionDef | Underscore
}
@ -117,35 +109,71 @@ NamedArg {
}
FunctionDef {
Do Params colon (consumeToTerminator | newlineOrSemicolon block) CatchExpr? FinallyExpr? end
singleLineFunctionDef | multilineFunctionDef
}
singleLineFunctionDef {
Do Params colon consumeToTerminator CatchExpr? FinallyExpr? @specialize[@name=keyword]<Identifier, "end">
}
multilineFunctionDef {
Do Params colon newlineOrSemicolon block CatchExpr? FinallyExpr? @specialize[@name=keyword]<Identifier, "end">
}
IfExpr {
if (ConditionalOp | expression) colon Block ElseIfExpr* ElseExpr? end
singleLineIf | multilineIf
}
singleLineIf {
@specialize[@name=keyword]<Identifier, "if"> (ConditionalOp | expression) colon SingleLineThenBlock @specialize[@name=keyword]<Identifier, "end">
}
multilineIf {
@specialize[@name=keyword]<Identifier, "if"> (ConditionalOp | expression) colon newlineOrSemicolon ThenBlock ElseIfExpr* ElseExpr? @specialize[@name=keyword]<Identifier, "end">
}
ElseIfExpr {
else if (ConditionalOp | expression) colon Block
@specialize[@name=keyword]<Identifier, "elseif"> (ConditionalOp | expression) colon newlineOrSemicolon ThenBlock
}
ElseExpr {
else colon Block
@specialize[@name=keyword]<Identifier, "else"> colon newlineOrSemicolon ThenBlock
}
ThenBlock {
block
}
SingleLineThenBlock {
consumeToTerminator
}
TryExpr {
try colon Block CatchExpr? FinallyExpr? end
singleLineTry | multilineTry
}
singleLineTry {
@specialize[@name=keyword]<Identifier, "try"> colon consumeToTerminator CatchExpr? FinallyExpr? @specialize[@name=keyword]<Identifier, "end">
}
multilineTry {
@specialize[@name=keyword]<Identifier, "try"> colon newlineOrSemicolon TryBlock CatchExpr? FinallyExpr? @specialize[@name=keyword]<Identifier, "end">
}
CatchExpr {
catch Identifier colon Block
@specialize[@name=keyword]<Identifier, "catch"> Identifier colon (newlineOrSemicolon TryBlock | consumeToTerminator)
}
FinallyExpr {
finally colon Block
@specialize[@name=keyword]<Identifier, "finally"> colon (newlineOrSemicolon TryBlock | consumeToTerminator)
}
TryBlock {
block
}
Throw {
throw (BinOp | ConditionalOp | expression)
@specialize[@name=keyword]<Identifier, "throw"> (BinOp | ConditionalOp | expression)
}
ConditionalOp {
@ -164,7 +192,7 @@ Params {
}
NamedParam {
NamedArgPrefix (String | Number | Boolean | null)
NamedArgPrefix (String | Number | Boolean | @specialize[@name=Null]<Identifier, "null">)
}
Assign {
@ -202,6 +230,7 @@ expression {
}
String { "'" stringContent* "'" }
}
stringContent {
@ -237,7 +266,7 @@ Array {
// to go through ambiguousFunctionCall (which is what we want semantically).
// Yes, it is annoying and I gave up trying to use GLR to fix it.
expressionWithoutIdentifier {
ParenExpr | Word | String | Number | Boolean | Regex | Dict | Array | null
ParenExpr | Word | String | Number | Boolean | Regex | Dict | Array | @specialize[@name=Null]<Identifier, "null">
}
block {

View File

@ -47,19 +47,20 @@ export const
Null = 45,
colon = 46,
CatchExpr = 47,
keyword = 68,
Block = 49,
keyword = 70,
TryBlock = 49,
FinallyExpr = 50,
Underscore = 53,
Array = 54,
ConditionalOp = 55,
PositionalArg = 56,
WhileExpr = 58,
FunctionCallWithBlock = 60,
TryExpr = 61,
Throw = 63,
IfExpr = 65,
FunctionCallWithBlock = 58,
TryExpr = 59,
Throw = 61,
IfExpr = 63,
SingleLineThenBlock = 65,
ThenBlock = 66,
ElseIfExpr = 67,
ElseExpr = 69,
CompoundAssign = 70,
Assign = 71
CompoundAssign = 71,
Assign = 72

View File

@ -4,14 +4,14 @@ import {operatorTokenizer} from "./operatorTokenizer"
import {tokenizer, specializeKeyword} from "./tokenizer"
import {trackScope} from "./scopeTracker"
import {highlighting} from "./highlight"
const spec_Identifier = {__proto__:null,null:90, catch:96, finally:102, end:104, while:118, try:124, throw:128, if:132, else:136}
const spec_Identifier = {__proto__:null,null:90, catch:96, finally:102, end:104, try:120, throw:124, if:128, elseif:136, else:140}
export const parser = LRParser.deserialize({
version: 14,
states: "9OQYQbOOO#zQcO'#C{O$zOSO'#C}OOQa'#DT'#DTO&TQbO'#DdO'iQcO'#E]OOQa'#E]'#E]O(lQcO'#E]O)nQcO'#E[O*UQRO'#C|O+eQcO'#EWO+uQcO'#EWO,PQbO'#CzO,wOpO'#CxOOQ`'#EX'#EXO,|QbO'#EWO-WQRO'#DtOOQ`'#EW'#EWO-lQQO'#EVOOQ`'#EV'#EVOOQ`'#Dv'#DvQYQbOOO-tQbO'#DWO.PQbO'#DhO.tQQO'#DkO.PQbO'#DmO.PQbO'#DoO.yQbO'#DUOOQa'#E['#E[OOQ`'#Df'#DfOOQ`'#Ek'#EkOOQ`'#EO'#EOO/TQbO,59cO/}QbO'#DPO0VQWO'#DQOOOO'#E_'#E_OOOO'#Dw'#DwO0kOSO,59iOOQa,59i,59iOOQ`'#Dx'#DxO0yQbO,5:OO1QQQO,59oOOQa,5:O,5:OO1]QbO,5:OO1gQbO,5:aO.PQbO,59hO.PQbO,59hO.PQbO,59hO.PQbO,5:PO.PQbO,5:PO.PQbO,5:PO1zQRO,59fO2RQRO,59fO2dQRO,59fO2_QQO,59fO2oQQO,59fO2wObO,59dO3SQbO'#EPO3_QbO,59bO3yQbO,5:UO1gQbO,5:`OOQ`,5:q,5:qOOQ`-E7t-E7tOOQ`'#Dy'#DyO4aQbO'#DXO4lQbO'#DYOOQO'#Dz'#DzO4dQQO'#DXO4zQQO,59rO5kQRO,5:SO5rQRO,5:SO3yQbO,5:VO5}QcO,5:XO6yQcO,5:XO7ZQcO,5:XO7eQRO,5:ZO7lQRO,5:ZOOQ`,59p,59pOOQ`-E7|-E7|OOOO,59k,59kOOOO,59l,59lOOOO-E7u-E7uOOQa1G/T1G/TOOQ`-E7v-E7vO7wQQO1G/ZOOQa1G/j1G/jO8SQbO1G/jOOQO'#D|'#D|O7wQQO1G/ZOOQa1G/Z1G/ZOOQ`'#D}'#D}O8SQbO1G/jOOQ`1G/{1G/{OOQa1G/S1G/SO9OQcO1G/SO9YQcO1G/SO9dQcO1G/SOOQa1G/k1G/kO;YQcO1G/kO;aQcO1G/kO;hQcO1G/kOOQa1G/Q1G/QOOQa1G/O1G/OO!dQbO'#C{O;oQbO'#CwOOQ`,5:k,5:kOOQ`-E7}-E7}OOQ`'#D_'#D_O;|QbO'#D_O<pQbO1G/pOOQ`1G/z1G/zOOQ`-E7w-E7wO<{QQO,59sOOQO,59t,59tOOQO-E7x-E7xO=TQbO1G/^O3yQbO1G/nO=kQbO1G/qO3yQbO1G/uO=vQQO7+$uOOQa7+$u7+$uO>RQbO7+%UOOQa7+%U7+%UOOQO-E7z-E7zOOQ`-E7{-E7{OOQ`'#D{'#D{O>]QQO'#D{O>bQbO'#EhOOQ`,59y,59yO?UQbO'#D]O?ZQQO'#D`OOQ`7+%[7+%[O?`QbO7+%[O?eQbO7+%[O?mQbO7+$xO?xQbO7+$xO@iQbO7+%YOOQ`7+%]7+%]O@nQbO7+%]O@sQbO7+%]O@{QbO7+%aOOQa<<Ha<<HaOOQa<<Hp<<HpOOQ`,5:g,5:gOOQ`-E7y-E7yOATQQO,59wO3yQbO,59zOOQ`<<Hv<<HvOAYQbO<<HvOOQ`<<Hd<<HdOA_QbO<<HdOAdQbO<<HdOAlQbO<<HdOOQ`<<Ht<<HtOOQ`<<Hw<<HwOAwQbO<<HwOOQ`'#EQ'#EQOA|QbO<<H{OBUQbO'#DsOOQ`<<H{<<H{OB^QbO<<H{O3yQbO1G/cOOQ`1G/f1G/fOOQ`AN>bAN>bOOQ`AN>OAN>OOBcQbOAN>OOBhQbOAN>OOOQ`AN>cAN>cOOQ`-E8O-E8OOOQ`AN>gAN>gOBpQbOAN>gO.PQbO,5:]O3yQbO,5:_OOQ`7+$}7+$}OOQ`G23jG23jOBuQbOG23jPBXQbO'#DqOOQ`G24RG24ROBzQRO1G/wOCRQRO1G/wOOQ`1G/y1G/yOOQ`LD)ULD)UO3yQbO7+%cOOQ`<<H}<<H}",
stateData: "Ca~O!wOS!xOS~OdPOe`OfUOg]OhfOmUOuUOvUO}UO!]gO!`hO!biO!djO!}[O#QQO#XRO#YSO#ZcO~OdlOfUOg]OhfOmUOuUOvUOykO}UO!VmO!}[O#QQO#XRO#YSO!ZoX#ZoX#`oX#^oX!QoX!ToX!UoX!foX~OP#OXQ#OXR#OXS#OXT#OXU#OXW#OXX#OXY#OXZ#OX[#OX]#OX^#OX!OoX~P!dOrsO#QvO#SqO#TrO~OdlOfUOg]OmUOuUOvUOykO}UO!}[O#QQO#XRO#YSO#ZwO~O#]zO~P%YOP#PXQ#PXR#PXS#PXT#PXU#PXW#PXX#PXY#PXZ#PX[#PX]#PX^#PX#Z#PX#`#PX!Q#PX!T#PX!U#PX!f#PX~OdlOfUOg]OhfOmUOuUOvUOykO}UO!VmO!}[O#QQO#XRO#YSO#^#PX~P&[OV|O~P&[OP#OXQ#OXR#OXS#OXT#OXU#OXW#OXX#OXY#OXZ#OX[#OX]#OX^#OX~O#Z!zX#`!zX!Q!zX!T!zX!U!zX!f!zX~P(sOP!OOQ!OOR!POS!POT!ROU!SOW!QOX!QOY!QOZ!QO[!QO]!QO^}O~O#Z!zX#`!zX!Q!zX!T!zX!U!zX!f!zX~OP!OOQ!OOR!POS!PO~P+POT!ROU!SO~P+POdPOfUOg]OhfOmUOuUOvUO}UO!}[O#QQO#XRO#YSO~O!|!YO~O!O!]O!Z!ZO~P+POV|O_!^O`!^Oa!^Ob!^Oc!^O~O#Z!_O#`!_O~Od!aOy!cO!O{P~OdlOfUOg]OmUOuUOvUO}UO!}[O#QQO#XRO#YSO~O!O!iO~OhfO!V!oO~P.POhfOykO!VmO!Oka!Zka#Zka#`ka#^ka!Qka!Tka!Uka!fka~P.POd!qO!}[O~O#Q!rO#S!rO#T!rO#U!rO#V!rO#W!rO~OrsO#Q!tO#SqO#TrO~O#]!wO~P%YOykO#Z!yO#]!{O~O#Z!|O#]!wO~P.POe`O!]gO!`hO!biO!djO~P,PO#^#XO~P(sOP!OOQ!OOR!POS!PO#^#XO~OT!ROU!SO#^#XO~O!Z!ZO#^#XO~Od#YOm#YO!}[O~Od#ZOg]O!}[O~O!Z!ZO#Zja#`ja#^ja!Qja!Tja!Uja!fja~Oe`O!]gO!`hO!biO!djO#Z#`O~P,POd!aOy!cO!O{X~Om#eOu#eO}#eO#QQO~O!O#gO~OT!ROU!SOW!QOX!QOY!QOZ!QO[!QO]!QO~O!O#hO~P5POT!ROU!SO!O#hO~O#Z!aa#`!aa!Q!aa!T!aa!U!aa!f!aa~P*UO#Z!aa#`!aa!Q!aa!T!aa!U!aa!f!aa~OP!OOQ!OOR!POS!PO~P6eOT!ROU!SO~P6eO!O#jO~P5POT!ROU!SO!O#jO~OykO#Z!yO#]#lO~O#Z!|O#]#nO~P.PO^}ORpiSpi#Zpi#`pi#^pi!Qpi!Tpi!Upi!fpi~OPpiQpi~P8^OP!OOQ!OO~P8^OP!OOQ!OORpiSpi#Zpi#`pi#^pi!Qpi!Tpi!Upi!fpi~OW!QOX!QOY!QOZ!QO[!QO]!QOT!Xi#Z!Xi#`!Xi#^!Xi!O!Xi!Q!Xi!T!Xi!U!Xi!f!Xi~OU!SO~P:XOU!SO~P:kOU!Xi~P:XOhfOykO!VmO~P.POe`O!]gO!`hO!biO!djO#Z#qO!Q#[P!T#[P!U#[P!f#[P~P,PO!Q#uO!T#vO!U#wO~Oy!cO!O{a~Oe`O!]gO!`hO!biO!djO#Z#{O~P,PO!Q#uO!T#vO!U#}O~OykO#Z!yO#]$RO~O#Z!|O#]$SO~P.PO#Z$TO~Oe`O!]gO!`hO!biO!djO#Z#qO!Q#[X!T#[X!U#[X!f#[X~P,POd$VO~O!O$WO~O!U$XO~O!T#vO!U$XO~O!Q#uO!T#vO!U$ZO~Oe`O!]gO!`hO!biO!djO#Z#qO!Q#[P!T#[P!U#[P~P,PO!U$_O~O!U$`O~O!T#vO!U$`O~O!U$eO!f$dO~O!O$gO~O!U$iO~O!U$jO~O!T#vO!U$jO~O!Q#uO!T#vO!U$jO~O!U$mO~O!U$oO!f$dO~O!O$rO!d$qO~O!U$oO~O!U$tO~O!T#vO!U$tO~O!U$wO~O!U${O~O!O$|O~P5POT!ROU!SO!O$|O~Omv~",
goto: "3}#`PPPPPPPPPPPPPPPPPPPPPPPPPP#a#v$[P%[#v&b'QP(O(OPP(S(}P)b*R*UPP*[P*h+QPPP+h,e-^P-eP-e-eP-eP-eP-wP-{-e-e.R.X._.e.k.u.|/W/b/k/rPPPP/x/|0jPP1S2mP3lPPPPPPPP3pPP3vpaOe|!]!^!i#`#g#h#j#s#{$W$g$r$|R!W[u^O[e|!Z!]!^!i#`#g#h#j#s#{$W$g$r$|rPO[e|!]!^!i#`#g#h#j#s#{$W$g$r$||lPSTgijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qR#Z!ZrTO[e|!]!^!i#`#g#h#j#s#{$W$g$r$||UPSTgijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qQ!qqQ#Y!YR#[!ZpYOe|!]!^!i#`#g#h#j#s#{$W$g$r$|Q!U[Q!kiQ#P!OR#S!P!pUOPST[egijkpx{|}!O!P!Q!R!S!]!^!i!x!}#Z#[#`#g#h#j#m#s#{$W$g$q$r$|R#e!cTsQu!qUOPST[egijkpx{|}!O!P!Q!R!S!]!^!i!x!}#Z#[#`#g#h#j#m#s#{$W$g$q$r$|YnPTp#Z#[QySQ!vxX!yy!v!z#kpaOe|!]!^!i#`#g#h#j#s#{$W$g$r$|YmPTp#Z#[Q!W[R!okR!ffX!df!b!e#dQ#y#aQ$P#iQ$]#zR$l$^Q#a!]Q#i!iQ#|#hQ$Q#jQ$h$WQ$s$gQ$z$rR$}$|Q#x#aQ$O#iQ$Y#yQ$[#zQ$a$PS$k$]$^R$u$l!OUPST[gijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qqVOe|!]!^!i#`#g#h#j#s#{$W$g$r$|pZOe|!]!^!i#`#g#h#j#s#{$W$g$r$|Q!V[Q!hgQ!liQ!njQ#T!SQ#V!RR$y$qZnPTp#Z#[qaOe|!]!^!i#`#g#h#j#s#{$W$g$r$|T$b$Q$cQ$f$QR$p$cQeOR!`eQuQR!suQxSR!uxQ!bfR#c!bQ!efQ#d!bT#f!e#dS#s#`#{R$U#sQ!zyQ#k!vT#o!z#kQ!}{Q#m!xT#p!}#mWpPT#Z#[R!ppS![_!XR#^![Q$c$QR$n$cTdOeSbOeQ#O|`#_!]!i#h#j$W$g$r$|Q#b!^U#r#`#s#{R#z#gp_Oe|!]!^!i#`#g#h#j#s#{$W$g$r$|Q!X[R#]!ZrXO[e|!]!^!i#`#g#h#j#s#{$W$g$r$|YmPTp#Z#[Q{SQ!ggQ!jiQ!mjQ!okQ!xxW!|{!x!}#mQ#P}Q#Q!OQ#R!PQ#T!QQ#U!RQ#W!SR$x$qpWOe|!]!^!i#`#g#h#j#s#{$W$g$r$||lPSTgijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qR!T[TtQuQ#t#`R$^#{ZoPTp#Z#[",
nodeNames: "⚠ Star Slash Plus Minus And Or Eq EqEq Neq Lt Lte Gt Gte Modulo PlusEq MinusEq StarEq SlashEq ModuloEq Identifier AssignableIdentifier Word IdentifierBeforeDot Do Program PipeExpr FunctionCall DotGet Number ParenExpr FunctionCallOrIdentifier BinOp String StringFragment Interpolation EscapeSeq Boolean Regex Dict NamedArg NamedArgPrefix FunctionDef Params NamedParam Null colon CatchExpr keyword Block FinallyExpr keyword keyword Underscore Array ConditionalOp PositionalArg operator WhileExpr keyword FunctionCallWithBlock TryExpr keyword Throw keyword IfExpr keyword ElseIfExpr keyword ElseExpr CompoundAssign Assign",
maxTerm: 108,
states: "<[QYQbOOO#tQcO'#C{O$tOSO'#C}O%SQbO'#EiOOQ`'#DW'#DWOOQa'#DT'#DTO&YQbO'#DdO'kQcO'#E^OOQa'#E^'#E^O(nQcO'#E^O)pQcO'#E]O*TQRO'#C|O+aQcO'#EXO+qQcO'#EXO+{QbO'#CzO,sOpO'#CxOOQ`'#EY'#EYO,xQbO'#EXOOQ`'#Dh'#DhO-SQQO'#EqOOQ`'#Di'#DiO-XQbO'#DkO-XQbO'#EsOOQ`'#Dm'#DmO-|QRO'#DuOOQ`'#EX'#EXO.bQQO'#EWOOQ`'#EW'#EWOOQ`'#Dw'#DwQYQbOOO.jQbO'#DUOOQa'#E]'#E]OOQ`'#Df'#DfOOQ`'#En'#EnOOQ`'#EP'#EPO.tQbO,59cO/kQbO'#DPO/sQWO'#DQOOOO'#E`'#E`OOOO'#Dx'#DxO0XOSO,59iOOQa,59i,59iOOQ`'#Dz'#DzO0gQbO'#DXO0rQbO'#DYOOQO'#D{'#D{O0jQQO'#DXO1QQQO,5;TOOQ`'#Dy'#DyO1VQbO,5:OO1^QQO,59oOOQa,5:O,5:OO1iQbO,5:OO1sQbO,5:bO-XQbO,59hO-XQbO,59hO-XQbO,59hO-XQbO,5:PO-XQbO,5:PO-XQbO,5:PO2TQRO,59fO2[QRO,59fO2mQRO,59fO2hQQO,59fO2xQQO,59fO3QObO,59dO3]QbO'#EQO3hQbO,59bO4PQbO,5;ZO4dQbO,5;]O4wQcO,5:VO5mQcO,5:VO5}QcO,5:VO6sQRO,5;_O6zQRO,5;_O1sQbO,5:aOOQ`,5:r,5:rOOQ`-E7u-E7uOOQ`,59p,59pOOQ`-E7}-E7}OOOO,59k,59kOOOO,59l,59lOOOO-E7v-E7vOOQa1G/T1G/TOOQ`-E7x-E7xO7VQQO,59sOOQO,59t,59tOOQO-E7y-E7yO7_QbO1G0oOOQ`-E7w-E7wO7rQQO1G/ZOOQa1G/j1G/jO7}QbO1G/jOOQO'#D}'#D}O7rQQO1G/ZOOQa1G/Z1G/ZOOQ`'#EO'#EOO7}QbO1G/jOOQ`1G/|1G/|OOQa1G/S1G/SO8vQcO1G/SO9QQcO1G/SO9[QcO1G/SOOQa1G/k1G/kO:zQcO1G/kO;RQcO1G/kO;YQcO1G/kOOQa1G/Q1G/QOOQa1G/O1G/OO!aQbO'#C{O;aQbO'#CwOOQ`,5:l,5:lOOQ`-E8O-E8OO;nQbO1G0uO;yQbO1G0vO<gQbO1G0wO;yQbO1G0xO<rQbO1G0yOOQ`1G/{1G/{O=VQbO7+&ZO;yQbO7+&]O=bQQO7+$uOOQa7+$u7+$uO=mQbO7+%UOOQa7+%U7+%UOOQO-E7{-E7{OOQ`-E7|-E7|O=wQbO'#D]O=|QQO'#D`OOQ`7+&a7+&aO>RQbO7+&aO>WQbO7+&aOOQ`'#D|'#D|O>`QQO'#D|O>eQbO'#EjO?XQbO7+&bOOQ`7+&c7+&cO?dQbO7+&cO?iQbO7+&cOOQ`'#D_'#D_O?qQbO7+&dOOQ`'#Do'#DoO?|QbO7+&eO@RQbO7+&fOOQ`<<Iu<<IuO@oQbO<<IuO@tQbO<<IuO@|QbO<<IwOOQa<<Ha<<HaOOQa<<Hp<<HpOAXQQO,59wOA^QbO,59zOOQ`<<I{<<I{OAqQbO<<I{OOQ`,5:h,5:hOOQ`-E7z-E7zOOQ`<<I|<<I|OAvQbO<<I|OA{QbO<<I|OOQ`<<I}<<I}OBTQbO<<I}OOQ`<<JO<<JOOBYQbO<<JOOB_QbO<<JOOOQ`<<JP<<JPOOQ`'#Dp'#DpOBgQbO<<JQOOQ`AN?aAN?aOBrQbOAN?aOOQ`AN?cAN?cOBwQbOAN?cOB|QbOAN?cOCUQbO1G/cOCiQbO1G/fOOQ`1G/f1G/fOOQ`AN?gAN?gOOQ`AN?hAN?hODPQbOAN?hOOQ`AN?iAN?iOOQ`AN?jAN?jODUQbOAN?jO-XQbO'#DqOOQ`'#ER'#ERODZQbOAN?lODfQQO'#DsOOQ`AN?lAN?lODkQbOAN?lOOQ`G24{G24{OOQ`G24}G24}ODpQbOG24}ODuQbO7+$}OOQ`7+$}7+$}OOQ`7+%Q7+%QOOQ`G25SG25SOOQ`G25UG25UOE`QRO,5:]OEgQRO,5:]OOQ`-E8P-E8POOQ`G25WG25WOErQbOG25WOEwQQO,5:_OOQ`LD*iLD*iOOQ`<<Hi<<HiOE|QQO1G/wOOQ`LD*rLD*rOCiQbO1G/yO@RQbO7+%cOOQ`7+%e7+%eOOQ`<<H}<<H}",
stateData: "FU~O!xOS!yOS~OdPOehOfWOg_OhROmWOuWOvWO}WO!^cO!`eO!bfO#O^O#RQO#YTO#ZUO#[kO~OdoOfWOg_OhROmWOuWOvWOynO}WO!VpO#O^O#RQO#YTO#ZUO!ZoX#[oX#ioX#aoX!QoX!ToX!UoX~OP#PXQ#PXR#PXS#PXT#PXU#PXW#PXX#PXY#PXZ#PX[#PX]#PX^#PX!OoX~P!aOrvO#RyO#TtO#UuO~OdzOy|O!O{P~OdoOfWOg_OmWOuWOvWOynO}WO#O^O#RQO#YTO#ZUO#[!QO~O#`!TO~P%_OP#QXQ#QXR#QXS#QXT#QXU#QXW#QXX#QXY#QXZ#QX[#QX]#QX^#QX#[#QX#i#QX!Q#QX!T#QX!U#QX~OdoOfWOg_OhROmWOuWOvWOynO}WO!VpO#O^O#RQO#YTO#ZUO#a#QX~P&aOV!VO~P&aOP#PXQ#PXR#PXS#PXT#PXU#PXW#PXX#PXY#PXZ#PX[#PX]#PX^#PX~O#[!{X#i!{X!Q!{X!T!{X!U!{X~P(uOP!XOQ!XOR!YOS!YOT![OU!]OW!ZOX!ZOY!ZOZ!ZO[!ZO]!ZO^!WO~O#[!{X#i!{X!Q!{X!T!{X!U!{X~OP!XOQ!XOR!YOS!YO~P+OOT![OU!]O~P+OOdPOfWOg_OhROmWOuWOvWO}WO#O^O#RQO#YTO#ZUO~O!}!cO~O!O!fO!Z!dO~P+OO!O!gO~OdoOfWOg_OmWOuWOvWO}WO#O^O#RQO#YTO#ZUO~OV!VO_!mO`!mOa!mOb!mOc!mO~O#[!nO#i!nO~OhRO!V!pO~P-XOhROynO!VpO!Oka!Zka#[ka#ika#aka!Qka!Tka!Uka~P-XOd!rO#O^O~O#R!sO#T!sO#U!sO#V!sO#W!sO#X!sO~OrvO#R!uO#TtO#UuO~OdzOy|O!O{X~Om!xOu!xO}!xO#RQO~O!O!zO~O#`!}O~P%_OynO#[#PO#`#RO~O#[#SO#`!}O~P-XOehO!^cO!`eO!bfO~P+{O#a#_O~P(uOP!XOQ!XOR!YOS!YO#a#_O~OT![OU!]O#a#_O~O!Z!dO#a#_O~Od#`Om#`O#O^O~Od#aOg_O#O^O~O!Z!dO#[ja#ija#aja!Qja!Tja!Uja~OehO!^cO!`eO!bfO#[#fO~P+{OehO!^cO!`eO!bfO#[#hO~P+{O#[!_a#i!_a!Q!_a!T!_a!U!_a~P*TO#[!_a#i!_a!Q!_a!T!_a!U!_a~OP!XOQ!XOR!YOS!YO~P5[OT![OU!]O~P5[OT![OU!]OW!ZOX!ZOY!ZOZ!ZO[!ZO]!ZO~O!O#iO~P6XOT![OU!]O!O#iO~Oy|O!O{a~OehO!^cO!`eO!bfO#[#lO~P+{OynO#[#PO#`#nO~O#[#SO#`#pO~P-XO^!WORpiSpi#[pi#ipi#api!Qpi!Tpi!Upi~OPpiQpi~P8XOP!XOQ!XO~P8XOP!XOQ!XORpiSpi#[pi#ipi#api!Qpi!Tpi!Upi~OW!ZOX!ZOY!ZOZ!ZO[!ZO]!ZOT!Xi#[!Xi#i!Xi#a!Xi!O!Xi!Q!Xi!T!Xi!U!Xi~OU!]O~P9|OU!]O~P:`OU!Xi~P9|OhROynO!VpO~P-XO!Q#sO!T#tO!U#uO~OehO!^cO!`eO!bfO#[#xO!Q#^P!T#^P!U#^P~P+{O!Q#sO!T#tO!U#|O~OehO!^cO!`eO!bfO#[$TO~P+{O!Q#sO!T#tO!U$UO~OynO#[#PO#`$YO~O#[#SO#`$ZO~P-XOd$[O~O!O$]O~O!U$^O~O!T#tO!U$^O~O#[$`O~OehO!^cO!`eO!bfO#[#xO!Q#^X!T#^X!U#^X!f#^X!h#^X~P+{O!Q#sO!T#tO!U$bO~O!U$eO~O!T#tO!U$eO~O!Q#sO!T#tO!U$gO~O!U$jO~OehO!^cO!`eO!bfO#[#xO!U#^P!f#^P!h#^P~P+{O!U$mO~O!T#tO!U$mO~O!Q#sO!T#tO!U$oO~O!O$rO~OehO!^cO!`eO!bfO#[$sO~P+{O!U$uO~O!U$vO~O!T#tO!U$vO~O!U$xO~O!U$yO~O!T#tO!U$yO~O!U%PO!f${O!h%OO~O!U%RO~O!U%SO~O!T#tO!U%SO~OehO!^cO!`eO!bfO#[%UO~P+{OehO!^cO!`eO!bfO#[#xO!U#^P~P+{O!U%XO~O!U%YO~O!U%^O!f${O!h%OO~O!O%`O~O!U%^O~O!U%aO~OehO!^cO!`eO!bfO#[#xO!T#^P!U#^P~P+{O!O%cO~P6XOT![OU!]O!O%cO~O!U%dO~O#[%eO~O#[%fO~Omv~",
goto: "7s#iPPPPPPPPPPPPPPPPPPPPPPPPPP#j$S$kP%m$S&u'hP(h(hPP(l)iP)|*p*sPP*yP+]+fPPP,[-Z.SP.Z.ZP.ZP.ZP.p.s.|P/QP.Z.Z/W/^/d/j/p/z0X0c0m0v0}PPPP1T1X2QPP2m4WP5XPPPPPPPP5]5y5]PP6Z6b6b6w6w7^7^viOm!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fR!a^{`O^m!V!d!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fxPO^m!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fzoPUVefns!R!U!W!X!Y!Z![!]#O#T#a#b#o${R#a!dxVO^m!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fzWPUVefns!R!U!W!X!Y!Z![!]#O#T#a#b#o${Q!rtQ#`!cR#b!dv[Om!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fQ!_^Q!ieQ#V!XR#Y!Y!tWOPUV^efmns!R!U!V!W!X!Y!Z![!]!f!g!m!z#O#T#a#b#f#h#i#l#o#z$T$]$r$s${%U%e%fR!x|TvQx!uWOPUV^efmns!R!U!V!W!X!Y!Z![!]!f!g!m!z#O#T#a#b#f#h#i#l#o#z$T$]$r$s${%U%e%fYqPVs#a#bQ!SUQ!|!RX#P!S!|#Q#mviOm!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fYpPVs#a#bQ!a^R!pnR!PRX}R{!O!wQ#w#eQ$O#gQ$W#kQ$d#{Q$i$QR$q$XQ$Q#hQ%W$sR%b%UQ#v#eQ#}#gQ$V#kQ$_#wQ$c#{Q$f$OQ$h$QQ$n$WQ$p$XQ$w$dQ$z$iR%T$q|WPUV^efns!R!U!W!X!Y!Z![!]#O#T#a#b#o${wXOm!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fv]Om!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fQ!`^Q!jeQ!lfQ#Z!]Q#]![R%[${ZqPVs#a#bwiOm!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fR$S#iQ$l$TQ%g%eR%h%fT$|$l$}Q%Q$lR%_$}QmOR!omQxQR!txQ!RUR!{!RQ{RR!v{Q!ORQ!w{T!y!O!w`#z#f#h#l$T$s%U%e%fR$a#zQ#Q!SQ#m!|T#q#Q#mQ#T!UQ#o#OT#r#T#oWsPV#a#bR!qsS!ea!bR#d!eQ$}$lR%]$}TlOmSjOmQ#U!VQ#e!fQ#g!gQ#j!mQ#k!zb#y#f#h#l#z$T$s%U%e%fQ$R#iQ$t$]R%V$rvaOm!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fQ!b^R#c!dxZO^m!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fYpPVs#a#bQ!UUQ!heQ!kfQ!pnQ#O!RW#S!U#O#T#oQ#V!WQ#W!XQ#X!YQ#Z!ZQ#[![Q#^!]R%Z${vYOm!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fzoPUVefns!R!U!W!X!Y!Z![!]#O#T#a#b#o${R!^^TwQx!VSOPV^mns!V!f!g!m!z#a#b#f#h#i#l#z$T$]$r$s%U%e%fQ#{#fU$P#h$s%UQ$X#lV$k$T%e%fZrPVs#a#bwbOm!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fwdOm!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%fwgOm!V!f!g!m!z#f#h#i#l#z$T$]$r$s%U%e%f",
nodeNames: "⚠ Star Slash Plus Minus And Or Eq EqEq Neq Lt Lte Gt Gte Modulo PlusEq MinusEq StarEq SlashEq ModuloEq Identifier AssignableIdentifier Word IdentifierBeforeDot Do Program PipeExpr FunctionCall DotGet Number ParenExpr FunctionCallOrIdentifier BinOp String StringFragment Interpolation EscapeSeq Boolean Regex Dict NamedArg NamedArgPrefix FunctionDef Params NamedParam Null colon CatchExpr keyword TryBlock FinallyExpr keyword keyword Underscore Array ConditionalOp PositionalArg operator FunctionCallWithBlock TryExpr keyword Throw keyword IfExpr keyword SingleLineThenBlock ThenBlock ElseIfExpr keyword ElseExpr keyword CompoundAssign Assign",
maxTerm: 117,
context: trackScope,
nodeProps: [
["closedBy", 46,"end"]
@ -19,9 +19,9 @@ export const parser = LRParser.deserialize({
propSources: [highlighting],
skippedNodes: [0],
repeatNodeCount: 11,
tokenData: "C_~R|OX#{XY$jYZ%TZp#{pq$jqs#{st%ntu'Vuw#{wx'[xy'ayz'zz{#{{|(e|}#{}!O+X!O!P#{!P!Q-n!Q![)S![!]6Z!]!^%T!^!}#{!}#O6t#O#P8j#P#Q8o#Q#R#{#R#S9Y#S#T#{#T#Y,Y#Y#Z9s#Z#b,Y#b#c>q#c#f,Y#f#g?n#g#h,Y#h#i@k#i#o,Y#o#p#{#p#qBo#q;'S#{;'S;=`$d<%l~#{~O#{~~CYS$QUrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{S$gP;=`<%l#{^$qUrS!wYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UrS#ZQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%uZrS!xYOY%nYZ#{Zt%ntu&huw%nwx&hx#O%n#O#P&h#P;'S%n;'S;=`'P<%lO%nY&mS!xYOY&hZ;'S&h;'S;=`&y<%lO&hY&|P;=`<%l&h^'SP;=`<%l%n~'[O#S~~'aO#Q~U'hUrS!}QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(RUrS#^QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(jWrSOt#{uw#{x!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U)ZYrSmQOt#{uw#{x!O#{!O!P)y!P!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U*OWrSOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U*oWrSmQOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U+^^rSOt#{uw#{x}#{}!O,Y!O!Q#{!Q![)S![!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{U,_[rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{U-[UyQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U-sWrSOt#{uw#{x!P#{!P!Q.]!Q#O#{#P;'S#{;'S;=`$d<%lO#{U.b^rSOY/^YZ#{Zt/^tu0auw/^wx0ax!P/^!P!Q#{!Q!}/^!}#O5S#O#P2o#P;'S/^;'S;=`6T<%lO/^U/e^rSvQOY/^YZ#{Zt/^tu0auw/^wx0ax!P/^!P!Q3U!Q!}/^!}#O5S#O#P2o#P;'S/^;'S;=`6T<%lO/^Q0fXvQOY0aZ!P0a!P!Q1R!Q!}0a!}#O1p#O#P2o#P;'S0a;'S;=`3O<%lO0aQ1UP!P!Q1XQ1^UvQ#Z#[1X#]#^1X#a#b1X#g#h1X#i#j1X#m#n1XQ1sVOY1pZ#O1p#O#P2Y#P#Q0a#Q;'S1p;'S;=`2i<%lO1pQ2]SOY1pZ;'S1p;'S;=`2i<%lO1pQ2lP;=`<%l1pQ2rSOY0aZ;'S0a;'S;=`3O<%lO0aQ3RP;=`<%l0aU3ZWrSOt#{uw#{x!P#{!P!Q3s!Q#O#{#P;'S#{;'S;=`$d<%lO#{U3zbrSvQOt#{uw#{x#O#{#P#Z#{#Z#[3s#[#]#{#]#^3s#^#a#{#a#b3s#b#g#{#g#h3s#h#i#{#i#j3s#j#m#{#m#n3s#n;'S#{;'S;=`$d<%lO#{U5X[rSOY5SYZ#{Zt5Stu1puw5Swx1px#O5S#O#P2Y#P#Q/^#Q;'S5S;'S;=`5}<%lO5SU6QP;=`<%l5SU6WP;=`<%l/^U6bUrS!OQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U6{W#YQrSOt#{uw#{x!_#{!_!`7e!`#O#{#P;'S#{;'S;=`$d<%lO#{U7jVrSOt#{uw#{x#O#{#P#Q8P#Q;'S#{;'S;=`$d<%lO#{U8WU#XQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~8oO#T~U8vU#]QrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9aUrS!VQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9x]rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#U:q#U#o,Y#o;'S#{;'S;=`$d<%lO#{U:v^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#`,Y#`#a;r#a#o,Y#o;'S#{;'S;=`$d<%lO#{U;w^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#g,Y#g#h<s#h#o,Y#o;'S#{;'S;=`$d<%lO#{U<x^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#X,Y#X#Y=t#Y#o,Y#o;'S#{;'S;=`$d<%lO#{U={[uQrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^>x[#UWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^?u[#WWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^@r^#VWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#f,Y#f#gAn#g#o,Y#o;'S#{;'S;=`$d<%lO#{UAs^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#i,Y#i#j<s#j#o,Y#o;'S#{;'S;=`$d<%lO#{UBvU!ZQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~C_O#`~",
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!|~~", 11)],
tokenData: "C_~R|OX#{XY$jYZ%TZp#{pq$jqs#{st%ntu'Vuw#{wx'[xy'ayz'zz{#{{|(e|}#{}!O+X!O!P#{!P!Q-n!Q![)S![!]6Z!]!^%T!^!}#{!}#O6t#O#P8j#P#Q8o#Q#R#{#R#S9Y#S#T#{#T#Y,Y#Y#Z9s#Z#b,Y#b#c>q#c#f,Y#f#g?n#g#h,Y#h#i@k#i#o,Y#o#p#{#p#qBo#q;'S#{;'S;=`$d<%l~#{~O#{~~CYS$QUrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{S$gP;=`<%l#{^$qUrS!xYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UrS#[QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%uZrS!yYOY%nYZ#{Zt%ntu&huw%nwx&hx#O%n#O#P&h#P;'S%n;'S;=`'P<%lO%nY&mS!yYOY&hZ;'S&h;'S;=`&y<%lO&hY&|P;=`<%l&h^'SP;=`<%l%n~'[O#T~~'aO#R~U'hUrS#OQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(RUrS#aQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(jWrSOt#{uw#{x!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U)ZYrSmQOt#{uw#{x!O#{!O!P)y!P!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U*OWrSOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U*oWrSmQOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U+^^rSOt#{uw#{x}#{}!O,Y!O!Q#{!Q![)S![!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{U,_[rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{U-[UyQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U-sWrSOt#{uw#{x!P#{!P!Q.]!Q#O#{#P;'S#{;'S;=`$d<%lO#{U.b^rSOY/^YZ#{Zt/^tu0auw/^wx0ax!P/^!P!Q#{!Q!}/^!}#O5S#O#P2o#P;'S/^;'S;=`6T<%lO/^U/e^rSvQOY/^YZ#{Zt/^tu0auw/^wx0ax!P/^!P!Q3U!Q!}/^!}#O5S#O#P2o#P;'S/^;'S;=`6T<%lO/^Q0fXvQOY0aZ!P0a!P!Q1R!Q!}0a!}#O1p#O#P2o#P;'S0a;'S;=`3O<%lO0aQ1UP!P!Q1XQ1^UvQ#Z#[1X#]#^1X#a#b1X#g#h1X#i#j1X#m#n1XQ1sVOY1pZ#O1p#O#P2Y#P#Q0a#Q;'S1p;'S;=`2i<%lO1pQ2]SOY1pZ;'S1p;'S;=`2i<%lO1pQ2lP;=`<%l1pQ2rSOY0aZ;'S0a;'S;=`3O<%lO0aQ3RP;=`<%l0aU3ZWrSOt#{uw#{x!P#{!P!Q3s!Q#O#{#P;'S#{;'S;=`$d<%lO#{U3zbrSvQOt#{uw#{x#O#{#P#Z#{#Z#[3s#[#]#{#]#^3s#^#a#{#a#b3s#b#g#{#g#h3s#h#i#{#i#j3s#j#m#{#m#n3s#n;'S#{;'S;=`$d<%lO#{U5X[rSOY5SYZ#{Zt5Stu1puw5Swx1px#O5S#O#P2Y#P#Q/^#Q;'S5S;'S;=`5}<%lO5SU6QP;=`<%l5SU6WP;=`<%l/^U6bUrS!OQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U6{W#ZQrSOt#{uw#{x!_#{!_!`7e!`#O#{#P;'S#{;'S;=`$d<%lO#{U7jVrSOt#{uw#{x#O#{#P#Q8P#Q;'S#{;'S;=`$d<%lO#{U8WU#YQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~8oO#U~U8vU#`QrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9aUrS!VQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9x]rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#U:q#U#o,Y#o;'S#{;'S;=`$d<%lO#{U:v^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#`,Y#`#a;r#a#o,Y#o;'S#{;'S;=`$d<%lO#{U;w^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#g,Y#g#h<s#h#o,Y#o;'S#{;'S;=`$d<%lO#{U<x^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#X,Y#X#Y=t#Y#o,Y#o;'S#{;'S;=`$d<%lO#{U={[uQrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^>x[#VWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^?u[#XWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^@r^#WWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#f,Y#f#gAn#g#o,Y#o;'S#{;'S;=`$d<%lO#{UAs^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#i,Y#i#j<s#j#o,Y#o;'S#{;'S;=`$d<%lO#{UBvU!ZQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~C_O#i~",
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!}~~", 11)],
topRules: {"Program":[0,25]},
specialized: [{term: 20, get: (value: any, stack: any) => (specializeKeyword(value, stack) << 1), external: specializeKeyword},{term: 20, get: (value: keyof typeof spec_Identifier) => spec_Identifier[value] || -1}],
tokenPrec: 1578
tokenPrec: 1705
})

View File

@ -752,7 +752,7 @@ Assign
EqEq ==
Number 5
colon :
Block
ThenBlock
Boolean true
keyword end
keyword end
@ -794,7 +794,7 @@ Assign
EqEq ==
Number 5
colon :
Block
ThenBlock
Boolean true
keyword end
keyword end

View File

@ -2,7 +2,7 @@ import { expect, describe, test } from 'bun:test'
import '../shrimp.grammar' // Importing this so changes cause it to retest!
describe('if/else if/else', () => {
describe('if/elseif/else', () => {
test('parses single line if', () => {
expect(`if y == 1: 'cool' end`).toMatchTree(`
IfExpr
@ -12,7 +12,7 @@ describe('if/else if/else', () => {
EqEq ==
Number 1
colon :
Block
SingleLineThenBlock
String
StringFragment cool
keyword end
@ -26,7 +26,7 @@ describe('if/else if/else', () => {
keyword if
Identifier x
colon :
Block
SingleLineThenBlock
Number 2
keyword end
`)
@ -44,7 +44,7 @@ describe('if/else if/else', () => {
Lt <
Number 9
colon :
Block
ThenBlock
FunctionCallOrIdentifier
Identifier yes
keyword end
@ -61,81 +61,78 @@ describe('if/else if/else', () => {
keyword if
Identifier with-else
colon :
Block
ThenBlock
FunctionCallOrIdentifier
Identifier x
ElseExpr
keyword else
colon :
Block
ThenBlock
FunctionCallOrIdentifier
Identifier y
keyword end
`)
})
test('parses multiline if with else if', () => {
expect(`if with-else-if:
test('parses multiline if with elseif', () => {
expect(`if with-elseif:
x
else if another-condition:
elseif another-condition:
y
end`).toMatchTree(`
IfExpr
keyword if
Identifier with-else-if
Identifier with-elseif
colon :
Block
ThenBlock
FunctionCallOrIdentifier
Identifier x
ElseIfExpr
keyword else
keyword if
keyword elseif
Identifier another-condition
colon :
Block
ThenBlock
FunctionCallOrIdentifier
Identifier y
keyword end
`)
})
test('parses multiline if with multiple else if and else', () => {
expect(`if with-else-if-else:
test('parses multiline if with multiple elseif and else', () => {
expect(`if with-elseif-else:
x
else if another-condition:
elseif another-condition:
y
else if yet-another-condition:
elseif yet-another-condition:
z
else:
oh-no
end`).toMatchTree(`
IfExpr
keyword if
Identifier with-else-if-else
Identifier with-elseif-else
colon :
Block
ThenBlock
FunctionCallOrIdentifier
Identifier x
ElseIfExpr
keyword else
keyword if
keyword elseif
Identifier another-condition
colon :
Block
ThenBlock
FunctionCallOrIdentifier
Identifier y
ElseIfExpr
keyword else
keyword if
keyword elseif
Identifier yet-another-condition
colon :
Block
ThenBlock
FunctionCallOrIdentifier
Identifier z
ElseExpr
keyword else
colon :
Block
ThenBlock
FunctionCallOrIdentifier
Identifier oh-no
keyword end
@ -151,124 +148,9 @@ describe('if/else if/else', () => {
keyword if
Boolean true
colon :
Block
SingleLineThenBlock
Number 2
keyword end
`)
})
})
describe('while', () => {
test('infinite loop', () => {
expect(`while true: true end`).toMatchTree(`
WhileExpr
keyword while
Boolean true
colon :
Block
Boolean true
keyword end`)
})
test('basic expression', () => {
expect(`while a > 0: true end`).toMatchTree(`
WhileExpr
keyword while
ConditionalOp
Identifier a
Gt >
Number 0
colon :
Block
Boolean true
keyword end`)
})
test('compound expression', () => {
expect(`while a > 0 and b < 100 and c < 1000: true end`).toMatchTree(`
WhileExpr
keyword while
ConditionalOp
ConditionalOp
ConditionalOp
Identifier a
Gt >
Number 0
And and
ConditionalOp
Identifier b
Lt <
Number 100
And and
ConditionalOp
Identifier c
Lt <
Number 1000
colon :
Block
Boolean true
keyword end`)
})
test('multiline infinite loop', () => {
expect(`
while true:
true
end`).toMatchTree(`
WhileExpr
keyword while
Boolean true
colon :
Block
Boolean true
keyword end`)
})
test('multiline basic expression', () => {
expect(`
while a > 0:
true
end`).toMatchTree(`
WhileExpr
keyword while
ConditionalOp
Identifier a
Gt >
Number 0
colon :
Block
Boolean true
keyword end`)
})
test('multiline compound expression', () => {
expect(`
while a > 0 and b < 100 and c < 1000:
true
end`).toMatchTree(`
WhileExpr
keyword while
ConditionalOp
ConditionalOp
ConditionalOp
Identifier a
Gt >
Number 0
And and
ConditionalOp
Identifier b
Lt <
Number 100
And and
ConditionalOp
Identifier c
Lt <
Number 1000
colon :
Block
Boolean true
keyword end`)
})
})

View File

@ -12,14 +12,14 @@ describe('try/catch/finally/throw', () => {
TryExpr
keyword try
colon :
Block
TryBlock
FunctionCallOrIdentifier
Identifier risky-operation
CatchExpr
keyword catch
Identifier err
colon :
Block
TryBlock
FunctionCall
Identifier handle-error
PositionalArg
@ -37,13 +37,13 @@ describe('try/catch/finally/throw', () => {
TryExpr
keyword try
colon :
Block
TryBlock
FunctionCallOrIdentifier
Identifier do-work
FinallyExpr
keyword finally
colon :
Block
TryBlock
FunctionCallOrIdentifier
Identifier cleanup
keyword end
@ -61,14 +61,14 @@ describe('try/catch/finally/throw', () => {
TryExpr
keyword try
colon :
Block
TryBlock
FunctionCallOrIdentifier
Identifier risky-operation
CatchExpr
keyword catch
Identifier err
colon :
Block
TryBlock
FunctionCall
Identifier handle-error
PositionalArg
@ -76,7 +76,7 @@ describe('try/catch/finally/throw', () => {
FinallyExpr
keyword finally
colon :
Block
TryBlock
FunctionCallOrIdentifier
Identifier cleanup
keyword end
@ -91,17 +91,15 @@ describe('try/catch/finally/throw', () => {
TryExpr
keyword try
colon :
Block
FunctionCall
Identifier parse-number
PositionalArg
Identifier input
FunctionCall
Identifier parse-number
PositionalArg
Identifier input
CatchExpr
keyword catch
Identifier err
colon :
Block
Number 0
Number 0
keyword end
`)
})
@ -111,21 +109,18 @@ describe('try/catch/finally/throw', () => {
TryExpr
keyword try
colon :
Block
FunctionCallOrIdentifier
Identifier work
FunctionCallOrIdentifier
Identifier work
CatchExpr
keyword catch
Identifier err
colon :
Block
Number 0
Number 0
FinallyExpr
keyword finally
colon :
Block
FunctionCallOrIdentifier
Identifier cleanup
FunctionCallOrIdentifier
Identifier cleanup
keyword end
`)
})
@ -169,15 +164,13 @@ describe('try/catch/finally/throw', () => {
TryExpr
keyword try
colon :
Block
FunctionCallOrIdentifier
Identifier work
FunctionCallOrIdentifier
Identifier work
CatchExpr
keyword catch
Identifier err
colon :
Block
Number 0
Number 0
keyword end
`)
})
@ -206,7 +199,7 @@ describe('function-level exception handling', () => {
keyword catch
Identifier e
colon :
Block
TryBlock
FunctionCallOrIdentifier
Identifier empty-string
keyword end
@ -234,7 +227,7 @@ describe('function-level exception handling', () => {
FinallyExpr
keyword finally
colon :
Block
TryBlock
FunctionCallOrIdentifier
Identifier close-resources
keyword end
@ -266,7 +259,7 @@ describe('function-level exception handling', () => {
keyword catch
Identifier err
colon :
Block
TryBlock
FunctionCall
Identifier log
PositionalArg
@ -276,7 +269,7 @@ describe('function-level exception handling', () => {
FinallyExpr
keyword finally
colon :
Block
TryBlock
FunctionCallOrIdentifier
Identifier cleanup
keyword end

View File

@ -9,13 +9,12 @@ describe('single line function blocks', () => {
FunctionCallOrIdentifier
Identifier trap
colon :
Block
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
@ -28,13 +27,12 @@ describe('single line function blocks', () => {
PositionalArg
Word EXIT
colon :
Block
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
@ -49,13 +47,12 @@ describe('single line function blocks', () => {
String
StringFragment exit
colon :
Block
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
@ -76,13 +73,12 @@ describe('single line function blocks', () => {
String
StringFragment EXIT
colon :
Block
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
@ -99,13 +95,12 @@ end
FunctionCallOrIdentifier
Identifier trap
colon :
Block
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
@ -121,13 +116,12 @@ end`).toMatchTree(`
PositionalArg
Word EXIT
colon :
Block
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
@ -148,13 +142,12 @@ end`).toMatchTree(`
NamedArgPrefix code=
Number 1
colon :
Block
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
@ -179,13 +172,12 @@ end`).toMatchTree(`
String
StringFragment EXIT
colon :
Block
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
@ -203,27 +195,26 @@ end`).toMatchTree(`
FunctionCallOrIdentifier
Identifier head
colon :
Block
FunctionCall
Identifier title
PositionalArg
Word What
PositionalArg
Identifier up
FunctionCall
Identifier meta
PositionalArg
Word charSet=UTF-8
FunctionCall
Identifier meta
NamedArg
NamedArgPrefix name=
String
StringFragment viewport
NamedArg
NamedArgPrefix content=
String
StringFragment width=device-width, initial-scale=1, viewport-fit=cover
FunctionCall
Identifier title
PositionalArg
Word What
PositionalArg
Identifier up
FunctionCall
Identifier meta
PositionalArg
Word charSet=UTF-8
FunctionCall
Identifier meta
NamedArg
NamedArgPrefix name=
String
StringFragment viewport
NamedArg
NamedArgPrefix content=
String
StringFragment width=device-width, initial-scale=1, viewport-fit=cover
keyword end
`)
})
@ -239,23 +230,22 @@ end`).toMatchTree(`
FunctionCallOrIdentifier
Identifier list
colon :
Block
FunctionCall
Identifier li
NamedArg
NamedArgPrefix border-bottom=
String
StringFragment 1px solid black
PositionalArg
Identifier one
FunctionCall
Identifier li
PositionalArg
Identifier two
FunctionCall
Identifier li
PositionalArg
Identifier three
FunctionCall
Identifier li
NamedArg
NamedArgPrefix border-bottom=
String
StringFragment 1px solid black
PositionalArg
Identifier one
FunctionCall
Identifier li
PositionalArg
Identifier two
FunctionCall
Identifier li
PositionalArg
Identifier three
keyword end`)
})
@ -270,34 +260,33 @@ end`)
FunctionCallOrIdentifier
Identifier p
colon :
Block
FunctionCall
Identifier h1
NamedArg
NamedArgPrefix class=
Identifier bright
NamedArg
NamedArgPrefix style=
String
StringFragment font-family: helvetica
PositionalArg
Word Heya
FunctionCall
Identifier h2
PositionalArg
Identifier man
PositionalArg
Identifier that
PositionalArg
Identifier is
PositionalArg
ParenExpr
FunctionCall
Identifier b
PositionalArg
Identifier wild
PositionalArg
Word !
FunctionCall
Identifier h1
NamedArg
NamedArgPrefix class=
Identifier bright
NamedArg
NamedArgPrefix style=
String
StringFragment font-family: helvetica
PositionalArg
Word Heya
FunctionCall
Identifier h2
PositionalArg
Identifier man
PositionalArg
Identifier that
PositionalArg
Identifier is
PositionalArg
ParenExpr
FunctionCall
Identifier b
PositionalArg
Identifier wild
PositionalArg
Word !
keyword end`)
})
})