what have i done

This commit is contained in:
Chris Wanstrath 2025-11-01 16:31:18 -07:00
parent bf0f781762
commit adcb956fa2
6 changed files with 506 additions and 19 deletions

View File

@ -405,6 +405,51 @@ export class Compiler {
return instructions return instructions
} }
case terms.FunctionCallWithBlock: {
const [fn, _colon, ...block] = getAllChildren(node)
let instructions: ProgramItem[] = []
const fnLabel: Label = `.func_${this.fnLabelCount++}`
const afterLabel: Label = `.after_${fnLabel}`
instructions.push(['JUMP', afterLabel])
instructions.push([`${fnLabel}:`])
instructions.push(
...block.filter(x => x.type.name !== 'keyword')
.map(x => this.#compileNode(x!, input))
.flat()
)
instructions.push(['RETURN'])
instructions.push([`${afterLabel}:`])
if (fn?.type.id === terms.FunctionCallOrIdentifier) {
instructions.push(['LOAD', input.slice(fn!.from, fn!.to)])
instructions.push(['MAKE_FUNCTION', [], fnLabel])
instructions.push(['PUSH', 1])
instructions.push(['PUSH', 0])
instructions.push(['CALL'])
} else if (fn?.type.id === terms.FunctionCall) {
let body = this.#compileNode(fn!, input)
const namedArgCount = (body[body.length - 2]![1] as number) * 2
const startSlice = body.length - namedArgCount - 3
body = [
...body.slice(0, startSlice),
['MAKE_FUNCTION', [], fnLabel],
...body.slice(startSlice)
]
// @ts-ignore
body[body.length - 3]![1] += 1
instructions.push(...body)
} else {
throw new Error(`FunctionCallWithBlock: Expected FunctionCallOrIdentifier or FunctionCall`)
}
return instructions
}
case terms.TryExpr: { case terms.TryExpr: {
const { tryBlock, catchVariable, catchBody, finallyBody } = getTryExprParts(node, input) const { tryBlock, catchVariable, catchBody, finallyBody } = getTryExprParts(node, input)

View File

@ -0,0 +1,136 @@
import { expect, describe, test } from 'bun:test'
describe('single line function blocks', () => {
test('work with no args', () => {
expect(`trap = do x: x end; trap: true end`).toEvaluateTo(true)
})
test('work with one arg', () => {
expect(`trap = do x y: [ x (y) ] end; trap EXIT: true end`).toEvaluateTo(['EXIT', true])
})
test('work with named args', () => {
expect(`attach = do signal fn: [ signal (fn) ] end; attach signal='exit': true end`).toEvaluateTo(['exit', true])
})
test('work with dot-get', () => {
expect(`signals = [trap=do x y: [x (y)] end]; signals.trap 'EXIT': true end`).toEvaluateTo(['EXIT', true])
})
})
describe('multi line function blocks', () => {
test('work with no args', () => {
expect(`
trap = do x: x end
trap:
true
end`).toEvaluateTo(true)
})
test('work with one arg', () => {
expect(`
trap = do x y: [ x (y) ] end
trap EXIT:
true
end`).toEvaluateTo(['EXIT', true])
})
test('work with named args', () => {
expect(`
attach = do signal fn: [ signal (fn) ] end
attach signal='exit':
true
end`).toEvaluateTo(['exit', true])
})
test('work with dot-get', () => {
expect(`
signals = [trap=do x y: [x (y)] end]
signals.trap 'EXIT':
true
end`).toEvaluateTo(['EXIT', true])
})
})
describe('ribbit', () => {
test('head tag', () => {
expect(`
head:
title What up
meta charSet=UTF-8
meta name=viewport content='width=device-width, initial-scale=1, viewport-fit=cover'
end`).toEvaluateTo(`head`, {
head: () => 'head'
})
})
test('li', () => {
expect(`
list:
li border-bottom='1px solid black' one
li two
li three
end`).toEvaluateTo(`list`, {
list: () => 'list'
})
})
test('inline expressions', () => {
const buffer: string[] = []
const tagBlock = async (tagName: string, props = {}, fn: Function) => {
const attrs = Object.entries(props).map(([key, value]) => `${key}="${value}"`)
const space = attrs.length ? ' ' : ''
buffer.push(`<${tagName}${space}${attrs.join(' ')}>`)
await fn()
buffer.push(`</${tagName}>`)
}
const tagCall = (tagName: string, atNamed: {}, ...args: any[]) => {
const attrs = Object.entries(atNamed).map(([key, value]) => `${key}="${value}"`)
const space = attrs.length ? ' ' : ''
const children = args
.reverse()
.map(a => a === null ? buffer.pop() : a)
.reverse().join(' ')
.replaceAll(' !!ribbit-nospace!! ', '')
buffer.push(`<${tagName}${space}${attrs.join(' ')}>${children}</${tagName}>`)
}
const tag = async (tagName: string, atNamed: {}, ...args: any[]) => {
if (typeof args[0] === 'function')
await tagBlock(tagName, atNamed, args[0])
else
tagCall(tagName, atNamed, ...args)
}
expect(`
ribbit:
p class=container:
h1 class=bright style='font-family: helvetica' Heya
h2 man that is (b wild) (nospace) !
p Double the fun.
end
end`).toEvaluateTo(
`<p class="container">
<h1 class="bright" style="font-family: helvetica">Heya</h1>
<h2>man that is <b>wild</b>!</h2>
<p>Double the fun.</p>
</p>`, {
ribbit: async (cb: Function) => {
await cb()
return buffer.join("\n")
},
p: (atNamed: {}, ...args: any[]) => tag('p', atNamed, ...args),
h1: (atNamed: {}, ...args: any[]) => tag('h1', atNamed, ...args),
h2: (atNamed: {}, ...args: any[]) => tag('h2', atNamed, ...args),
b: (atNamed: {}, ...args: any[]) => tag('b', atNamed, ...args),
nospace: () => '!!ribbit-nospace!!',
join: (...args: string[]) => args.join(''),
})
})
})

View File

@ -50,6 +50,7 @@ item {
consumeToTerminator { consumeToTerminator {
PipeExpr | PipeExpr |
FunctionCallWithBlock |
ambiguousFunctionCall | ambiguousFunctionCall |
TryExpr | TryExpr |
Throw | Throw |
@ -70,6 +71,18 @@ pipeOperand {
FunctionCall | FunctionCallOrIdentifier FunctionCall | FunctionCallOrIdentifier
} }
FunctionCallWithBlock {
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 { FunctionCallOrIdentifier {
DotGet | Identifier DotGet | Identifier
} }

View File

@ -45,7 +45,7 @@ export const
Params = 43, Params = 43,
colon = 44, colon = 44,
CatchExpr = 45, CatchExpr = 45,
keyword = 68, keyword = 69,
TryBlock = 47, TryBlock = 47,
FinallyExpr = 48, FinallyExpr = 48,
Underscore = 51, Underscore = 51,
@ -53,12 +53,13 @@ export const
Null = 53, Null = 53,
ConditionalOp = 54, ConditionalOp = 54,
PositionalArg = 55, PositionalArg = 55,
TryExpr = 57, FunctionCallWithBlock = 57,
Throw = 59, TryExpr = 58,
IfExpr = 61, Throw = 60,
SingleLineThenBlock = 63, IfExpr = 62,
ThenBlock = 64, SingleLineThenBlock = 64,
ElseIfExpr = 65, ThenBlock = 65,
ElseExpr = 67, ElseIfExpr = 66,
CompoundAssign = 69, ElseExpr = 68,
Assign = 70 CompoundAssign = 70,
Assign = 71

View File

@ -4,14 +4,14 @@ import {operatorTokenizer} from "./operatorTokenizer"
import {tokenizer, specializeKeyword} from "./tokenizer" import {tokenizer, specializeKeyword} from "./tokenizer"
import {trackScope} from "./scopeTracker" import {trackScope} from "./scopeTracker"
import {highlighting} from "./highlight" import {highlighting} from "./highlight"
const spec_Identifier = {__proto__:null,catch:92, finally:98, end:100, null:106, try:116, throw:120, if:124, elseif:132, else:136} const spec_Identifier = {__proto__:null,catch:92, finally:98, end:100, null:106, try:118, throw:122, if:126, elseif:134, else:138}
export const parser = LRParser.deserialize({ export const parser = LRParser.deserialize({
version: 14, version: 14,
states: "9[QYQbOOO#tQcO'#C{O$qOSO'#C}O%PQbO'#EfOOQ`'#DW'#DWOOQa'#DT'#DTO&SQbO'#DbO'eQcO'#EZOOQa'#EZ'#EZO(hQcO'#EZO)jQcO'#EYO)}QRO'#C|O+ZQcO'#EUO+kQcO'#EUO+uQbO'#CzO,mOpO'#CxOOQ`'#EV'#EVO,rQbO'#EUO,yQQO'#ElOOQ`'#Dg'#DgO-OQbO'#DiO-OQbO'#EnOOQ`'#Dk'#DkO-sQRO'#DsOOQ`'#EU'#EUO.XQQO'#ETOOQ`'#ET'#ETOOQ`'#Du'#DuQYQbOOO.aQbO'#DUOOQa'#EY'#EYOOQ`'#De'#DeOOQ`'#Ek'#EkOOQ`'#D|'#D|O.kQbO,59cO/_QbO'#DPO/gQWO'#DQOOOO'#E]'#E]OOOO'#Dv'#DvO/{OSO,59iOOQa,59i,59iOOQ`'#Dx'#DxO0ZQbO'#DXO0cQQO,5;QOOQ`'#Dw'#DwO0hQbO,59|O0oQQO,59oOOQa,59|,59|O0zQbO,59|O1UQbO,5:`O-OQbO,59hO-OQbO,59hO-OQbO,59hO-OQbO,5:OO-OQbO,5:OO-OQbO,5:OO1fQRO,59fO1mQRO,59fO2OQRO,59fO1yQQO,59fO2ZQQO,59fO2cObO,59dO2nQbO'#D}O2yQbO,59bO3bQbO,5;WO3uQcO,5:TO4kQcO,5:TO4{QcO,5:TO5qQRO,5;YO5xQRO,5;YO1UQbO,5:_OOQ`,5:o,5:oOOQ`-E7s-E7sOOQ`,59p,59pOOQ`-E7z-E7zOOOO,59k,59kOOOO,59l,59lOOOO-E7t-E7tOOQa1G/T1G/TOOQ`-E7v-E7vO6TQbO1G0lOOQ`-E7u-E7uO6hQQO1G/ZOOQa1G/h1G/hO6sQbO1G/hOOQO'#Dz'#DzO6hQQO1G/ZOOQa1G/Z1G/ZOOQ`'#D{'#D{O6sQbO1G/hOOQ`1G/z1G/zOOQa1G/S1G/SO7lQcO1G/SO7vQcO1G/SO8QQcO1G/SOOQa1G/j1G/jO9pQcO1G/jO9wQcO1G/jO:OQcO1G/jOOQa1G/Q1G/QOOQa1G/O1G/OO!aQbO'#C{O:VQbO'#CwOOQ`,5:i,5:iOOQ`-E7{-E7{O:dQbO1G0rO:oQbO1G0sO;]QbO1G0tOOQ`1G/y1G/yO;pQbO7+&WO:oQbO7+&YO;{QQO7+$uOOQa7+$u7+$uO<WQbO7+%SOOQa7+%S7+%SOOQO-E7x-E7xOOQ`-E7y-E7yO<bQbO'#DZO<gQQO'#D^OOQ`7+&^7+&^O<lQbO7+&^O<qQbO7+&^OOQ`'#Dy'#DyO<yQQO'#DyO=OQbO'#EgOOQ`'#D]'#D]O=rQbO7+&_OOQ`'#Dm'#DmO=}QbO7+&`O>SQbO7+&aOOQ`<<Ir<<IrO>pQbO<<IrO>uQbO<<IrO>}QbO<<ItOOQa<<Ha<<HaOOQa<<Hn<<HnO?YQQO,59uO?_QbO,59xOOQ`<<Ix<<IxO?rQbO<<IxOOQ`,5:e,5:eOOQ`-E7w-E7wOOQ`<<Iy<<IyO?wQbO<<IyO?|QbO<<IyOOQ`<<Iz<<IzOOQ`'#Dn'#DnO@UQbO<<I{OOQ`AN?^AN?^O@aQbOAN?^OOQ`AN?`AN?`O@fQbOAN?`O@kQbOAN?`O@sQbO1G/aOAWQbO1G/dOOQ`1G/d1G/dOOQ`AN?dAN?dOOQ`AN?eAN?eOAnQbOAN?eO-OQbO'#DoOOQ`'#EO'#EOOAsQbOAN?gOBOQQO'#DqOOQ`AN?gAN?gOBTQbOAN?gOOQ`G24xG24xOOQ`G24zG24zOBYQbOG24zOB_QbO7+${OOQ`7+${7+${OOQ`7+%O7+%OOOQ`G25PG25POBxQRO,5:ZOCPQRO,5:ZOOQ`-E7|-E7|OOQ`G25RG25ROC[QbOG25ROCaQQO,5:]OOQ`LD*fLD*fOOQ`<<Hg<<HgOCfQQO1G/uOOQ`LD*mLD*mOAWQbO1G/wO>SQbO7+%aOOQ`7+%c7+%cOOQ`<<H{<<H{", states: ";fQYQbOOO#tQcO'#C{O$tOSO'#C}O%SQbO'#EgOOQ`'#DW'#DWOOQa'#DT'#DTO&VQbO'#DbO'hQcO'#E[OOQa'#E['#E[O(kQcO'#E[O)mQcO'#EZO*QQRO'#C|O+^QcO'#EVO+nQcO'#EVO+xQbO'#CzO,pOpO'#CxOOQ`'#EW'#EWO,uQbO'#EVOOQ`'#Dg'#DgO-PQQO'#EoOOQ`'#Dh'#DhO-UQbO'#DjO-UQbO'#EqOOQ`'#Dl'#DlO-yQRO'#DtOOQ`'#EV'#EVO._QQO'#EUOOQ`'#EU'#EUOOQ`'#Dv'#DvQYQbOOO.gQbO'#DUOOQa'#EZ'#EZOOQ`'#De'#DeOOQ`'#El'#ElOOQ`'#D}'#D}O.qQbO,59cO/hQbO'#DPO/pQWO'#DQOOOO'#E^'#E^OOOO'#Dw'#DwO0UOSO,59iOOQa,59i,59iOOQ`'#Dy'#DyO0dQbO'#DXO0lQQO,5;ROOQ`'#Dx'#DxO0qQbO,59|O0xQQO,59oOOQa,59|,59|O1TQbO,59|O1_QbO,5:aO-UQbO,59hO-UQbO,59hO-UQbO,59hO-UQbO,5:OO-UQbO,5:OO-UQbO,5:OO1oQRO,59fO1vQRO,59fO2XQRO,59fO2SQQO,59fO2dQQO,59fO2lObO,59dO2wQbO'#EOO3SQbO,59bO3kQbO,5;XO4OQbO,5;ZO4cQcO,5:UO5XQcO,5:UO5iQcO,5:UO6_QRO,5;]O6fQRO,5;]O1_QbO,5:`OOQ`,5:p,5:pOOQ`-E7t-E7tOOQ`,59p,59pOOQ`-E7{-E7{OOOO,59k,59kOOOO,59l,59lOOOO-E7u-E7uOOQa1G/T1G/TOOQ`-E7w-E7wO6qQbO1G0mOOQ`-E7v-E7vO7UQQO1G/ZOOQa1G/h1G/hO7aQbO1G/hOOQO'#D{'#D{O7UQQO1G/ZOOQa1G/Z1G/ZOOQ`'#D|'#D|O7aQbO1G/hOOQ`1G/{1G/{OOQa1G/S1G/SO8YQcO1G/SO8dQcO1G/SO8nQcO1G/SOOQa1G/j1G/jO:^QcO1G/jO:eQcO1G/jO:lQcO1G/jOOQa1G/Q1G/QOOQa1G/O1G/OO!aQbO'#C{O:sQbO'#CwOOQ`,5:j,5:jOOQ`-E7|-E7|O;QQbO1G0sO;]QbO1G0tO;yQbO1G0uO;]QbO1G0vO<UQbO1G0wOOQ`1G/z1G/zO<iQbO7+&XO;]QbO7+&ZO<tQQO7+$uOOQa7+$u7+$uO=PQbO7+%SOOQa7+%S7+%SOOQO-E7y-E7yOOQ`-E7z-E7zO=ZQbO'#DZO=`QQO'#D^OOQ`7+&_7+&_O=eQbO7+&_O=jQbO7+&_OOQ`'#Dz'#DzO=rQQO'#DzO=wQbO'#EhO>kQbO7+&`OOQ`7+&a7+&aO>vQbO7+&aO>{QbO7+&aOOQ`'#D]'#D]O?TQbO7+&bOOQ`'#Dn'#DnO?`QbO7+&cO?eQbO7+&dOOQ`<<Is<<IsO@RQbO<<IsO@WQbO<<IsO@`QbO<<IuOOQa<<Ha<<HaOOQa<<Hn<<HnO@kQQO,59uO@pQbO,59xOOQ`<<Iy<<IyOATQbO<<IyOOQ`,5:f,5:fOOQ`-E7x-E7xOOQ`<<Iz<<IzOAYQbO<<IzOA_QbO<<IzOOQ`<<I{<<I{OAgQbO<<I{OOQ`<<I|<<I|OAlQbO<<I|OAqQbO<<I|OOQ`<<I}<<I}OOQ`'#Do'#DoOAyQbO<<JOOOQ`AN?_AN?_OBUQbOAN?_OOQ`AN?aAN?aOBZQbOAN?aOB`QbOAN?aOBhQbO1G/aOB{QbO1G/dOOQ`1G/d1G/dOOQ`AN?eAN?eOOQ`AN?fAN?fOCcQbOAN?fOOQ`AN?gAN?gOOQ`AN?hAN?hOChQbOAN?hO-UQbO'#DpOOQ`'#EP'#EPOCmQbOAN?jOCxQQO'#DrOOQ`AN?jAN?jOC}QbOAN?jOOQ`G24yG24yOOQ`G24{G24{ODSQbOG24{ODXQbO7+${OOQ`7+${7+${OOQ`7+%O7+%OOOQ`G25QG25QOOQ`G25SG25SODrQRO,5:[ODyQRO,5:[OOQ`-E7}-E7}OOQ`G25UG25UOEUQbOG25UOEZQQO,5:^OOQ`LD*gLD*gOOQ`<<Hg<<HgOE`QQO1G/vOOQ`LD*pLD*pOB{QbO1G/xO?eQbO7+%bOOQ`7+%d7+%dOOQ`<<H|<<H|",
stateData: "Cn~O!uOS!vOS~OdPOegOfWOg_OhROmWOuWOvWO!VWO![bO!^dO!`eO!{^O#OQO#VTO#WUO#XjO~OdnOfWOg_OhROmWOuWOvWOymO!ToO!VWO!{^O#OQO#VTO#WUO!YoX#XoX#doX#^oX!OoX!RoX!SoX~OP!|XQ!|XR!|XS!|XT!|XU!|XW!|XX!|XY!|XZ!|X[!|X]!|X^!|X~P!aOruO#OxO#QsO#RtO~OdyO|{P~OdnOfWOg_OmWOuWOvWOymO!VWO!{^O#OQO#VTO#WUO#X|O~O#]!PO~P%XOP!}XQ!}XR!}XS!}XT!}XU!}XW!}XX!}XY!}XZ!}X[!}X]!}X^!}X#X!}X#d!}X!O!}X!R!}X!S!}X~OdnOfWOg_OhROmWOuWOvWOymO!ToO!VWO!{^O#OQO#VTO#WUO#^!}X~P&ZOV!RO~P&ZOP!|XQ!|XR!|XS!|XT!|XU!|XW!|XX!|XY!|XZ!|X[!|X]!|X^!|X~O#X!xX#d!xX!O!xX!R!xX!S!xX~P(oOP!TOQ!TOR!UOS!UOT!WOU!XOW!VOX!VOY!VOZ!VO[!VO]!VO^!SO~O#X!xX#d!xX!O!xX!R!xX!S!xX~OP!TOQ!TOR!UOS!UO~P*xOT!WOU!XO~P*xOdPOfWOg_OhROmWOuWOvWO!VWO!{^O#OQO#VTO#WUO~O!z!_O~O!Y!`O~P*xO|!bO~OdnOfWOg_OmWOuWOvWO!VWO!{^O#OQO#VTO#WUO~OV!RO_!hO`!hOa!hOb!hOc!hO~O#X!iO#d!iO~OhRO!T!kO~P-OOhROymO!ToO!Yka#Xka#dka#^ka!Oka!Rka!Ska~P-OOd!mO!{^O~O#O!nO#Q!nO#R!nO#S!nO#T!nO#U!nO~OruO#O!pO#QsO#RtO~OdyO|{X~O|!rO~O#]!uO~P%XOymO#X!wO#]!yO~O#X!zO#]!uO~P-OOegO![bO!^dO!`eO~P+uO#^#VO~P(oOP!TOQ!TOR!UOS!UO#^#VO~OT!WOU!XO#^#VO~O!Y!`O#^#VO~Od#WOm#WO!{^O~Od#XOg_O!{^O~O!Y!`O#Xja#dja#^ja!Oja!Rja!Sja~OegO![bO!^dO!`eO#X#^O~P+uO#X!]a#d!]a!O!]a!R!]a!S!]a~P)}O#X!]a#d!]a!O!]a!R!]a!S!]a~OP!TOQ!TOR!UOS!UO~P4YOT!WOU!XO~P4YOT!WOU!XOW!VOX!VOY!VOZ!VO[!VO]!VO~O|#_O~P5VOT!WOU!XO|#_O~OegO![bO!^dO!`eO#X#bO~P+uOymO#X!wO#]#dO~O#X!zO#]#fO~P-OO^!SORpiSpi#Xpi#dpi#^pi!Opi!Rpi!Spi~OPpiQpi~P6}OP!TOQ!TO~P6}OP!TOQ!TORpiSpi#Xpi#dpi#^pi!Opi!Rpi!Spi~OW!VOX!VOY!VOZ!VO[!VO]!VOT!Wi#X!Wi#d!Wi#^!Wi|!Wi!O!Wi!R!Wi!S!Wi~OU!XO~P8rOU!XO~P9UOU!Wi~P8rOhROymO!ToO~P-OO!O#iO!R#jO!S#kO~OegO![bO!^dO!`eO#X#nO!O#ZP!R#ZP!S#ZP~P+uOegO![bO!^dO!`eO#X#uO~P+uO!O#iO!R#jO!S#vO~OymO#X!wO#]#zO~O#X!zO#]#{O~P-OOd#|O~O|#}O~O!S$OO~O!R#jO!S$OO~O#X$QO~OegO![bO!^dO!`eO#X#nO!O#ZX!R#ZX!S#ZX!d#ZX!f#ZX~P+uO!O#iO!R#jO!S$SO~O!S$VO~OegO![bO!^dO!`eO#X#nO!S#ZP!d#ZP!f#ZP~P+uO!S$YO~O!R#jO!S$YO~O!O#iO!R#jO!S$[O~O|$_O~OegO![bO!^dO!`eO#X$`O~P+uO!S$bO~O!S$cO~O!R#jO!S$cO~O!S$iO!d$eO!f$hO~O!S$kO~O!S$lO~O!R#jO!S$lO~OegO![bO!^dO!`eO#X$nO~P+uOegO![bO!^dO!`eO#X#nO!S#ZP~P+uO!S$qO~O!S$uO!d$eO!f$hO~O|$wO~O!S$uO~O!S$xO~OegO![bO!^dO!`eO#X#nO!R#ZP!S#ZP~P+uO|$zO~P5VOT!WOU!XO|$zO~O!S${O~O#X$|O~O#X$}O~Omv~", stateData: "Eh~O!vOS!wOS~OdPOehOfWOg_OhROmWOuWOvWO!VWO!]cO!_eO!afO!|^O#PQO#WTO#XUO#YkO~OdoOfWOg_OhROmWOuWOvWOynO!TpO!VWO!|^O#PQO#WTO#XUO!YoX#YoX#goX#_oX!OoX!RoX!SoX~OP!}XQ!}XR!}XS!}XT!}XU!}XW!}XX!}XY!}XZ!}X[!}X]!}X^!}X|oX~P!aOrvO#PyO#RtO#SuO~OdzO|{P~OdoOfWOg_OmWOuWOvWOynO!VWO!|^O#PQO#WTO#XUO#Y}O~O#^!QO~P%[OP#OXQ#OXR#OXS#OXT#OXU#OXW#OXX#OXY#OXZ#OX[#OX]#OX^#OX#Y#OX#g#OX!O#OX!R#OX!S#OX~OdoOfWOg_OhROmWOuWOvWOynO!TpO!VWO!|^O#PQO#WTO#XUO#_#OX~P&^OV!SO~P&^OP!}XQ!}XR!}XS!}XT!}XU!}XW!}XX!}XY!}XZ!}X[!}X]!}X^!}X~O#Y!yX#g!yX!O!yX!R!yX!S!yX~P(rOP!UOQ!UOR!VOS!VOT!XOU!YOW!WOX!WOY!WOZ!WO[!WO]!WO^!TO~O#Y!yX#g!yX!O!yX!R!yX!S!yX~OP!UOQ!UOR!VOS!VO~P*{OT!XOU!YO~P*{OdPOfWOg_OhROmWOuWOvWO!VWO!|^O#PQO#WTO#XUO~O!{!`O~O|!cO!Y!aO~P*{O|!dO~OdoOfWOg_OmWOuWOvWO!VWO!|^O#PQO#WTO#XUO~OV!SO_!jO`!jOa!jOb!jOc!jO~O#Y!kO#g!kO~OhRO!T!mO~P-UOhROynO!TpO|ka!Yka#Yka#gka#_ka!Oka!Rka!Ska~P-UOd!oO!|^O~O#P!pO#R!pO#S!pO#T!pO#U!pO#V!pO~OrvO#P!rO#RtO#SuO~OdzO|{X~O|!tO~O#^!wO~P%[OynO#Y!yO#^!{O~O#Y!|O#^!wO~P-UOehO!]cO!_eO!afO~P+xO#_#XO~P(rOP!UOQ!UOR!VOS!VO#_#XO~OT!XOU!YO#_#XO~O!Y!aO#_#XO~Od#YOm#YO!|^O~Od#ZOg_O!|^O~O!Y!aO#Yja#gja#_ja!Oja!Rja!Sja~OehO!]cO!_eO!afO#Y#`O~P+xOehO!]cO!_eO!afO#Y#bO~P+xO#Y!^a#g!^a!O!^a!R!^a!S!^a~P*QO#Y!^a#g!^a!O!^a!R!^a!S!^a~OP!UOQ!UOR!VOS!VO~P4vOT!XOU!YO~P4vOT!XOU!YOW!WOX!WOY!WOZ!WO[!WO]!WO~O|#cO~P5sOT!XOU!YO|#cO~OehO!]cO!_eO!afO#Y#fO~P+xOynO#Y!yO#^#hO~O#Y!|O#^#jO~P-UO^!TORpiSpi#Ypi#gpi#_pi!Opi!Rpi!Spi~OPpiQpi~P7kOP!UOQ!UO~P7kOP!UOQ!UORpiSpi#Ypi#gpi#_pi!Opi!Rpi!Spi~OW!WOX!WOY!WOZ!WO[!WO]!WOT!Wi#Y!Wi#g!Wi#_!Wi|!Wi!O!Wi!R!Wi!S!Wi~OU!YO~P9`OU!YO~P9rOU!Wi~P9`OhROynO!TpO~P-UO!O#mO!R#nO!S#oO~OehO!]cO!_eO!afO#Y#rO!O#[P!R#[P!S#[P~P+xO!O#mO!R#nO!S#vO~OehO!]cO!_eO!afO#Y#}O~P+xO!O#mO!R#nO!S$OO~OynO#Y!yO#^$SO~O#Y!|O#^$TO~P-UOd$UO~O|$VO~O!S$WO~O!R#nO!S$WO~O#Y$YO~OehO!]cO!_eO!afO#Y#rO!O#[X!R#[X!S#[X!e#[X!g#[X~P+xO!O#mO!R#nO!S$[O~O!S$_O~O!R#nO!S$_O~O!O#mO!R#nO!S$aO~O!S$dO~OehO!]cO!_eO!afO#Y#rO!S#[P!e#[P!g#[P~P+xO!S$gO~O!R#nO!S$gO~O!O#mO!R#nO!S$iO~O|$lO~OehO!]cO!_eO!afO#Y$mO~P+xO!S$oO~O!S$pO~O!R#nO!S$pO~O!S$rO~O!S$sO~O!R#nO!S$sO~O!S$yO!e$uO!g$xO~O!S${O~O!S$|O~O!R#nO!S$|O~OehO!]cO!_eO!afO#Y%OO~P+xOehO!]cO!_eO!afO#Y#rO!S#[P~P+xO!S%RO~O!S%SO~O!S%WO!e$uO!g$xO~O|%YO~O!S%WO~O!S%ZO~OehO!]cO!_eO!afO#Y#rO!R#[P!S#[P~P+xO|%]O~P5sOT!XOU!YO|%]O~O!S%^O~O#Y%_O~O#Y%`O~Omv~",
goto: "4k#dPPPPPPPPPPPPPPPPPPPPPPPPPP#e#{$bP%b#{&h'XP(S(SPP'X(WP(k)]P)`P)l)uPPP*_P+[,RP,YP,YP,YP,m,p,yP,}P,Y,Y-T-Z-a-g-m-y.T._.h.oPPPP.u.y/nPP0X1pP2oPPPPPPPP2s3_2sPP3l3s3s4W4WrhOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}R!]^w`O^l!R!`!b!h!r#^#_#b#p#u#}$_$`$n$|$}tPO^l!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}znPUVdemr}!Q!S!T!U!V!W!X!v!{#X#Y#e$eR#X!`tVO^l!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}zWPUVdemr}!Q!S!T!U!V!W!X!v!{#X#Y#e$eQ!msQ#W!_R#Y!`r[Ol!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}Q!Z^Q!ddQ!}!TR#Q!U!qWOPUV^delmr}!Q!R!S!T!U!V!W!X!b!h!r!v!{#X#Y#^#_#b#e#p#u#}$_$`$e$n$|$}TuQwYpPVr#X#YQ!OUQ!t}X!w!O!t!x#crhOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}YoPVr#X#YQ!]^R!kmR{RQ#m#]Q#x#aQ$U#rR$^#yQ#r#^Q$p$`R$y$nQ#l#]Q#w#aQ$P#mQ$T#rQ$Z#xQ$]#yQ$d$UR$m$^|WPUV^demr}!Q!S!T!U!V!W!X!v!{#X#Y#e$esXOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}r]Ol!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}Q![^Q!edQ!geQ#R!XQ#T!WR$s$eZpPVr#X#YshOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}R#t#_Q$X#uQ%O$|R%P$}T$f$X$gQ$j$XR$v$gQlOR!jlQwQR!owQ}UR!s}QzRR!qz^#p#^#b#u$`$n$|$}R$R#pQ!x!OQ#c!tT#g!x#cQ!{!QQ#e!vT#h!{#eWrPV#X#YR!lrS!aa!^R#[!aQ$g$XR$t$gTkOlSiOlQ!|!RQ#]!bQ#`!hQ#a!r`#o#^#b#p#u$`$n$|$}Q#s#_Q$a#}R$o$_raOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}Q!^^R#Z!`tZO^l!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}YoPVr#X#YQ!QUQ!cdQ!feQ!kmQ!v}W!z!Q!v!{#eQ!}!SQ#O!TQ#P!UQ#R!VQ#S!WQ#U!XR$r$erYOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}znPUVdemr}!Q!S!T!U!V!W!X!v!{#X#Y#e$eR!Y^TvQw!RSOPV^lmr!R!b!h!r#X#Y#^#_#b#p#u#}$_$`$n$|$}U#q#^$`$nQ#y#bV$W#u$|$}ZqPVr#X#YscOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}sfOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}", goto: "6a#gPPPPPPPPPPPPPPPPPPPPPPPPPP#h$Q$iP%k$Q&s'fP(c(cPP'f(gP(z)nP)qP*T*^PPP+SP,R,zP-R-RP-RP-RP-h-k-tP-xP-R-R.O.U.[.b.h.u/P/Z/d/kPPPP/q/u0nPP1Z2tP3uPPPPPPPP3y4g3yPP4w5O5O5e5e5z5zviOm!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`R!^^{`O^m!S!a!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`xPO^m!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`zoPUVefns!O!R!T!U!V!W!X!Y!x!}#Z#[#i$uR#Z!axVO^m!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`zWPUVefns!O!R!T!U!V!W!X!Y!x!}#Z#[#i$uQ!otQ#Y!`R#[!av[Om!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`Q![^Q!feQ#P!UR#S!V!uWOPUV^efmns!O!R!S!T!U!V!W!X!Y!c!d!j!t!x!}#Z#[#`#b#c#f#i#t#}$V$l$m$u%O%_%`TvQxYqPVs#Z#[Q!PUQ!v!OX!y!P!v!z#gviOm!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`YpPVs#Z#[Q!^^R!mnR|RQ#q#_Q#x#aQ$Q#eQ$^#uQ$c#zR$k$RQ#z#bQ%Q$mR%[%OQ#p#_Q#w#aQ$P#eQ$X#qQ$]#uQ$`#xQ$b#zQ$h$QQ$j$RQ$q$^Q$t$cR$}$k|WPUV^efns!O!R!T!U!V!W!X!Y!x!}#Z#[#i$uwXOm!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`v]Om!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`Q!]^Q!geQ!ifQ#T!YQ#V!XR%U$uZqPVs#Z#[wiOm!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`R#|#cQ$f#}Q%a%_R%b%`T$v$f$wQ$z$fR%X$wQmOR!lmQxQR!qxQ!OUR!u!OQ{RR!s{`#t#`#b#f#}$m%O%_%`R$Z#tQ!z!PQ#g!vT#k!z#gQ!}!RQ#i!xT#l!}#iWsPV#Z#[R!nsS!ba!_R#^!bQ$w$fR%V$wTlOmSjOmQ#O!SQ#_!cQ#a!dQ#d!jQ#e!tb#s#`#b#f#t#}$m%O%_%`Q#{#cQ$n$VR%P$lvaOm!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`Q!_^R#]!axZO^m!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`YpPVs#Z#[Q!RUQ!eeQ!hfQ!mnQ!x!OW!|!R!x!}#iQ#P!TQ#Q!UQ#R!VQ#T!WQ#U!XQ#W!YR%T$uvYOm!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`zoPUVefns!O!R!T!U!V!W!X!Y!x!}#Z#[#i$uR!Z^TwQx!VSOPV^mns!S!c!d!j!t#Z#[#`#b#c#f#t#}$V$l$m%O%_%`Q#u#`U#y#b$m%OQ$R#fV$e#}%_%`ZrPVs#Z#[wbOm!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`wdOm!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`wgOm!S!c!d!j!t#`#b#c#f#t#}$V$l$m%O%_%`",
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 colon CatchExpr keyword TryBlock FinallyExpr keyword keyword Underscore Array Null ConditionalOp PositionalArg operator TryExpr keyword Throw keyword IfExpr keyword SingleLineThenBlock ThenBlock ElseIfExpr keyword ElseExpr keyword CompoundAssign Assign", 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 colon CatchExpr keyword TryBlock FinallyExpr keyword keyword Underscore Array Null ConditionalOp PositionalArg operator FunctionCallWithBlock TryExpr keyword Throw keyword IfExpr keyword SingleLineThenBlock ThenBlock ElseIfExpr keyword ElseExpr keyword CompoundAssign Assign",
maxTerm: 112, maxTerm: 115,
context: trackScope, context: trackScope,
nodeProps: [ nodeProps: [
["closedBy", 44,"end"] ["closedBy", 44,"end"]
@ -19,9 +19,9 @@ export const parser = LRParser.deserialize({
propSources: [highlighting], propSources: [highlighting],
skippedNodes: [0], skippedNodes: [0],
repeatNodeCount: 10, repeatNodeCount: 10,
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!uYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UrS#XQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%uZrS!vYOY%nYZ#{Zt%ntu&huw%nwx&hx#O%n#O#P&h#P;'S%n;'S;=`'P<%lO%nY&mS!vYOY&hZ;'S&h;'S;=`&y<%lO&hY&|P;=`<%l&h^'SP;=`<%l%n~'[O#Q~~'aO#O~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|QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U6{W#WQrSOt#{uw#{x!_#{!_!`7e!`#O#{#P;'S#{;'S;=`$d<%lO#{U7jVrSOt#{uw#{x#O#{#P#Q8P#Q;'S#{;'S;=`$d<%lO#{U8WU#VQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~8oO#R~U8vU#]QrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9aUrS!TQOt#{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[#SWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^?u[#UWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^@r^#TWrSOt#{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!YQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~C_O#d~", 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!vYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UrS#YQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%uZrS!wYOY%nYZ#{Zt%ntu&huw%nwx&hx#O%n#O#P&h#P;'S%n;'S;=`'P<%lO%nY&mS!wYOY&hZ;'S&h;'S;=`&y<%lO&hY&|P;=`<%l&h^'SP;=`<%l%n~'[O#R~~'aO#P~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|QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U6{W#XQrSOt#{uw#{x!_#{!_!`7e!`#O#{#P;'S#{;'S;=`$d<%lO#{U7jVrSOt#{uw#{x#O#{#P#Q8P#Q;'S#{;'S;=`$d<%lO#{U8WU#WQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~8oO#S~U8vU#^QrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9aUrS!TQOt#{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[#TWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^?u[#VWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^@r^#UWrSOt#{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!YQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~C_O#g~",
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!z~~", 11)], tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!{~~", 11)],
topRules: {"Program":[0,25]}, 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}], 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: 1591 tokenPrec: 1677
}) })

View File

@ -0,0 +1,292 @@
import { expect, describe, test } from 'bun:test'
import '../shrimp.grammar' // Importing this so changes cause it to retest!
describe('single line function blocks', () => {
test('work with no args', () => {
expect(`trap: echo bye bye end`).toMatchTree(`
FunctionCallWithBlock
FunctionCallOrIdentifier
Identifier trap
colon :
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
test('work with one arg', () => {
expect(`trap EXIT: echo bye bye end`).toMatchTree(`
FunctionCallWithBlock
FunctionCall
Identifier trap
PositionalArg
Word EXIT
colon :
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
test('work with named args', () => {
expect(`attach signal='exit': echo bye bye end`).toMatchTree(`
FunctionCallWithBlock
FunctionCall
Identifier attach
NamedArg
NamedArgPrefix signal=
String
StringFragment exit
colon :
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
test('work with dot-get', () => {
expect(`signals = [=]; signals.trap 'EXIT': echo bye bye end`).toMatchTree(`
Assign
AssignableIdentifier signals
Eq =
Dict [=]
FunctionCallWithBlock
FunctionCall
DotGet
IdentifierBeforeDot signals
Identifier trap
PositionalArg
String
StringFragment EXIT
colon :
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
})
describe('multi line function blocks', () => {
test('work with no args', () => {
expect(`
trap:
echo bye bye
end
`).toMatchTree(`
FunctionCallWithBlock
FunctionCallOrIdentifier
Identifier trap
colon :
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
test('work with one arg', () => {
expect(`
trap EXIT:
echo bye bye
end`).toMatchTree(`
FunctionCallWithBlock
FunctionCall
Identifier trap
PositionalArg
Word EXIT
colon :
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
test('work with named args', () => {
expect(`
attach signal='exit' code=1:
echo bye bye
end`).toMatchTree(`
FunctionCallWithBlock
FunctionCall
Identifier attach
NamedArg
NamedArgPrefix signal=
String
StringFragment exit
NamedArg
NamedArgPrefix code=
Number 1
colon :
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
test('work with dot-get', () => {
expect(`
signals = [=]
signals.trap 'EXIT':
echo bye bye
end`).toMatchTree(`
Assign
AssignableIdentifier signals
Eq =
Dict [=]
FunctionCallWithBlock
FunctionCall
DotGet
IdentifierBeforeDot signals
Identifier trap
PositionalArg
String
StringFragment EXIT
colon :
FunctionCall
Identifier echo
PositionalArg
Identifier bye
PositionalArg
Identifier bye
keyword end`
)
})
})
describe('ribbit', () => {
test('head tag', () => {
expect(`
head:
title What up
meta charSet=UTF-8
meta name='viewport' content='width=device-width, initial-scale=1, viewport-fit=cover'
end`).toMatchTree(`
FunctionCallWithBlock
FunctionCallOrIdentifier
Identifier head
colon :
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
`)
})
test('li', () => {
expect(`
list:
li border-bottom='1px solid black' one
li two
li three
end`).toMatchTree(`
FunctionCallWithBlock
FunctionCallOrIdentifier
Identifier list
colon :
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`)
})
test('inline expressions', () => {
expect(`
p:
h1 class=bright style='font-family: helvetica' Heya
h2 man that is (b wild)!
end`)
.toMatchTree(`
FunctionCallWithBlock
FunctionCallOrIdentifier
Identifier p
colon :
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`)
})
})