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 fnLabelCount = 0
ifLabelCount = 0 ifLabelCount = 0
tryLabelCount = 0 tryLabelCount = 0
loopLabelCount = 0
bytecode: Bytecode bytecode: Bytecode
pipeCounter = 0 pipeCounter = 0
@ -389,7 +388,9 @@ export class Compiler {
return instructions return instructions
} }
case terms.Block: { case terms.ThenBlock:
case terms.SingleLineThenBlock:
case terms.TryBlock: {
const children = getAllChildren(node) const children = getAllChildren(node)
const instructions: ProgramItem[] = [] const instructions: ProgramItem[] = []
@ -673,24 +674,6 @@ export class Compiler {
return instructions 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: 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

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

View File

@ -39,7 +39,7 @@ const tagCall = (tagName: string, atNamed = {}, ...args: any[]) => {
const space = attrs.length ? ' ' : '' const space = attrs.length ? ' ' : ''
const children = args const children = args
.reverse() .reverse()
.map(a => a === TAG_TOKEN ? buffer.pop() : a) .map(a => a === null ? buffer.pop() : a)
.reverse().join(' ') .reverse().join(' ')
.replaceAll(` ${NOSPACE_TOKEN} `, '') .replaceAll(` ${NOSPACE_TOKEN} `, '')
@ -50,16 +50,13 @@ const tagCall = (tagName: string, atNamed = {}, ...args: any[]) => {
} }
const tag = async (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]) await tagBlock(tagName, atNamed, args[0])
} else { else
tagCall(tagName, atNamed, ...args) tagCall(tagName, atNamed, ...args)
return TAG_TOKEN
}
} }
const NOSPACE_TOKEN = '!!ribbit-nospace!!' 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"] const SELF_CLOSING = ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"]
describe('ribbit', () => { 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) elseThenBlock = parts.at(-1)
} else if (child.type.id === terms.ElseIfExpr) { } else if (child.type.id === terms.ElseIfExpr) {
const [_else, _if, conditional, _colon, thenBlock] = parts const [_keyword, conditional, _colon, thenBlock] = parts
if (!conditional || !thenBlock) { if (!conditional || !thenBlock) {
const names = parts.map((p) => p.type.name).join(', ') const names = parts.map((p) => p.type.name).join(', ')
const message = `ElseIfExpr expected conditional and thenBlock, got ${names}` 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) => { export const getTryExprParts = (node: SyntaxNode, input: string) => {
const children = getAllChildren(node) 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 const [tryKeyword, _colon, tryBlock, ...rest] = children
if (!tryKeyword || !tryBlock) { if (!tryKeyword || !tryBlock) {

View File

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

View File

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

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,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({ export const parser = LRParser.deserialize({
version: 14, 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}", 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: "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~", 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: "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#[", 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 Block FinallyExpr keyword keyword Underscore Array ConditionalOp PositionalArg operator WhileExpr keyword FunctionCallWithBlock TryExpr keyword Throw keyword IfExpr keyword ElseIfExpr keyword ElseExpr 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 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: 108, maxTerm: 117,
context: trackScope, context: trackScope,
nodeProps: [ nodeProps: [
["closedBy", 46,"end"] ["closedBy", 46,"end"]
@ -19,9 +19,9 @@ export const parser = LRParser.deserialize({
propSources: [highlighting], propSources: [highlighting],
skippedNodes: [0], skippedNodes: [0],
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$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#`~", 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)], 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: 1578 tokenPrec: 1705
}) })

View File

@ -752,7 +752,7 @@ Assign
EqEq == EqEq ==
Number 5 Number 5
colon : colon :
Block ThenBlock
Boolean true Boolean true
keyword end keyword end
keyword end keyword end
@ -794,7 +794,7 @@ Assign
EqEq == EqEq ==
Number 5 Number 5
colon : colon :
Block ThenBlock
Boolean true Boolean true
keyword end keyword end
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! 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', () => { test('parses single line if', () => {
expect(`if y == 1: 'cool' end`).toMatchTree(` expect(`if y == 1: 'cool' end`).toMatchTree(`
IfExpr IfExpr
@ -12,7 +12,7 @@ describe('if/else if/else', () => {
EqEq == EqEq ==
Number 1 Number 1
colon : colon :
Block SingleLineThenBlock
String String
StringFragment cool StringFragment cool
keyword end keyword end
@ -26,7 +26,7 @@ describe('if/else if/else', () => {
keyword if keyword if
Identifier x Identifier x
colon : colon :
Block SingleLineThenBlock
Number 2 Number 2
keyword end keyword end
`) `)
@ -44,7 +44,7 @@ describe('if/else if/else', () => {
Lt < Lt <
Number 9 Number 9
colon : colon :
Block ThenBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier yes Identifier yes
keyword end keyword end
@ -61,81 +61,78 @@ describe('if/else if/else', () => {
keyword if keyword if
Identifier with-else Identifier with-else
colon : colon :
Block ThenBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier x Identifier x
ElseExpr ElseExpr
keyword else keyword else
colon : colon :
Block ThenBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier y Identifier y
keyword end keyword end
`) `)
}) })
test('parses multiline if with else if', () => { test('parses multiline if with elseif', () => {
expect(`if with-else-if: expect(`if with-elseif:
x x
else if another-condition: elseif another-condition:
y y
end`).toMatchTree(` end`).toMatchTree(`
IfExpr IfExpr
keyword if keyword if
Identifier with-else-if Identifier with-elseif
colon : colon :
Block ThenBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier x Identifier x
ElseIfExpr ElseIfExpr
keyword else keyword elseif
keyword if
Identifier another-condition Identifier another-condition
colon : colon :
Block ThenBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier y Identifier y
keyword end keyword end
`) `)
}) })
test('parses multiline if with multiple else if and else', () => { test('parses multiline if with multiple elseif and else', () => {
expect(`if with-else-if-else: expect(`if with-elseif-else:
x x
else if another-condition: elseif another-condition:
y y
else if yet-another-condition: elseif yet-another-condition:
z z
else: else:
oh-no oh-no
end`).toMatchTree(` end`).toMatchTree(`
IfExpr IfExpr
keyword if keyword if
Identifier with-else-if-else Identifier with-elseif-else
colon : colon :
Block ThenBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier x Identifier x
ElseIfExpr ElseIfExpr
keyword else keyword elseif
keyword if
Identifier another-condition Identifier another-condition
colon : colon :
Block ThenBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier y Identifier y
ElseIfExpr ElseIfExpr
keyword else keyword elseif
keyword if
Identifier yet-another-condition Identifier yet-another-condition
colon : colon :
Block ThenBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier z Identifier z
ElseExpr ElseExpr
keyword else keyword else
colon : colon :
Block ThenBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier oh-no Identifier oh-no
keyword end keyword end
@ -151,124 +148,9 @@ describe('if/else if/else', () => {
keyword if keyword if
Boolean true Boolean true
colon : colon :
Block SingleLineThenBlock
Number 2 Number 2
keyword end 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 TryExpr
keyword try keyword try
colon : colon :
Block TryBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier risky-operation Identifier risky-operation
CatchExpr CatchExpr
keyword catch keyword catch
Identifier err Identifier err
colon : colon :
Block TryBlock
FunctionCall FunctionCall
Identifier handle-error Identifier handle-error
PositionalArg PositionalArg
@ -37,13 +37,13 @@ describe('try/catch/finally/throw', () => {
TryExpr TryExpr
keyword try keyword try
colon : colon :
Block TryBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier do-work Identifier do-work
FinallyExpr FinallyExpr
keyword finally keyword finally
colon : colon :
Block TryBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier cleanup Identifier cleanup
keyword end keyword end
@ -61,14 +61,14 @@ describe('try/catch/finally/throw', () => {
TryExpr TryExpr
keyword try keyword try
colon : colon :
Block TryBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier risky-operation Identifier risky-operation
CatchExpr CatchExpr
keyword catch keyword catch
Identifier err Identifier err
colon : colon :
Block TryBlock
FunctionCall FunctionCall
Identifier handle-error Identifier handle-error
PositionalArg PositionalArg
@ -76,7 +76,7 @@ describe('try/catch/finally/throw', () => {
FinallyExpr FinallyExpr
keyword finally keyword finally
colon : colon :
Block TryBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier cleanup Identifier cleanup
keyword end keyword end
@ -91,17 +91,15 @@ describe('try/catch/finally/throw', () => {
TryExpr TryExpr
keyword try keyword try
colon : colon :
Block FunctionCall
FunctionCall Identifier parse-number
Identifier parse-number PositionalArg
PositionalArg Identifier input
Identifier input
CatchExpr CatchExpr
keyword catch keyword catch
Identifier err Identifier err
colon : colon :
Block Number 0
Number 0
keyword end keyword end
`) `)
}) })
@ -111,21 +109,18 @@ describe('try/catch/finally/throw', () => {
TryExpr TryExpr
keyword try keyword try
colon : colon :
Block FunctionCallOrIdentifier
FunctionCallOrIdentifier Identifier work
Identifier work
CatchExpr CatchExpr
keyword catch keyword catch
Identifier err Identifier err
colon : colon :
Block Number 0
Number 0
FinallyExpr FinallyExpr
keyword finally keyword finally
colon : colon :
Block FunctionCallOrIdentifier
FunctionCallOrIdentifier Identifier cleanup
Identifier cleanup
keyword end keyword end
`) `)
}) })
@ -169,15 +164,13 @@ describe('try/catch/finally/throw', () => {
TryExpr TryExpr
keyword try keyword try
colon : colon :
Block FunctionCallOrIdentifier
FunctionCallOrIdentifier Identifier work
Identifier work
CatchExpr CatchExpr
keyword catch keyword catch
Identifier err Identifier err
colon : colon :
Block Number 0
Number 0
keyword end keyword end
`) `)
}) })
@ -206,7 +199,7 @@ describe('function-level exception handling', () => {
keyword catch keyword catch
Identifier e Identifier e
colon : colon :
Block TryBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier empty-string Identifier empty-string
keyword end keyword end
@ -234,7 +227,7 @@ describe('function-level exception handling', () => {
FinallyExpr FinallyExpr
keyword finally keyword finally
colon : colon :
Block TryBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier close-resources Identifier close-resources
keyword end keyword end
@ -266,7 +259,7 @@ describe('function-level exception handling', () => {
keyword catch keyword catch
Identifier err Identifier err
colon : colon :
Block TryBlock
FunctionCall FunctionCall
Identifier log Identifier log
PositionalArg PositionalArg
@ -276,7 +269,7 @@ describe('function-level exception handling', () => {
FinallyExpr FinallyExpr
keyword finally keyword finally
colon : colon :
Block TryBlock
FunctionCallOrIdentifier FunctionCallOrIdentifier
Identifier cleanup Identifier cleanup
keyword end keyword end

View File

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