Merge pull request 'Add comments to the tree' (#24) from comments-in-tree into main

Reviewed-on: #24
This commit is contained in:
probablycorey 2025-11-06 00:19:34 +00:00
commit 7229f4afd0
10 changed files with 156 additions and 93 deletions

View File

@ -75,6 +75,7 @@ export class Compiler {
if (DEBUG) { if (DEBUG) {
const bytecodeString = bytecodeToString(this.bytecode) const bytecodeString = bytecodeToString(this.bytecode)
console.log(`\n🤖 bytecode:\n----------------\n${bytecodeString}\n\n`) console.log(`\n🤖 bytecode:\n----------------\n${bytecodeString}\n\n`)
console.log(`\n🤖 bytecode:\n----------------\n${this.instructions}\n\n`)
} }
} catch (error) { } catch (error) {
if (error instanceof CompilerError) { if (error instanceof CompilerError) {
@ -281,13 +282,27 @@ export class Compiler {
const opValue = input.slice(operator.from, operator.to) const opValue = input.slice(operator.from, operator.to)
switch (opValue) { switch (opValue) {
case '+=': instructions.push(['ADD']); break case '+=':
case '-=': instructions.push(['SUB']); break instructions.push(['ADD'])
case '*=': instructions.push(['MUL']); break break
case '/=': instructions.push(['DIV']); break case '-=':
case '%=': instructions.push(['MOD']); break instructions.push(['SUB'])
break
case '*=':
instructions.push(['MUL'])
break
case '/=':
instructions.push(['DIV'])
break
case '%=':
instructions.push(['MOD'])
break
default: default:
throw new CompilerError(`Unknown compound operator: ${opValue}`, operator.from, operator.to) throw new CompilerError(
`Unknown compound operator: ${opValue}`,
operator.from,
operator.to
)
} }
// DUP and store (same as regular assignment) // DUP and store (same as regular assignment)
@ -305,10 +320,8 @@ export class Compiler {
} }
case terms.FunctionDef: { case terms.FunctionDef: {
const { paramNames, bodyNodes, catchVariable, catchBody, finallyBody } = getFunctionDefParts( const { paramNames, bodyNodes, catchVariable, catchBody, finallyBody } =
node, getFunctionDefParts(node, input)
input
)
const instructions: ProgramItem[] = [] const instructions: ProgramItem[] = []
const functionLabel: Label = `.func_${this.fnLabelCount++}` const functionLabel: Label = `.func_${this.fnLabelCount++}`
const afterLabel: Label = `.after_${functionLabel}` const afterLabel: Label = `.after_${functionLabel}`
@ -331,7 +344,13 @@ export class Compiler {
if (catchVariable || finallyBody) { if (catchVariable || finallyBody) {
// If function has catch or finally, wrap body in try/catch/finally // If function has catch or finally, wrap body in try/catch/finally
instructions.push( instructions.push(
...this.#compileTryCatchFinally(compileFunctionBody, catchVariable, catchBody, finallyBody, input) ...this.#compileTryCatchFinally(
compileFunctionBody,
catchVariable,
catchBody,
finallyBody,
input
)
) )
} else { } else {
instructions.push(...compileFunctionBody()) instructions.push(...compileFunctionBody())
@ -414,8 +433,9 @@ export class Compiler {
instructions.push(['JUMP', afterLabel]) instructions.push(['JUMP', afterLabel])
instructions.push([`${fnLabel}:`]) instructions.push([`${fnLabel}:`])
instructions.push( instructions.push(
...block.filter(x => x.type.name !== 'keyword') ...block
.map(x => this.#compileNode(x!, input)) .filter((x) => x.type.name !== 'keyword')
.map((x) => this.#compileNode(x!, input))
.flat() .flat()
) )
instructions.push(['RETURN']) instructions.push(['RETURN'])
@ -435,15 +455,16 @@ export class Compiler {
body = [ body = [
...body.slice(0, startSlice), ...body.slice(0, startSlice),
['MAKE_FUNCTION', [], fnLabel], ['MAKE_FUNCTION', [], fnLabel],
...body.slice(startSlice) ...body.slice(startSlice),
] ]
// @ts-ignore // @ts-ignore
body[body.length - 3]![1] += 1 body[body.length - 3]![1] += 1
instructions.push(...body) instructions.push(...body)
} else { } else {
throw new Error(`FunctionCallWithBlock: Expected FunctionCallOrIdentifier or FunctionCall`) throw new Error(
`FunctionCallWithBlock: Expected FunctionCallOrIdentifier or FunctionCall`
)
} }
return instructions return instructions
@ -642,7 +663,7 @@ export class Compiler {
// = can be a valid word, and is also valid inside words, so for now we cheat // = can be a valid word, and is also valid inside words, so for now we cheat
// and check for arrays that look like `[ = ]` to interpret them as // and check for arrays that look like `[ = ]` to interpret them as
// empty dicts // empty dicts
if (children.length === 1 && children[0]!.name === 'Word') { if (children.length === 1 && children[0]!.type.id === terms.Word) {
const child = children[0]! const child = children[0]!
if (input.slice(child.from, child.to) === '=') { if (input.slice(child.from, child.to) === '=') {
return [['MAKE_DICT', 0]] return [['MAKE_DICT', 0]]
@ -691,6 +712,10 @@ export class Compiler {
return instructions return instructions
} }
case terms.Comment: {
return [] // ignore comments
}
default: default:
throw new CompilerError( throw new CompilerError(
`Compiler doesn't know how to handle a "${node.type.name}" node.`, `Compiler doesn't know how to handle a "${node.type.name}" node.`,

View File

@ -304,9 +304,12 @@ describe('default params', () => {
}) })
test.skip('dict default', () => { test.skip('dict default', () => {
expect('make-person = do person=[name=Bob age=60]: person end; make-person') expect('make-person = do person=[name=Bob age=60]: person end; make-person').toEvaluateTo({
.toEvaluateTo({ name: 'Bob', age: 60 }) name: 'Bob',
expect('make-person = do person=[name=Bob age=60]: person end; make-person [name=Jon age=21]') age: 60,
.toEvaluateTo({ name: 'Jon', age: 21 }) })
expect(
'make-person = do person=[name=Bob age=60]: person end; make-person [name=Jon age=21]'
).toEvaluateTo({ name: 'Jon', age: 21 })
}) })
}) })

View File

@ -66,8 +66,8 @@ describe('array literals', () => {
}) })
test('comments within arrays', () => { test('comments within arrays', () => {
expect(`[1 # first expect(`[1
2 # second 2
]`).toEvaluateTo([1, 2]) ]`).toEvaluateTo([1, 2])
}) })

View File

@ -22,7 +22,8 @@ export const getAllChildren = (node: SyntaxNode): SyntaxNode[] => {
children.push(child) children.push(child)
child = child.nextSibling child = child.nextSibling
} }
return children
return children.filter((n) => n.type.id !== terms.Comment)
} }
export const getBinaryParts = (node: SyntaxNode) => { export const getBinaryParts = (node: SyntaxNode) => {
@ -50,13 +51,15 @@ export const getAssignmentParts = (node: SyntaxNode) => {
// array destructuring // array destructuring
if (left && left.type.id === terms.Array) { if (left && left.type.id === terms.Array) {
const identifiers = getAllChildren(left).filter(child => child.type.id === terms.Identifier) const identifiers = getAllChildren(left).filter((child) => child.type.id === terms.Identifier)
return { arrayPattern: identifiers, right } return { arrayPattern: identifiers, right }
} }
if (!left || left.type.id !== terms.AssignableIdentifier) { if (!left || left.type.id !== terms.AssignableIdentifier) {
throw new CompilerError( throw new CompilerError(
`Assign left child must be an AssignableIdentifier or Array, got ${left ? left.type.name : 'none'}`, `Assign left child must be an AssignableIdentifier or Array, got ${
left ? left.type.name : 'none'
}`,
node.from, node.from,
node.to node.to
) )
@ -71,7 +74,9 @@ export const getCompoundAssignmentParts = (node: SyntaxNode) => {
if (!left || left.type.id !== terms.AssignableIdentifier) { if (!left || left.type.id !== terms.AssignableIdentifier) {
throw new CompilerError( throw new CompilerError(
`CompoundAssign left child must be an AssignableIdentifier, got ${left ? left.type.name : 'none'}`, `CompoundAssign left child must be an AssignableIdentifier, got ${
left ? left.type.name : 'none'
}`,
node.from, node.from,
node.to node.to
) )

View File

@ -2,7 +2,7 @@
@context trackScope from "./scopeTracker" @context trackScope from "./scopeTracker"
@skip { space | comment } @skip { space | Comment }
@top Program { item* } @top Program { item* }
@ -18,7 +18,7 @@
newlineOrSemicolon { "\n" | ";" } newlineOrSemicolon { "\n" | ";" }
eof { @eof } eof { @eof }
space { " " | "\t" } space { " " | "\t" }
comment { "#" ![\n]* } Comment { "#" " " ![\n]* }
leftParen { "(" } leftParen { "(" }
rightParen { ")" } rightParen { ")" }
colon[closedBy="end", @name="colon"] { ":" } colon[closedBy="end", @name="colon"] { ":" }

View File

@ -24,42 +24,43 @@ export const
Word = 22, Word = 22,
IdentifierBeforeDot = 23, IdentifierBeforeDot = 23,
Do = 24, Do = 24,
Program = 25, Comment = 25,
PipeExpr = 26, Program = 26,
FunctionCall = 27, PipeExpr = 27,
DotGet = 28, FunctionCall = 28,
Number = 29, DotGet = 29,
ParenExpr = 30, Number = 30,
IfExpr = 31, ParenExpr = 31,
keyword = 69, IfExpr = 32,
ConditionalOp = 33, keyword = 70,
String = 34, ConditionalOp = 34,
StringFragment = 35, String = 35,
Interpolation = 36, StringFragment = 36,
EscapeSeq = 37, Interpolation = 37,
Boolean = 38, EscapeSeq = 38,
Regex = 39, Boolean = 39,
Dict = 40, Regex = 40,
NamedArg = 41, Dict = 41,
NamedArgPrefix = 42, NamedArg = 42,
FunctionDef = 43, NamedArgPrefix = 43,
Params = 44, FunctionDef = 44,
NamedParam = 45, Params = 45,
Null = 46, NamedParam = 46,
colon = 47, Null = 47,
CatchExpr = 48, colon = 48,
Block = 50, CatchExpr = 49,
FinallyExpr = 51, Block = 51,
Underscore = 54, FinallyExpr = 52,
Array = 55, Underscore = 55,
ElseIfExpr = 56, Array = 56,
ElseExpr = 58, ElseIfExpr = 57,
FunctionCallOrIdentifier = 59, ElseExpr = 59,
BinOp = 60, FunctionCallOrIdentifier = 60,
PositionalArg = 61, BinOp = 61,
WhileExpr = 63, PositionalArg = 62,
FunctionCallWithBlock = 65, WhileExpr = 64,
TryExpr = 66, FunctionCallWithBlock = 66,
Throw = 68, TryExpr = 67,
CompoundAssign = 70, Throw = 69,
Assign = 71 CompoundAssign = 71,
Assign = 72

View File

@ -4,24 +4,24 @@ 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,if:64, null:92, catch:98, finally:104, end:106, else:114, while:128, try:134, throw:138} const spec_Identifier = {__proto__:null,if:66, null:94, catch:100, finally:106, end:108, else:116, while:130, try:136, throw:140}
export const parser = LRParser.deserialize({ export const parser = LRParser.deserialize({
version: 14, version: 14,
states: "9[QYQbOOO!dOSO'#DOOOQa'#DU'#DUO#mQbO'#DeO%RQcO'#E^OOQa'#E^'#E^O&XQcO'#E^O'ZQcO'#E]O'qQcO'#E]O)^QRO'#C}O*mQcO'#EWO*wQcO'#EWO+XQbO'#CzO,SOpO'#CxOOQ`'#EX'#EXO,XQbO'#EWO,cQRO'#DtOOQ`'#EW'#EWO,wQQO'#EVOOQ`'#EV'#EVOOQ`'#Dv'#DvQYQbOOO-PQbO'#DXO-[QbO'#C{O.PQbO'#DmO.tQQO'#DpO.PQbO'#DrO.yQbO'#DQO/RQWO'#DROOOO'#E`'#E`OOOO'#Dw'#DwO/gOSO,59jOOQa,59j,59jOOQ`'#Dx'#DxO/uQbO,5:PO/|QbO'#DVO0WQQO,59pOOQa,5:P,5:PO0cQbO,5:POOQa'#E]'#E]OOQ`'#Dk'#DkOOQ`'#El'#ElOOQ`'#EP'#EPO0mQbO,59cO1gQbO,5:aO.PQbO,59iO.PQbO,59iO.PQbO,59iO.PQbO,5:UO.PQbO,5:UO.PQbO,5:UO1wQRO,59fO2OQRO,59fO2ZQRO,59fO2UQQO,59fO2lQQO,59fO2tObO,59dO3PQbO'#EQO3[QbO,59bO3vQbO,5:ZO1gQbO,5:`OOQ`,5:q,5:qOOQ`-E7t-E7tOOQ`'#Dy'#DyO4ZQbO'#DYO4fQbO'#DZOOQO'#Dz'#DzO4^QQO'#DYO4tQQO,59sO4yQcO'#E]O6_QRO'#E[O6fQRO'#E[OOQO'#E['#E[O6qQQO,59gO6vQRO,5:XO6}QRO,5:XO3vQbO,5:[O7YQcO,5:^O8UQcO,5:^O8`QcO,5:^OOOO,59l,59lOOOO,59m,59mOOOO-E7u-E7uOOQa1G/U1G/UOOQ`-E7v-E7vO8pQQO1G/[OOQa1G/k1G/kO8{QbO1G/kOOQ`,59q,59qOOQO'#D|'#D|O8pQQO1G/[OOQa1G/[1G/[OOQ`'#D}'#D}O8{QbO1G/kOOQ`-E7}-E7}OOQ`1G/{1G/{OOQa1G/T1G/TO:WQcO1G/TO:_QcO1G/TO:fQcO1G/TOOQa1G/p1G/pO;_QcO1G/pO;iQcO1G/pO;sQcO1G/pOOQa1G/Q1G/QOOQa1G/O1G/OO<hQbO'#DiO=_QbO'#CwOOQ`,5:l,5:lOOQ`-E8O-E8OOOQ`'#D`'#D`O=lQbO'#D`O>]QbO1G/uOOQ`1G/z1G/zOOQ`-E7w-E7wO>hQQO,59tOOQO,59u,59uOOQO-E7x-E7xO>pQbO1G/_O3vQbO1G/RO3vQbO1G/sO?TQbO1G/vO?`QQO7+$vOOQa7+$v7+$vO?kQbO7+%VOOQa7+%V7+%VOOQO-E7z-E7zOOQ`-E7{-E7{OOQ`'#D{'#D{O?uQQO'#D{O?zQbO'#EiOOQ`,59z,59zO@kQbO'#D^O@pQQO'#DaOOQ`7+%a7+%aO@uQbO7+%aO@zQbO7+%aOASQbO7+$yOA_QbO7+$yOA{QbO7+$mOBTQbO7+%_OOQ`7+%b7+%bOBYQbO7+%bOB_QbO7+%bOOQa<<Hb<<HbOOQa<<Hq<<HqOOQ`,5:g,5:gOOQ`-E7y-E7yOBgQQO,59xO3vQbO,59{OOQ`<<H{<<H{OBlQbO<<H{OOQ`<<He<<HeOBqQbO<<HeOBvQbO<<HeOCOQbO<<HeOOQ`'#EO'#EOOCZQbO<<HXOCcQbO'#DhOOQ`<<HX<<HXOCkQbO<<HXOOQ`<<Hy<<HyOOQ`<<H|<<H|OCpQbO<<H|O3vQbO1G/dOOQ`1G/g1G/gOOQ`AN>gAN>gOOQ`AN>PAN>POCuQbOAN>POCzQbOAN>POOQ`-E7|-E7|OOQ`AN=sAN=sODSQbOAN=sO-[QbO,5:QO3vQbO,5:SOOQ`AN>hAN>hOOQ`7+%O7+%OOOQ`G23kG23kODXQbOG23kPD^QbO'#DfOOQ`G23_G23_ODcQQO1G/lOOQ`1G/n1G/nOOQ`LD)VLD)VO3vQbO7+%WOOQ`<<Hr<<Hr", states: "9[QYQbOOO!dOSO'#DPOOQa'#DV'#DVO#mQbO'#DfO%RQcO'#E^OOQa'#E^'#E^O&XQcO'#E^O'ZQcO'#E]O'qQcO'#E]O)^QRO'#DOO*mQcO'#EWO*wQcO'#EWO+XQbO'#C{O,SOpO'#CyOOQ`'#EX'#EXO,XQbO'#EWO,cQRO'#DuOOQ`'#EW'#EWO,wQQO'#EVOOQ`'#EV'#EVOOQ`'#Dw'#DwQYQbOOO-PQbO'#DYO-[QbO'#C|O.PQbO'#DnO.tQQO'#DqO.PQbO'#DsO.yQbO'#DRO/RQWO'#DSOOOO'#E`'#E`OOOO'#Dx'#DxO/gOSO,59kOOQa,59k,59kOOQ`'#Dy'#DyO/uQbO,5:QO/|QbO'#DWO0WQQO,59qOOQa,5:Q,5:QO0cQbO,5:QOOQa'#E]'#E]OOQ`'#Dl'#DlOOQ`'#El'#ElOOQ`'#EQ'#EQO0mQbO,59dO1gQbO,5:bO.PQbO,59jO.PQbO,59jO.PQbO,59jO.PQbO,5:VO.PQbO,5:VO.PQbO,5:VO1wQRO,59gO2OQRO,59gO2ZQRO,59gO2UQQO,59gO2lQQO,59gO2tObO,59eO3PQbO'#ERO3[QbO,59cO3vQbO,5:[O1gQbO,5:aOOQ`,5:q,5:qOOQ`-E7u-E7uOOQ`'#Dz'#DzO4ZQbO'#DZO4fQbO'#D[OOQO'#D{'#D{O4^QQO'#DZO4tQQO,59tO4yQcO'#E]O6_QRO'#E[O6fQRO'#E[OOQO'#E['#E[O6qQQO,59hO6vQRO,5:YO6}QRO,5:YO3vQbO,5:]O7YQcO,5:_O8UQcO,5:_O8`QcO,5:_OOOO,59m,59mOOOO,59n,59nOOOO-E7v-E7vOOQa1G/V1G/VOOQ`-E7w-E7wO8pQQO1G/]OOQa1G/l1G/lO8{QbO1G/lOOQ`,59r,59rOOQO'#D}'#D}O8pQQO1G/]OOQa1G/]1G/]OOQ`'#EO'#EOO8{QbO1G/lOOQ`-E8O-E8OOOQ`1G/|1G/|OOQa1G/U1G/UO:WQcO1G/UO:_QcO1G/UO:fQcO1G/UOOQa1G/q1G/qO;_QcO1G/qO;iQcO1G/qO;sQcO1G/qOOQa1G/R1G/ROOQa1G/P1G/PO<hQbO'#DjO=_QbO'#CxOOQ`,5:m,5:mOOQ`-E8P-E8POOQ`'#Da'#DaO=lQbO'#DaO>]QbO1G/vOOQ`1G/{1G/{OOQ`-E7x-E7xO>hQQO,59uOOQO,59v,59vOOQO-E7y-E7yO>pQbO1G/`O3vQbO1G/SO3vQbO1G/tO?TQbO1G/wO?`QQO7+$wOOQa7+$w7+$wO?kQbO7+%WOOQa7+%W7+%WOOQO-E7{-E7{OOQ`-E7|-E7|OOQ`'#D|'#D|O?uQQO'#D|O?zQbO'#EiOOQ`,59{,59{O@kQbO'#D_O@pQQO'#DbOOQ`7+%b7+%bO@uQbO7+%bO@zQbO7+%bOASQbO7+$zOA_QbO7+$zOA{QbO7+$nOBTQbO7+%`OOQ`7+%c7+%cOBYQbO7+%cOB_QbO7+%cOOQa<<Hc<<HcOOQa<<Hr<<HrOOQ`,5:h,5:hOOQ`-E7z-E7zOBgQQO,59yO3vQbO,59|OOQ`<<H|<<H|OBlQbO<<H|OOQ`<<Hf<<HfOBqQbO<<HfOBvQbO<<HfOCOQbO<<HfOOQ`'#EP'#EPOCZQbO<<HYOCcQbO'#DiOOQ`<<HY<<HYOCkQbO<<HYOOQ`<<Hz<<HzOOQ`<<H}<<H}OCpQbO<<H}O3vQbO1G/eOOQ`1G/h1G/hOOQ`AN>hAN>hOOQ`AN>QAN>QOCuQbOAN>QOCzQbOAN>QOOQ`-E7}-E7}OOQ`AN=tAN=tODSQbOAN=tO-[QbO,5:RO3vQbO,5:TOOQ`AN>iAN>iOOQ`7+%P7+%POOQ`G23lG23lODXQbOG23lPD^QbO'#DgOOQ`G23`G23`ODcQQO1G/mOOQ`1G/o1G/oOOQ`LD)WLD)WO3vQbO7+%XOOQ`<<Hs<<Hs",
stateData: "Dk~O!wOS!xOS~OdWOe`OfTOg]OhfOmTOpgOvTOwTO!OTO!bhO!eiO!gjO!}[O#RPO#YQO#ZRO#[cO~OsmO#RpO#TkO#UlO~OdwOfTOg]OmTOvTOwTOzsO!OTO!}[O#RPO#YQO#ZRO#[qO~O#^uO~P!rOP#QXQ#QXR#QXS#QXT#QXU#QXW#QXX#QXY#QXZ#QX[#QX]#QX^#QX#[#QX#a#QX!R#QX!U#QX!V#QX!Z#QX~OdwOfTOg]OhfOmTOvTOwTOzsO!OTO!WxO!}[O#RPO#YQO#ZRO#_#QX!P#QX~P#tOV|O~P#tOP#PXQ#PXR#PXS#PXT#PXU#PXW#PXX#PXY#PXZ#PX[#PX]#PX^#PX~O#[!zX#a!zX!R!zX!U!zX!V!zX!Z!zX~P&`OdwOfTOg]OhfOmTOvTOwTOzsO!OTO!WxO!}[O#RPO#YQO#ZRO!P!]X!`!]X#[!]X#a!]X#_!]X!R!]X!U!]X!V!]X!Z!]X~P&`OP!ROQ!ROR!SOS!SOT!OOU!POW}OX}OY}OZ}O[}O]}O^!QO~O#[!zX#a!zX!R!zX!U!zX!V!zX!Z!zX~OT!OOU!PO~P*XOP!ROQ!ROR!SOS!SO~P*XOdWOfTOg]OhfOmTOpgOvTOwTO!OTO!}[O#RPO#YQO#ZRO~O!|!YO~O!P!]O!`!ZO~P*XOV|O_!^O`!^Oa!^Ob!^Oc!^O~O#[!_O#a!_O~Od!aOz!cO!P|P~Od!gOfTOg]OmTOvTOwTO!OTO!}[O#RPO#YQO#ZRO~OdwOfTOg]OmTOvTOwTO!OTO!}[O#RPO#YQO#ZRO~O!P!nO~Od!rO!}[O~O#R!sO#T!sO#U!sO#V!sO#W!sO#X!sO~OsmO#R!uO#TkO#UlO~O#^!xO~P!rOhfO!W!zO~P.POzsO#[!{O#^!}O~O#[#OO#^!xO~P.POhfOzsO!WxO!Pka!`ka#[ka#aka#_ka!Rka!Uka!Vka!Zka~P.POe`O!bhO!eiO!gjO~P+XO#_#[O~P&`OT!OOU!PO#_#[O~OP!ROQ!ROR!SOS!SO#_#[O~O!`!ZO#_#[O~Od#]Om#]O!}[O~Od#^Og]O!}[O~O!`!ZO#[ja#aja#_ja!Rja!Uja!Vja!Zja~Oe`O!bhO!eiO!gjO#[#cO~P+XOd!aOz!cO!P|X~Om#hOv#hO!O#hO#RPO~O!P#jO~OhfOzsO!WxOT#PXU#PXW#PXX#PXY#PXZ#PX[#PX]#PX!P#PX~P.POT!OOU!POW}OX}OY}OZ}O[}O]}O~O!P#OX~P5sOT!OOU!PO!P#OX~O!P#kO~O!P#lO~P5sOT!OOU!PO!P#lO~O#[!fa#a!fa!R!fa!U!fa!V!fa!Z!fa~P)^O#[!fa#a!fa!R!fa!U!fa!V!fa!Z!fa~OT!OOU!PO~P7pOP!ROQ!ROR!SOS!SO~P7pOzsO#[!{O#^#oO~O#[#OO#^#qO~P.POW}OX}OY}OZ}O[}O]}OTqi#[qi#aqi#_qi!Pqi!Rqi!Uqi!Vqi!Zqi~OU!PO~P9VOU!PO~P9iOUqi~P9VO^!QOR!^iS!^i#[!^i#a!^i#_!^i!R!^i!U!^i!V!^i!Z!^i~OP!^iQ!^i~P:mOP!ROQ!RO~P:mOP!ROQ!ROR!^iS!^i#[!^i#a!^i#_!^i!R!^i!U!^i!V!^i!Z!^i~OhfOzsO!WxO!`!]X#[!]X#a!]X#_!]X!R!]X!U!]X!V!]X!Z!]X~P.POhfOzsO!WxO~P.POe`O!bhO!eiO!gjO#[#tO!R#]P!U#]P!V#]P!Z#]P~P+XO!R#xO!U#yO!V#zO~Oz!cO!P|a~Oe`O!bhO!eiO!gjO#[$OO~P+XO!R#xO!U#yO!V$RO~OzsO#[!{O#^$UO~O#[#OO#^$VO~P.PO#[$WO~Oe`O!bhO!eiO!gjO#[#tO!R#]X!U#]X!V#]X!Z#]X~P+XOd$YO~O!P$ZO~O!V$[O~O!U#yO!V$[O~O!R#xO!U#yO!V$^O~Oe`O!bhO!eiO!gjO#[#tO!R#]P!U#]P!V#]P~P+XO!V$eO!Z$dO~O!V$gO~O!V$hO~O!U#yO!V$hO~O!P$jO~O!V$lO~O!V$mO~O!U#yO!V$mO~O!R#xO!U#yO!V$mO~O!V$qO!Z$dO~Op$sO!P$tO~O!V$qO~O!V$uO~O!V$wO~O!U#yO!V$wO~O!V$zO~O!V$}O~Op$sO~O!P%OO~Omw~", stateData: "Dk~O!xOSiOS~OdWOe`OfTOg]OhfOnTOqgOwTOxTO!PTO!chO!fiO!hjO!}[O#RPO#YQO#ZRO#[cO~OtmO#RpO#TkO#UlO~OdwOfTOg]OnTOwTOxTO{sO!PTO!}[O#RPO#YQO#ZRO#[qO~O#^uO~P!rOP#QXQ#QXR#QXS#QXT#QXU#QXW#QXX#QXY#QXZ#QX[#QX]#QX^#QX#[#QX#a#QX!S#QX!V#QX!W#QX![#QX~OdwOfTOg]OhfOnTOwTOxTO{sO!PTO!XxO!}[O#RPO#YQO#ZRO#_#QX!Q#QX~P#tOV|O~P#tOP#PXQ#PXR#PXS#PXT#PXU#PXW#PXX#PXY#PXZ#PX[#PX]#PX^#PX~O#[!zX#a!zX!S!zX!V!zX!W!zX![!zX~P&`OdwOfTOg]OhfOnTOwTOxTO{sO!PTO!XxO!}[O#RPO#YQO#ZRO!Q!^X!a!^X#[!^X#a!^X#_!^X!S!^X!V!^X!W!^X![!^X~P&`OP!ROQ!ROR!SOS!SOT!OOU!POW}OX}OY}OZ}O[}O]}O^!QO~O#[!zX#a!zX!S!zX!V!zX!W!zX![!zX~OT!OOU!PO~P*XOP!ROQ!ROR!SOS!SO~P*XOdWOfTOg]OhfOnTOqgOwTOxTO!PTO!}[O#RPO#YQO#ZRO~O!|!YO~O!Q!]O!a!ZO~P*XOV|O_!^O`!^Oa!^Ob!^Oc!^O~O#[!_O#a!_O~Od!aO{!cO!Q}P~Od!gOfTOg]OnTOwTOxTO!PTO!}[O#RPO#YQO#ZRO~OdwOfTOg]OnTOwTOxTO!PTO!}[O#RPO#YQO#ZRO~O!Q!nO~Od!rO!}[O~O#R!sO#T!sO#U!sO#V!sO#W!sO#X!sO~OtmO#R!uO#TkO#UlO~O#^!xO~P!rOhfO!X!zO~P.PO{sO#[!{O#^!}O~O#[#OO#^!xO~P.POhfO{sO!XxO!Qla!ala#[la#ala#_la!Sla!Vla!Wla![la~P.POe`O!chO!fiO!hjO~P+XO#_#[O~P&`OT!OOU!PO#_#[O~OP!ROQ!ROR!SOS!SO#_#[O~O!a!ZO#_#[O~Od#]On#]O!}[O~Od#^Og]O!}[O~O!a!ZO#[ka#aka#_ka!Ska!Vka!Wka![ka~Oe`O!chO!fiO!hjO#[#cO~P+XOd!aO{!cO!Q}X~On#hOw#hO!P#hO#RPO~O!Q#jO~OhfO{sO!XxOT#PXU#PXW#PXX#PXY#PXZ#PX[#PX]#PX!Q#PX~P.POT!OOU!POW}OX}OY}OZ}O[}O]}O~O!Q#OX~P5sOT!OOU!PO!Q#OX~O!Q#kO~O!Q#lO~P5sOT!OOU!PO!Q#lO~O#[!ga#a!ga!S!ga!V!ga!W!ga![!ga~P)^O#[!ga#a!ga!S!ga!V!ga!W!ga![!ga~OT!OOU!PO~P7pOP!ROQ!ROR!SOS!SO~P7pO{sO#[!{O#^#oO~O#[#OO#^#qO~P.POW}OX}OY}OZ}O[}O]}OTri#[ri#ari#_ri!Qri!Sri!Vri!Wri![ri~OU!PO~P9VOU!PO~P9iOUri~P9VO^!QOR!_iS!_i#[!_i#a!_i#_!_i!S!_i!V!_i!W!_i![!_i~OP!_iQ!_i~P:mOP!ROQ!RO~P:mOP!ROQ!ROR!_iS!_i#[!_i#a!_i#_!_i!S!_i!V!_i!W!_i![!_i~OhfO{sO!XxO!a!^X#[!^X#a!^X#_!^X!S!^X!V!^X!W!^X![!^X~P.POhfO{sO!XxO~P.POe`O!chO!fiO!hjO#[#tO!S#]P!V#]P!W#]P![#]P~P+XO!S#xO!V#yO!W#zO~O{!cO!Q}a~Oe`O!chO!fiO!hjO#[$OO~P+XO!S#xO!V#yO!W$RO~O{sO#[!{O#^$UO~O#[#OO#^$VO~P.PO#[$WO~Oe`O!chO!fiO!hjO#[#tO!S#]X!V#]X!W#]X![#]X~P+XOd$YO~O!Q$ZO~O!W$[O~O!V#yO!W$[O~O!S#xO!V#yO!W$^O~Oe`O!chO!fiO!hjO#[#tO!S#]P!V#]P!W#]P~P+XO!W$eO![$dO~O!W$gO~O!W$hO~O!V#yO!W$hO~O!Q$jO~O!W$lO~O!W$mO~O!V#yO!W$mO~O!S#xO!V#yO!W$mO~O!W$qO![$dO~Oq$sO!Q$tO~O!W$qO~O!W$uO~O!W$wO~O!V#yO!W$wO~O!W$zO~O!W$}O~Oq$sO~O!Q%OO~Onx~",
goto: "4x#aPPPPPPPPPPPPPPPPPPPPPPPPPP#b#w$aP%d#bP&k'bP(a(aPP(e)aP)u*g*jPP*pP*|+fPPP+|,zP-O-U-j.YP.bP.b.bP.bP.b.b.t.z/Q/W/^/h/o/y0T0Z0ePPPP0l0p1^PP1v1|3fP4fPPPPPPPP4jPP4ppaOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OR!W[t^O[e|!Z!]!^!n#c#j#k#l#v$O$Z$j$t%OT!jg$srWO[e|!]!^!n#c#j#k#l#v$O$Z$j$t%OzwRSWhjrsv{}!O!P!Q!R!S!g!y#P#^#_#pS!gg$sR#^!ZvSO[eg|!]!^!n#c#j#k#l#v$O$Z$j$s$t%OzTRSWhjrsv{}!O!P!Q!R!S!g!y#P#^#_#pQ!rkQ#]!YR#_!ZpYOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQ!U[S!ig$sQ!mhQ!pjQ#S!PR#U!O!rTORSW[eghjrsv{|}!O!P!Q!R!S!]!^!g!n!y#P#^#_#c#j#k#l#p#v$O$Z$j$s$t%OR#h!cTmPo!sTORSW[eghjrsv{|}!O!P!Q!R!S!]!^!g!n!y#P#^#_#c#j#k#l#p#v$O$Z$j$s$t%OQtR[ySW{!g#^#_Q!wrX!{t!w!|#npaOe|!]!^!n#c#j#k#l#v$O$Z$j$t%O[xSW{!g#^#_Q!W[R!zsR!ffX!df!b!e#gQ#|#dQ$T#mQ$`#}R$o$aQ#d!]Q#m!nQ$P#kQ$Q#lQ$k$ZQ$v$jQ$|$tR%P%OQ#{#dQ$S#mQ$]#|Q$_#}Q$i$TS$n$`$aR$x$o!QTRSW[ghjrsv{}!O!P!Q!R!S!g!y#P#^#_#p$sqUOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OT$b$P$cQ$f$PR$r$cu^O[e|!Z!]!^!n#c#j#k#l#v$O$Z$j$t%OpZOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQ!V[Q!qjQ#W!RR#Z!S]ySW{!g#^#_qaOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQeOR!`eQoPR!toQrRR!vrQ!bfR#f!bQ!efQ#g!bT#i!e#gS#v#c$OR$X#vQ!|tQ#n!wT#r!|#nQ#PvQ#p!yT#s#P#pQ$c$PR$p$cY{SW!g#^#_R#Q{S![_!XR#a![TdOeSbOeQ#R|`#b!]!n#k#l$Z$j$t%OQ#e!^U#u#c#v$OR#}#jp_Oe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQ!X[R#`!ZQ!kgR${$srXO[e|!]!^!n#c#j#k#l#v$O$Z$j$t%OQvR[xSW{!g#^#_S!hg$sQ!lhQ!ojQ!yrQ!zsW#Ov!y#P#pQ#S}Q#T!OQ#V!PQ#W!QQ#X!RR#Y!SpVOe|!]!^!n#c#j#k#l#v$O$Z$j$t%O!OwRSWghjrsv{}!O!P!Q!R!S!g!y#P#^#_#p$sR!T[TnPoQ#w#cR$a$O]zSW{!g#^#_", goto: "4x#aPPPPPPPPPPPPPPPPPPPPPPPPPPP#b#w$aP%d#bP&k'bP(a(aPP(e)aP)u*g*jPP*pP*|+fPPP+|,zP-O-U-j.YP.bP.b.bP.bP.b.b.t.z/Q/W/^/h/o/y0T0Z0ePPP0l0p1^PP1v1|3fP4fPPPPPPPP4jPP4ppaOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OR!W[t^O[e|!Z!]!^!n#c#j#k#l#v$O$Z$j$t%OT!jg$srWO[e|!]!^!n#c#j#k#l#v$O$Z$j$t%OzwRSWhjrsv{}!O!P!Q!R!S!g!y#P#^#_#pS!gg$sR#^!ZvSO[eg|!]!^!n#c#j#k#l#v$O$Z$j$s$t%OzTRSWhjrsv{}!O!P!Q!R!S!g!y#P#^#_#pQ!rkQ#]!YR#_!ZpYOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQ!U[S!ig$sQ!mhQ!pjQ#S!PR#U!O!rTORSW[eghjrsv{|}!O!P!Q!R!S!]!^!g!n!y#P#^#_#c#j#k#l#p#v$O$Z$j$s$t%OR#h!cTmPo!sTORSW[eghjrsv{|}!O!P!Q!R!S!]!^!g!n!y#P#^#_#c#j#k#l#p#v$O$Z$j$s$t%OQtR[ySW{!g#^#_Q!wrX!{t!w!|#npaOe|!]!^!n#c#j#k#l#v$O$Z$j$t%O[xSW{!g#^#_Q!W[R!zsR!ffX!df!b!e#gQ#|#dQ$T#mQ$`#}R$o$aQ#d!]Q#m!nQ$P#kQ$Q#lQ$k$ZQ$v$jQ$|$tR%P%OQ#{#dQ$S#mQ$]#|Q$_#}Q$i$TS$n$`$aR$x$o!QTRSW[ghjrsv{}!O!P!Q!R!S!g!y#P#^#_#p$sqUOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OT$b$P$cQ$f$PR$r$cu^O[e|!Z!]!^!n#c#j#k#l#v$O$Z$j$t%OpZOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQ!V[Q!qjQ#W!RR#Z!S]ySW{!g#^#_qaOe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQeOR!`eQoPR!toQrRR!vrQ!bfR#f!bQ!efQ#g!bT#i!e#gS#v#c$OR$X#vQ!|tQ#n!wT#r!|#nQ#PvQ#p!yT#s#P#pQ$c$PR$p$cY{SW!g#^#_R#Q{S![_!XR#a![TdOeSbOeQ#R|`#b!]!n#k#l$Z$j$t%OQ#e!^U#u#c#v$OR#}#jp_Oe|!]!^!n#c#j#k#l#v$O$Z$j$t%OQ!X[R#`!ZQ!kgR${$srXO[e|!]!^!n#c#j#k#l#v$O$Z$j$t%OQvR[xSW{!g#^#_S!hg$sQ!lhQ!ojQ!yrQ!zsW#Ov!y#P#pQ#S}Q#T!OQ#V!PQ#W!QQ#X!RR#Y!SpVOe|!]!^!n#c#j#k#l#v$O$Z$j$t%O!OwRSWghjrsv{}!O!P!Q!R!S!g!y#P#^#_#p$sR!T[TnPoQ#w#cR$a$O]zSW{!g#^#_",
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 IfExpr keyword ConditionalOp String StringFragment Interpolation EscapeSeq Boolean Regex Dict NamedArg NamedArgPrefix FunctionDef Params NamedParam Null colon CatchExpr keyword Block FinallyExpr keyword keyword Underscore Array ElseIfExpr keyword ElseExpr FunctionCallOrIdentifier BinOp PositionalArg operator WhileExpr keyword FunctionCallWithBlock TryExpr keyword Throw 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 Comment Program PipeExpr FunctionCall DotGet Number ParenExpr IfExpr keyword ConditionalOp String StringFragment Interpolation EscapeSeq Boolean Regex Dict NamedArg NamedArgPrefix FunctionDef Params NamedParam Null colon CatchExpr keyword Block FinallyExpr keyword keyword Underscore Array ElseIfExpr keyword ElseExpr FunctionCallOrIdentifier BinOp PositionalArg operator WhileExpr keyword FunctionCallWithBlock TryExpr keyword Throw keyword CompoundAssign Assign",
maxTerm: 109, maxTerm: 109,
context: trackScope, context: trackScope,
nodeProps: [ nodeProps: [
["closedBy", 47,"end"] ["closedBy", 48,"end"]
], ],
propSources: [highlighting], propSources: [highlighting],
skippedNodes: [0], skippedNodes: [0,25],
repeatNodeCount: 11, 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$QUsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{S$gP;=`<%l#{^$qUsS!wYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UsS#[QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%uZsS!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#T~~'aO#R~U'hUsS!}QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(RUsS#_QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(jWsSOt#{uw#{x!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U)ZYsSmQOt#{uw#{x!O#{!O!P)y!P!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U*OWsSOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U*oWsSmQOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U+^^sSOt#{uw#{x}#{}!O,Y!O!Q#{!Q![)S![!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{U,_[sSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{U-[UzQsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U-sWsSOt#{uw#{x!P#{!P!Q.]!Q#O#{#P;'S#{;'S;=`$d<%lO#{U.b^sSOY/^YZ#{Zt/^tu0auw/^wx0ax!P/^!P!Q#{!Q!}/^!}#O5S#O#P2o#P;'S/^;'S;=`6T<%lO/^U/e^sSwQOY/^YZ#{Zt/^tu0auw/^wx0ax!P/^!P!Q3U!Q!}/^!}#O5S#O#P2o#P;'S/^;'S;=`6T<%lO/^Q0fXwQOY0aZ!P0a!P!Q1R!Q!}0a!}#O1p#O#P2o#P;'S0a;'S;=`3O<%lO0aQ1UP!P!Q1XQ1^UwQ#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;=`<%l0aU3ZWsSOt#{uw#{x!P#{!P!Q3s!Q#O#{#P;'S#{;'S;=`$d<%lO#{U3zbsSwQOt#{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[sSOY5SYZ#{Zt5Stu1puw5Swx1px#O5S#O#P2Y#P#Q/^#Q;'S5S;'S;=`5}<%lO5SU6QP;=`<%l5SU6WP;=`<%l/^U6bUsS!PQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U6{W#ZQsSOt#{uw#{x!_#{!_!`7e!`#O#{#P;'S#{;'S;=`$d<%lO#{U7jVsSOt#{uw#{x#O#{#P#Q8P#Q;'S#{;'S;=`$d<%lO#{U8WU#YQsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~8oO#U~U8vU#^QsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9aUsS!WQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9x]sSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#U:q#U#o,Y#o;'S#{;'S;=`$d<%lO#{U:v^sSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#`,Y#`#a;r#a#o,Y#o;'S#{;'S;=`$d<%lO#{U;w^sSOt#{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^sSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#X,Y#X#Y=t#Y#o,Y#o;'S#{;'S;=`$d<%lO#{U={[vQsSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^>x[#VWsSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^?u[#XWsSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^@r^#WWsSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#f,Y#f#gAn#g#o,Y#o;'S#{;'S;=`$d<%lO#{UAs^sSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#i,Y#i#j<s#j#o,Y#o;'S#{;'S;=`$d<%lO#{UBvU!`QsSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~C_O#a~", tokenData: "C|~R|OX#{XY$jYZ%TZp#{pq$jqs#{st%ntu'tuw#{wx'yxy(Oyz(iz{#{{|)S|}#{}!O+v!O!P#{!P!Q.]!Q![)q![!]6x!]!^%T!^!}#{!}#O7c#O#P9X#P#Q9^#Q#R#{#R#S9w#S#T#{#T#Y,w#Y#Z:b#Z#b,w#b#c?`#c#f,w#f#g@]#g#h,w#h#iAY#i#o,w#o#p#{#p#qC^#q;'S#{;'S;=`$d<%l~#{~O#{~~CwS$QUtSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{S$gP;=`<%l#{^$qUtS!xYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UtS#[QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%sWtSOp#{pq&]qt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^&dZiYtSOY&]YZ#{Zt&]tu'Vuw&]wx'Vx#O&]#O#P'V#P;'S&];'S;=`'n<%lO&]Y'[SiYOY'VZ;'S'V;'S;=`'h<%lO'VY'kP;=`<%l'V^'qP;=`<%l&]~'yO#T~~(OO#R~U(VUtS!}QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(pUtS#_QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U)XWtSOt#{uw#{x!Q#{!Q![)q![#O#{#P;'S#{;'S;=`$d<%lO#{U)xYtSnQOt#{uw#{x!O#{!O!P*h!P!Q#{!Q![)q![#O#{#P;'S#{;'S;=`$d<%lO#{U*mWtSOt#{uw#{x!Q#{!Q![+V![#O#{#P;'S#{;'S;=`$d<%lO#{U+^WtSnQOt#{uw#{x!Q#{!Q![+V![#O#{#P;'S#{;'S;=`$d<%lO#{U+{^tSOt#{uw#{x}#{}!O,w!O!Q#{!Q![)q![!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{U,|[tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{U-yU{QtSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U.bWtSOt#{uw#{x!P#{!P!Q.z!Q#O#{#P;'S#{;'S;=`$d<%lO#{U/P^tSOY/{YZ#{Zt/{tu1Ouw/{wx1Ox!P/{!P!Q#{!Q!}/{!}#O5q#O#P3^#P;'S/{;'S;=`6r<%lO/{U0S^tSxQOY/{YZ#{Zt/{tu1Ouw/{wx1Ox!P/{!P!Q3s!Q!}/{!}#O5q#O#P3^#P;'S/{;'S;=`6r<%lO/{Q1TXxQOY1OZ!P1O!P!Q1p!Q!}1O!}#O2_#O#P3^#P;'S1O;'S;=`3m<%lO1OQ1sP!P!Q1vQ1{UxQ#Z#[1v#]#^1v#a#b1v#g#h1v#i#j1v#m#n1vQ2bVOY2_Z#O2_#O#P2w#P#Q1O#Q;'S2_;'S;=`3W<%lO2_Q2zSOY2_Z;'S2_;'S;=`3W<%lO2_Q3ZP;=`<%l2_Q3aSOY1OZ;'S1O;'S;=`3m<%lO1OQ3pP;=`<%l1OU3xWtSOt#{uw#{x!P#{!P!Q4b!Q#O#{#P;'S#{;'S;=`$d<%lO#{U4ibtSxQOt#{uw#{x#O#{#P#Z#{#Z#[4b#[#]#{#]#^4b#^#a#{#a#b4b#b#g#{#g#h4b#h#i#{#i#j4b#j#m#{#m#n4b#n;'S#{;'S;=`$d<%lO#{U5v[tSOY5qYZ#{Zt5qtu2_uw5qwx2_x#O5q#O#P2w#P#Q/{#Q;'S5q;'S;=`6l<%lO5qU6oP;=`<%l5qU6uP;=`<%l/{U7PUtS!QQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U7jW#ZQtSOt#{uw#{x!_#{!_!`8S!`#O#{#P;'S#{;'S;=`$d<%lO#{U8XVtSOt#{uw#{x#O#{#P#Q8n#Q;'S#{;'S;=`$d<%lO#{U8uU#YQtSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~9^O#U~U9eU#^QtSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U:OUtS!XQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U:g]tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#U;`#U#o,w#o;'S#{;'S;=`$d<%lO#{U;e^tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#`,w#`#a<a#a#o,w#o;'S#{;'S;=`$d<%lO#{U<f^tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#g,w#g#h=b#h#o,w#o;'S#{;'S;=`$d<%lO#{U=g^tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#X,w#X#Y>c#Y#o,w#o;'S#{;'S;=`$d<%lO#{U>j[wQtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^?g[#VWtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^@d[#XWtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#o,w#o;'S#{;'S;=`$d<%lO#{^Aa^#WWtSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#f,w#f#gB]#g#o,w#o;'S#{;'S;=`$d<%lO#{UBb^tSOt#{uw#{x}#{}!O,w!O!_#{!_!`-r!`#O#{#P#T#{#T#i,w#i#j=b#j#o,w#o;'S#{;'S;=`$d<%lO#{UCeU!aQtSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~C|O#a~",
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!|~~", 11)], tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!|~~", 11)],
topRules: {"Program":[0,25]}, topRules: {"Program":[0,26]},
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: 1634 tokenPrec: 1634
}) })

View File

@ -48,7 +48,6 @@ describe('Identifier', () => {
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier even?`) Identifier even?`)
}) })
}) })
describe('Unicode Symbol Support', () => { describe('Unicode Symbol Support', () => {
@ -637,26 +636,51 @@ describe('DotGet whitespace sensitivity', () => {
}) })
describe('Comments', () => { describe('Comments', () => {
test('are barely there', () => { test('are greedy', () => {
expect(`x = 5 # one banana\ny = 2 # two bananas`).toMatchTree(` expect(`
x = 5 # one banana
y = 2 # two bananas`).toMatchTree(`
Assign Assign
AssignableIdentifier x AssignableIdentifier x
Eq = Eq =
Number 5 Number 5
Comment # one banana
Assign Assign
AssignableIdentifier y AssignableIdentifier y
Eq = Eq =
Number 2`) Number 2
Comment # two bananas`)
expect('# some comment\nbasename = 5 # very astute\n basename / prop\n# good info').toMatchTree(` expect(`
Assign # some comment
AssignableIdentifier basename basename = 5 # very astute
Eq = basename / prop
Number 5 # good info`).toMatchTree(`
BinOp Comment # some comment
Identifier basename Assign
Slash / AssignableIdentifier basename
Identifier prop`) Eq =
Number 5
Comment # very astute
BinOp
Identifier basename
Slash /
Identifier prop
Comment # good info`)
})
test('words with # are not considered comments', () => {
expect('find #hashtag-file.txt').toMatchTree(`
FunctionCall
Identifier find
PositionalArg
Word #hashtag-file.txt`)
})
test('hastags in strings are not comments', () => {
expect("'this is not a #comment'").toMatchTree(`
String
StringFragment this is not a #comment`)
}) })
}) })
@ -697,7 +721,6 @@ describe('Array destructuring', () => {
Number 2`) Number 2`)
}) })
test('works with dotget', () => { test('works with dotget', () => {
expect('[ a ] = [ [1 2 3] ]; a.1').toMatchTree(` expect('[ a ] = [ [1 2 3] ]; a.1').toMatchTree(`
Assign Assign

View File

@ -150,8 +150,11 @@ describe('array literals', () => {
2 # second 2 # second
]`).toMatchTree(` ]`).toMatchTree(`
Array Array
Comment # something...
Number 1 Number 1
Comment # first
Number 2 Number 2
Comment # second
`) `)
}) })
@ -397,12 +400,15 @@ c=3]`).toMatchTree(`
c=3 c=3
]`).toMatchTree(` ]`).toMatchTree(`
Dict Dict
Comment # something...
NamedArg NamedArg
NamedArgPrefix a= NamedArgPrefix a=
Number 1 Number 1
Comment # first
NamedArg NamedArg
NamedArgPrefix b= NamedArgPrefix b=
Number 2 Number 2
Comment # second
NamedArg NamedArg
NamedArgPrefix c= NamedArgPrefix c=
Number 3 Number 3

Binary file not shown.