implicit function-level try blocks
This commit is contained in:
parent
701ca98401
commit
0720348a08
|
|
@ -255,7 +255,10 @@ export class Compiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
case terms.FunctionDef: {
|
case terms.FunctionDef: {
|
||||||
const { paramNames, bodyNodes } = getFunctionDefParts(node, input)
|
const { paramNames, bodyNodes, catchVariable, catchBody, finallyBody } = getFunctionDefParts(
|
||||||
|
node,
|
||||||
|
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}`
|
||||||
|
|
@ -263,9 +266,28 @@ export class Compiler {
|
||||||
instructions.push(['JUMP', afterLabel])
|
instructions.push(['JUMP', afterLabel])
|
||||||
|
|
||||||
instructions.push([`${functionLabel}:`])
|
instructions.push([`${functionLabel}:`])
|
||||||
bodyNodes.forEach((bodyNode) => {
|
|
||||||
instructions.push(...this.#compileNode(bodyNode, input))
|
const compileFunctionBody = () => {
|
||||||
|
const bodyInstructions: ProgramItem[] = []
|
||||||
|
bodyNodes.forEach((bodyNode, index) => {
|
||||||
|
bodyInstructions.push(...this.#compileNode(bodyNode, input))
|
||||||
|
if (index < bodyNodes.length - 1) {
|
||||||
|
bodyInstructions.push(['POP'])
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
return bodyInstructions
|
||||||
|
}
|
||||||
|
|
||||||
|
// If function has catch or finally, wrap body in try/catch/finally
|
||||||
|
if (catchVariable || finallyBody) {
|
||||||
|
instructions.push(
|
||||||
|
...this.#compileTryCatchFinally(compileFunctionBody, catchVariable, catchBody, finallyBody, input)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Normal function without catch/finally
|
||||||
|
instructions.push(...compileFunctionBody())
|
||||||
|
}
|
||||||
|
|
||||||
instructions.push(['RETURN'])
|
instructions.push(['RETURN'])
|
||||||
|
|
||||||
instructions.push([`${afterLabel}:`])
|
instructions.push([`${afterLabel}:`])
|
||||||
|
|
@ -338,60 +360,21 @@ export class Compiler {
|
||||||
case terms.TryExpr: {
|
case terms.TryExpr: {
|
||||||
const { tryBlock, catchVariable, catchBody, finallyBody } = getTryExprParts(node, input)
|
const { tryBlock, catchVariable, catchBody, finallyBody } = getTryExprParts(node, input)
|
||||||
|
|
||||||
const instructions: ProgramItem[] = []
|
return this.#compileTryCatchFinally(
|
||||||
this.tryLabelCount++
|
() => this.#compileNode(tryBlock, input),
|
||||||
const catchLabel: Label = `.catch_${this.tryLabelCount}`
|
catchVariable,
|
||||||
const finallyLabel: Label = finallyBody ? `.finally_${this.tryLabelCount}` : null as any
|
catchBody,
|
||||||
const endLabel: Label = `.end_try_${this.tryLabelCount}`
|
finallyBody,
|
||||||
|
input
|
||||||
instructions.push(['PUSH_TRY', catchLabel])
|
)
|
||||||
|
|
||||||
const tryInstructions = this.#compileNode(tryBlock, input)
|
|
||||||
instructions.push(...tryInstructions)
|
|
||||||
|
|
||||||
instructions.push(['POP_TRY'])
|
|
||||||
if (finallyBody) {
|
|
||||||
instructions.push(['JUMP', finallyLabel])
|
|
||||||
} else {
|
|
||||||
instructions.push(['JUMP', endLabel])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
instructions.push([`${catchLabel}:`])
|
case terms.Throw: {
|
||||||
if (catchBody && catchVariable) {
|
|
||||||
// catch block
|
|
||||||
instructions.push(['STORE', catchVariable])
|
|
||||||
const catchInstructions = this.#compileNode(catchBody, input)
|
|
||||||
instructions.push(...catchInstructions)
|
|
||||||
instructions.push(['JUMP', finallyBody ? finallyLabel : endLabel])
|
|
||||||
} else {
|
|
||||||
// no catch block
|
|
||||||
if (finallyBody) {
|
|
||||||
instructions.push(['JUMP', finallyLabel])
|
|
||||||
} else {
|
|
||||||
instructions.push(['THROW'])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally block
|
|
||||||
if (finallyBody) {
|
|
||||||
instructions.push([`${finallyLabel}:`])
|
|
||||||
const finallyInstructions = this.#compileNode(finallyBody, input)
|
|
||||||
instructions.push(...finallyInstructions)
|
|
||||||
// finally doesn't return a value
|
|
||||||
instructions.push(['POP'])
|
|
||||||
}
|
|
||||||
|
|
||||||
instructions.push([`${endLabel}:`])
|
|
||||||
|
|
||||||
return instructions
|
|
||||||
}
|
|
||||||
|
|
||||||
case terms.ThrowStatement: {
|
|
||||||
const children = getAllChildren(node)
|
const children = getAllChildren(node)
|
||||||
const [_throwKeyword, expression] = children
|
const [_throwKeyword, expression] = children
|
||||||
if (!expression) {
|
if (!expression) {
|
||||||
throw new CompilerError(
|
throw new CompilerError(
|
||||||
`ThrowStatement expected expression, got ${children.length} children`,
|
`Throw expected expression, got ${children.length} children`,
|
||||||
node.from,
|
node.from,
|
||||||
node.to
|
node.to
|
||||||
)
|
)
|
||||||
|
|
@ -606,4 +589,52 @@ export class Compiler {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#compileTryCatchFinally(
|
||||||
|
compileTryBody: () => ProgramItem[],
|
||||||
|
catchVariable: string | undefined,
|
||||||
|
catchBody: SyntaxNode | undefined,
|
||||||
|
finallyBody: SyntaxNode | undefined,
|
||||||
|
input: string
|
||||||
|
): ProgramItem[] {
|
||||||
|
const instructions: ProgramItem[] = []
|
||||||
|
this.tryLabelCount++
|
||||||
|
const catchLabel: Label = `.catch_${this.tryLabelCount}`
|
||||||
|
const finallyLabel: Label = finallyBody ? `.finally_${this.tryLabelCount}` : (null as any)
|
||||||
|
const endLabel: Label = `.end_try_${this.tryLabelCount}`
|
||||||
|
|
||||||
|
instructions.push(['PUSH_TRY', catchLabel])
|
||||||
|
instructions.push(...compileTryBody())
|
||||||
|
instructions.push(['POP_TRY'])
|
||||||
|
instructions.push(['JUMP', finallyBody ? finallyLabel : endLabel])
|
||||||
|
|
||||||
|
// catch block
|
||||||
|
instructions.push([`${catchLabel}:`])
|
||||||
|
if (catchBody && catchVariable) {
|
||||||
|
instructions.push(['STORE', catchVariable])
|
||||||
|
const catchInstructions = this.#compileNode(catchBody, input)
|
||||||
|
instructions.push(...catchInstructions)
|
||||||
|
instructions.push(['JUMP', finallyBody ? finallyLabel : endLabel])
|
||||||
|
} else {
|
||||||
|
// no catch block
|
||||||
|
if (finallyBody) {
|
||||||
|
instructions.push(['JUMP', finallyLabel])
|
||||||
|
} else {
|
||||||
|
instructions.push(['THROW'])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally block
|
||||||
|
if (finallyBody) {
|
||||||
|
instructions.push([`${finallyLabel}:`])
|
||||||
|
const finallyInstructions = this.#compileNode(finallyBody, input)
|
||||||
|
instructions.push(...finallyInstructions)
|
||||||
|
// finally doesn't return a value
|
||||||
|
instructions.push(['POP'])
|
||||||
|
}
|
||||||
|
|
||||||
|
instructions.push([`${endLabel}:`])
|
||||||
|
|
||||||
|
return instructions
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -181,3 +181,131 @@ describe('exception handling', () => {
|
||||||
`).toEvaluateTo(30)
|
`).toEvaluateTo(30)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('function-level exception handling', () => {
|
||||||
|
test('function with catch - no error', () => {
|
||||||
|
expect(`
|
||||||
|
read-file = do path:
|
||||||
|
path
|
||||||
|
catch e:
|
||||||
|
'default'
|
||||||
|
end
|
||||||
|
|
||||||
|
read-file test.txt
|
||||||
|
`).toEvaluateTo('test.txt')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('function with catch - error thrown', () => {
|
||||||
|
expect(`
|
||||||
|
read-file = do path:
|
||||||
|
throw 'file not found'
|
||||||
|
catch e:
|
||||||
|
'default'
|
||||||
|
end
|
||||||
|
|
||||||
|
read-file test.txt
|
||||||
|
`).toEvaluateTo('default')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('function with catch - error variable binding', () => {
|
||||||
|
expect(`
|
||||||
|
safe-call = do:
|
||||||
|
throw 'operation failed'
|
||||||
|
catch err:
|
||||||
|
err
|
||||||
|
end
|
||||||
|
|
||||||
|
safe-call
|
||||||
|
`).toEvaluateTo('operation failed')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('function with finally - always runs', () => {
|
||||||
|
expect(`
|
||||||
|
counter = 0
|
||||||
|
increment-task = do:
|
||||||
|
result = 42
|
||||||
|
result
|
||||||
|
finally:
|
||||||
|
counter = counter + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
x = increment-task
|
||||||
|
y = increment-task
|
||||||
|
counter
|
||||||
|
`).toEvaluateTo(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('function with finally - return value from body', () => {
|
||||||
|
expect(`
|
||||||
|
get-value = do:
|
||||||
|
100
|
||||||
|
finally:
|
||||||
|
999
|
||||||
|
end
|
||||||
|
|
||||||
|
get-value
|
||||||
|
`).toEvaluateTo(100)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('function with catch and finally', () => {
|
||||||
|
expect(`
|
||||||
|
cleanup-count = 0
|
||||||
|
safe-op = do should-fail:
|
||||||
|
if should-fail:
|
||||||
|
throw 'failed'
|
||||||
|
end
|
||||||
|
'success'
|
||||||
|
catch e:
|
||||||
|
'caught'
|
||||||
|
finally:
|
||||||
|
cleanup-count = cleanup-count + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
result1 = safe-op false
|
||||||
|
result2 = safe-op true
|
||||||
|
cleanup-count
|
||||||
|
`).toEvaluateTo(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('function with catch and finally - catch return value', () => {
|
||||||
|
expect(`
|
||||||
|
safe-fail = do:
|
||||||
|
throw 'always fails'
|
||||||
|
catch e:
|
||||||
|
'error handled'
|
||||||
|
finally:
|
||||||
|
noop = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
safe-fail
|
||||||
|
`).toEvaluateTo('error handled')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('function without catch/finally still works', () => {
|
||||||
|
expect(`
|
||||||
|
regular = do x:
|
||||||
|
x + 10
|
||||||
|
end
|
||||||
|
|
||||||
|
regular 5
|
||||||
|
`).toEvaluateTo(15)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('nested functions with catch', () => {
|
||||||
|
expect(`
|
||||||
|
inner = do:
|
||||||
|
throw 'inner error'
|
||||||
|
catch e:
|
||||||
|
'inner caught'
|
||||||
|
end
|
||||||
|
|
||||||
|
outer = do:
|
||||||
|
inner
|
||||||
|
catch e:
|
||||||
|
'outer caught'
|
||||||
|
end
|
||||||
|
|
||||||
|
outer
|
||||||
|
`).toEvaluateTo('inner caught')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
||||||
|
|
@ -59,11 +59,11 @@ export const getAssignmentParts = (node: SyntaxNode) => {
|
||||||
|
|
||||||
export const getFunctionDefParts = (node: SyntaxNode, input: string) => {
|
export const getFunctionDefParts = (node: SyntaxNode, input: string) => {
|
||||||
const children = getAllChildren(node)
|
const children = getAllChildren(node)
|
||||||
const [fnKeyword, paramsNode, colon, ...bodyNodes] = children
|
const [fnKeyword, paramsNode, colon, ...rest] = children
|
||||||
|
|
||||||
if (!fnKeyword || !paramsNode || !colon || !bodyNodes) {
|
if (!fnKeyword || !paramsNode || !colon || !rest) {
|
||||||
throw new CompilerError(
|
throw new CompilerError(
|
||||||
`FunctionDef expected 5 children, got ${children.length}`,
|
`FunctionDef expected at least 4 children, got ${children.length}`,
|
||||||
node.from,
|
node.from,
|
||||||
node.to
|
node.to
|
||||||
)
|
)
|
||||||
|
|
@ -80,8 +80,48 @@ export const getFunctionDefParts = (node: SyntaxNode, input: string) => {
|
||||||
return input.slice(param.from, param.to)
|
return input.slice(param.from, param.to)
|
||||||
})
|
})
|
||||||
|
|
||||||
const bodyWithoutEnd = bodyNodes.slice(0, -1)
|
// Separate body nodes from catch/finally/end
|
||||||
return { paramNames, bodyNodes: bodyWithoutEnd }
|
const bodyNodes: SyntaxNode[] = []
|
||||||
|
let catchExpr: SyntaxNode | undefined
|
||||||
|
let catchVariable: string | undefined
|
||||||
|
let catchBody: SyntaxNode | undefined
|
||||||
|
let finallyExpr: SyntaxNode | undefined
|
||||||
|
let finallyBody: SyntaxNode | undefined
|
||||||
|
|
||||||
|
for (const child of rest) {
|
||||||
|
if (child.type.id === terms.CatchExpr) {
|
||||||
|
catchExpr = child
|
||||||
|
const catchChildren = getAllChildren(child)
|
||||||
|
const [_catchKeyword, identifierNode, _colon, body] = catchChildren
|
||||||
|
if (!identifierNode || !body) {
|
||||||
|
throw new CompilerError(
|
||||||
|
`CatchExpr expected identifier and body, got ${catchChildren.length} children`,
|
||||||
|
child.from,
|
||||||
|
child.to
|
||||||
|
)
|
||||||
|
}
|
||||||
|
catchVariable = input.slice(identifierNode.from, identifierNode.to)
|
||||||
|
catchBody = body
|
||||||
|
} else if (child.type.id === terms.FinallyExpr) {
|
||||||
|
finallyExpr = child
|
||||||
|
const finallyChildren = getAllChildren(child)
|
||||||
|
const [_finallyKeyword, _colon, body] = finallyChildren
|
||||||
|
if (!body) {
|
||||||
|
throw new CompilerError(
|
||||||
|
`FinallyExpr expected body, got ${finallyChildren.length} children`,
|
||||||
|
child.from,
|
||||||
|
child.to
|
||||||
|
)
|
||||||
|
}
|
||||||
|
finallyBody = body
|
||||||
|
} else if (child.type.name === 'keyword' && input.slice(child.from, child.to) === 'end') {
|
||||||
|
// Skip the end keyword
|
||||||
|
} else {
|
||||||
|
bodyNodes.push(child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { paramNames, bodyNodes, catchVariable, catchBody, finallyBody }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getFunctionCallParts = (node: SyntaxNode, input: string) => {
|
export const getFunctionCallParts = (node: SyntaxNode, input: string) => {
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ consumeToTerminator {
|
||||||
PipeExpr |
|
PipeExpr |
|
||||||
ambiguousFunctionCall |
|
ambiguousFunctionCall |
|
||||||
TryExpr |
|
TryExpr |
|
||||||
ThrowStatement |
|
Throw |
|
||||||
IfExpr |
|
IfExpr |
|
||||||
FunctionDef |
|
FunctionDef |
|
||||||
Assign |
|
Assign |
|
||||||
|
|
@ -99,11 +99,11 @@ FunctionDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
singleLineFunctionDef {
|
singleLineFunctionDef {
|
||||||
Do Params colon consumeToTerminator @specialize[@name=keyword]<Identifier, "end">
|
Do Params colon consumeToTerminator CatchExpr? FinallyExpr? @specialize[@name=keyword]<Identifier, "end">
|
||||||
}
|
}
|
||||||
|
|
||||||
multilineFunctionDef {
|
multilineFunctionDef {
|
||||||
Do Params colon newlineOrSemicolon block @specialize[@name=keyword]<Identifier, "end">
|
Do Params colon newlineOrSemicolon block CatchExpr? FinallyExpr? @specialize[@name=keyword]<Identifier, "end">
|
||||||
}
|
}
|
||||||
|
|
||||||
IfExpr {
|
IfExpr {
|
||||||
|
|
@ -158,7 +158,7 @@ TryBlock {
|
||||||
block
|
block
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowStatement {
|
Throw {
|
||||||
@specialize[@name=keyword]<Identifier, "throw"> expression
|
@specialize[@name=keyword]<Identifier, "throw"> expression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,17 +39,17 @@ export const
|
||||||
FunctionDef = 37,
|
FunctionDef = 37,
|
||||||
Params = 38,
|
Params = 38,
|
||||||
colon = 39,
|
colon = 39,
|
||||||
|
CatchExpr = 40,
|
||||||
keyword = 63,
|
keyword = 63,
|
||||||
Underscore = 41,
|
TryBlock = 42,
|
||||||
Array = 42,
|
FinallyExpr = 43,
|
||||||
Null = 43,
|
Underscore = 46,
|
||||||
ConditionalOp = 44,
|
Array = 47,
|
||||||
PositionalArg = 45,
|
Null = 48,
|
||||||
TryExpr = 47,
|
ConditionalOp = 49,
|
||||||
CatchExpr = 49,
|
PositionalArg = 50,
|
||||||
TryBlock = 51,
|
TryExpr = 52,
|
||||||
FinallyExpr = 52,
|
Throw = 54,
|
||||||
ThrowStatement = 54,
|
|
||||||
IfExpr = 56,
|
IfExpr = 56,
|
||||||
SingleLineThenBlock = 58,
|
SingleLineThenBlock = 58,
|
||||||
ThenBlock = 59,
|
ThenBlock = 59,
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,13 @@ 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,end:80, null:86, try:96, catch:100, finally:106, throw:110, if:114, elseif:122, else:126}
|
const spec_Identifier = {__proto__:null,catch:82, finally:88, end:90, null:96, try:106, throw:110, if:114, elseif:122, else:126}
|
||||||
export const parser = LRParser.deserialize({
|
export const parser = LRParser.deserialize({
|
||||||
version: 14,
|
version: 14,
|
||||||
states: "7^QYQbOOO#tQcO'#CvO$qOSO'#CxO%PQbO'#E`OOQ`'#DR'#DROOQa'#DO'#DOO&SQbO'#DWO'XQcO'#ETOOQa'#ET'#ETO)cQcO'#ESO*bQRO'#CwO+WQcO'#EOO+hQcO'#EOO+rQbO'#CuO,jOpO'#CsOOQ`'#EP'#EPO,oQbO'#EOO,vQQO'#EfOOQ`'#D]'#D]O,{QbO'#DdO,{QbO'#EhOOQ`'#Df'#DfO-pQRO'#DnOOQ`'#EO'#EOO-uQQO'#D}OOQ`'#D}'#D}OOQ`'#Do'#DoQYQbOOO-}QbO'#DPOOQa'#ES'#ESOOQ`'#DZ'#DZOOQ`'#Ee'#EeOOQ`'#Dv'#DvO.XQbO,59^O.rQbO'#CzO.zQWO'#C{OOOO'#EV'#EVOOOO'#Dp'#DpO/`OSO,59dOOQa,59d,59dOOQ`'#Dr'#DrO/nQbO'#DSO/vQQO,5:zOOQ`'#Dq'#DqO/{QbO,59rO0SQQO,59jOOQa,59r,59rO0_QbO,59rO,{QbO,59cO,{QbO,59cO,{QbO,59cO,{QbO,59tO,{QbO,59tO,{QbO,59tO0iQRO,59aO0pQRO,59aO1RQRO,59aO0|QQO,59aO1^QQO,59aO1fObO,59_O1qQbO'#DwO1|QbO,59]O2eQbO,5;QOOQ`,5:O,5:OO2xQRO,5;SO3PQRO,5;SO3[QbO,5:YOOQ`,5:i,5:iOOQ`-E7m-E7mOOQ`,59k,59kOOQ`-E7t-E7tOOOO,59f,59fOOOO,59g,59gOOOO-E7n-E7nOOQa1G/O1G/OOOQ`-E7p-E7pO3lQbO1G0fOOQ`-E7o-E7oO4PQQO1G/UOOQa1G/^1G/^O4[QbO1G/^OOQO'#Dt'#DtO4PQQO1G/UOOQa1G/U1G/UOOQ`'#Du'#DuO4[QbO1G/^OOQa1G.}1G.}O5TQcO1G.}O5_QcO1G.}O5iQcO1G.}OOQa1G/`1G/`O7XQcO1G/`O7`QcO1G/`O7gQcO1G/`OOQa1G.{1G.{OOQa1G.y1G.yO!aQbO'#CvO&ZQbO'#CrOOQ`,5:c,5:cOOQ`-E7u-E7uO7nQbO1G0lO7yQbO1G0mO8gQbO1G0nOOQ`1G/t1G/tO8zQbO7+&QO9PQbO7+&RO9gQQO7+$pOOQa7+$p7+$pO9rQbO7+$xOOQa7+$x7+$xOOQO-E7r-E7rOOQ`-E7s-E7sO9|QbO'#D_O:RQQO'#DbOOQ`7+&W7+&WO:WQbO7+&WO:]QbO7+&WOOQ`'#Ds'#DsO:eQQO'#DsO:jQbO'#EbOOQ`'#Da'#DaO;^QbO7+&XOOQ`'#Dh'#DhO;iQbO7+&YO;nQbO7+&ZOOQ`<<Il<<IlO<[QbO<<ImOOQa<<H[<<H[OOQa<<Hd<<HdO<aQQO,59yO<fQbO,59|OOQ`<<Ir<<IrO<yQbO<<IrOOQ`,5:_,5:_OOQ`-E7q-E7qOOQ`<<Is<<IsO=OQbO<<IsO=TQbO<<IsOOQ`<<It<<ItOOQ`'#Di'#DiO=]QbO<<IuOOQ`AN?XAN?XO=hQbO1G/eO9PQbO1G/hOOQ`1G/h1G/hOOQ`AN?^AN?^OOQ`AN?_AN?_O={QbOAN?_O,{QbO'#DjOOQ`'#Dx'#DxO>QQbOAN?aO>]QQO'#DlOOQ`AN?aAN?aO>bQbOAN?aO>gQbO7+%POOQ`7+%P7+%POOQ`7+%S7+%SOOQ`G24yG24yO?QQRO,5:UO?XQRO,5:UOOQ`-E7v-E7vOOQ`G24{G24{O?dQbOG24{O?iQQO,5:WOOQ`<<Hk<<HkO?nQQO1G/pOOQ`LD*gLD*gO9PQbO1G/rO;nQbO7+%[OOQ`7+%^7+%^OOQ`<<Hv<<Hv",
|
states: "8lQYQbOOO#tQcO'#CvO$qOSO'#CxO%PQbO'#E`OOQ`'#DR'#DROOQa'#DO'#DOO&SQbO'#D]O'XQcO'#ETOOQa'#ET'#ETO)cQcO'#ESO*bQRO'#CwO+WQcO'#EOO+hQcO'#EOO+rQbO'#CuO,jOpO'#CsOOQ`'#EP'#EPO,oQbO'#EOO,vQQO'#EfOOQ`'#Db'#DbO,{QbO'#DdO,{QbO'#EhOOQ`'#Df'#DfO-pQRO'#DnOOQ`'#EO'#EOO-uQQO'#D}OOQ`'#D}'#D}OOQ`'#Do'#DoQYQbOOO-}QbO'#DPOOQa'#ES'#ESOOQ`'#D`'#D`OOQ`'#Ee'#EeOOQ`'#Dv'#DvO.XQbO,59^O.rQbO'#CzO.zQWO'#C{OOOO'#EV'#EVOOOO'#Dp'#DpO/`OSO,59dOOQa,59d,59dOOQ`'#Dr'#DrO/nQbO'#DSO/vQQO,5:zOOQ`'#Dq'#DqO/{QbO,59wO0SQQO,59jOOQa,59w,59wO0_QbO,59wO,{QbO,59cO,{QbO,59cO,{QbO,59cO,{QbO,59yO,{QbO,59yO,{QbO,59yO0iQRO,59aO0pQRO,59aO1RQRO,59aO0|QQO,59aO1^QQO,59aO1fObO,59_O1qQbO'#DwO1|QbO,59]O2eQbO,5;QOOQ`,5:O,5:OO2xQRO,5;SO3PQRO,5;SO3[QbO,5:YOOQ`,5:i,5:iOOQ`-E7m-E7mOOQ`,59k,59kOOQ`-E7t-E7tOOOO,59f,59fOOOO,59g,59gOOOO-E7n-E7nOOQa1G/O1G/OOOQ`-E7p-E7pO3lQbO1G0fOOQ`-E7o-E7oO4PQQO1G/UOOQa1G/c1G/cO4[QbO1G/cOOQO'#Dt'#DtO4PQQO1G/UOOQa1G/U1G/UOOQ`'#Du'#DuO4[QbO1G/cOOQa1G.}1G.}O5TQcO1G.}O5_QcO1G.}O5iQcO1G.}OOQa1G/e1G/eO7XQcO1G/eO7`QcO1G/eO7gQcO1G/eOOQa1G.{1G.{OOQa1G.y1G.yO!aQbO'#CvO&ZQbO'#CrOOQ`,5:c,5:cOOQ`-E7u-E7uO7nQbO1G0lO7yQbO1G0mO8gQbO1G0nOOQ`1G/t1G/tO8zQbO7+&QO7yQbO7+&SO9VQQO7+$pOOQa7+$p7+$pO9bQbO7+$}OOQa7+$}7+$}OOQO-E7r-E7rOOQ`-E7s-E7sO9lQbO'#DUO9qQQO'#DXOOQ`7+&W7+&WO9vQbO7+&WO9{QbO7+&WOOQ`'#Ds'#DsO:TQQO'#DsO:YQbO'#EaOOQ`'#DW'#DWO:|QbO7+&XOOQ`'#Dh'#DhO;XQbO7+&YO;^QbO7+&ZOOQ`<<Il<<IlO;zQbO<<IlO<PQbO<<IlO<XQbO<<InOOQa<<H[<<H[OOQa<<Hi<<HiO<dQQO,59pO<iQbO,59sOOQ`<<Ir<<IrO<|QbO<<IrOOQ`,5:_,5:_OOQ`-E7q-E7qOOQ`<<Is<<IsO=RQbO<<IsO=WQbO<<IsOOQ`<<It<<ItOOQ`'#Di'#DiO=`QbO<<IuOOQ`AN?WAN?WO=kQbOAN?WOOQ`AN?YAN?YO=pQbOAN?YO=uQbOAN?YO=}QbO1G/[O>bQbO1G/_OOQ`1G/_1G/_OOQ`AN?^AN?^OOQ`AN?_AN?_O>xQbOAN?_O,{QbO'#DjOOQ`'#Dx'#DxO>}QbOAN?aO?YQQO'#DlOOQ`AN?aAN?aO?_QbOAN?aOOQ`G24rG24rOOQ`G24tG24tO?dQbOG24tO?iQbO7+$vOOQ`7+$v7+$vOOQ`7+$y7+$yOOQ`G24yG24yO@SQRO,5:UO@ZQRO,5:UOOQ`-E7v-E7vOOQ`G24{G24{O@fQbOG24{O@kQQO,5:WOOQ`LD*`LD*`OOQ`<<Hb<<HbO@pQQO1G/pOOQ`LD*gLD*gO>bQbO1G/rO;^QbO7+%[OOQ`7+%^7+%^OOQ`<<Hv<<Hv",
|
||||||
stateData: "?v~O!oOS!pOS~O_PO`fOaWOb^OcROhWOpWOqWO{WO!QaO!XcO!ZdO!u]O!xQO#PTO#QUO#RiO~O_mOaWOb^OcROhWOpWOqWOtlOynO{WO!u]O!xQO#PTO#QUO!OjX#RjX#^jX#WjXxjX!SjX!VjX~OP!vXQ!vXR!vXS!vXT!vXU!vXW!vXX!vXY!vXZ!vX[!vX]!vX^!vX~P!aOmtO!xwO!zrO!{sO~O_xOwvP~O_mOaWOb^OhWOpWOqWOtlO{WO!u]O!xQO#PTO#QUO#R{O~O#V!OO~P%XO_mOaWOb^OcROhWOpWOqWOtlOynO{WO!u]O!xQO#PTO#QUO~OP!wXQ!wXR!wXS!wXT!wXU!wXW!wXX!wXY!wXZ!wX[!wX]!wX^!wX#R!wX#^!wX#W!wXx!wX!S!wX!V!wX~P&ZOP!vXQ!vXR!vXS!vXT!vXU!vXW!vXX!vXY!vXZ!vX[!vX]!vX^!vX~O#R!rX#^!rXx!rX!S!rX!V!rX~P(hOT!UOU!VOW!TOX!TOY!TOZ!TO[!TO]!TO~OP!ROQ!ROR!SOS!SO^!QO~P)vO#R!rX#^!rXx!rX!S!rX!V!rX~OP!ROQ!ROR!SOS!SO~P*uOT!UOU!VO~P*uO_POaWOb^OcROhWOpWOqWO{WO!u]O!xQO#PTO#QUO~O!t!]O~O!O!^O~P*uOw!`O~O_mOaWOb^OhWOpWOqWO{WO!u]O!xQO#PTO#QUO~OV!dO~O#R!eO#^!eO~OcROy!gO~P,{O!Ofa#Rfa#^fa#Wfaxfa!Sfa!Vfa~P&ZO_!iO!u]O~O!x!jO!z!jO!{!jO!|!jO!}!jO#O!jO~OmtO!x!lO!zrO!{sO~O_xOwvX~Ow!nO~O#V!qO~P%XOtlO#R!sO#V!uO~O#R!vO#V!qO~P,{O#W#QO~P(hOP!ROQ!ROR!SOS!SO#W#QO~OT!UOU!VO#W#QO~O!O!^O#W#QO~O_#ROh#RO!u]O~O_#SOb^O!u]O~O!O!^O#Rea#^ea#Weaxea!Sea!Vea~O`fO!QaO!XcO!ZdO#R#XO~P+rOw#YO~P)vOT!UOU!VOw#YO~O`fO!QaO!XcO!ZdO~P+rO`fO!QaO!XcO!ZdO#R#]O~P+rOtlO#R!sO#V#_O~O#R!vO#V#aO~P,{O^!QORkiSki#Rki#^ki#Wkixki!Ski!Vki~OPkiQki~P4fOP!ROQ!RO~P4fOP!ROQ!RORkiSki#Rki#^ki#Wkixki!Ski!Vki~OW!TOX!TOY!TOZ!TO[!TO]!TOT|i#R|i#^|i#W|iw|ix|i!S|i!V|i~OU!VO~P6ZOU!VO~P6mOU|i~P6ZOx#fO!S#dO!V#eO~O`fO!QaO!XcO!ZdO#R#iOx#UP!S#UP!V#UP~P+rO`fO!QaO!XcO!ZdO#R#pO~P+rOx#qO~O`fO!QaO!XcO!ZdO#R#iOx#UP~P+rOtlO#R!sO#V#sO~O#R!vO#V#tO~P,{O_#uO~Ow#vO~Ox#wO~Ox#wO!V#eO~O#R#yO~O`fO!QaO!XcO!ZdO#R#iOx#UX!S#UX!V#UX!_#UX!a#UX~P+rOx#{O!S#dO!V#eO~Ox$OO~O`fO!QaO!XcO!ZdO#R#iOx#UP!_#UP!a#UP~P+rOx$RO~Ow$SO~O`fO!QaO!XcO!ZdO#R$TO~P+rOx$VO~Ox$WO~Ox$WO!V#eO~Ox$^O!_$YO!a$]O~O`fO!QaO!XcO!ZdO#R$`O~P+rOx$cO~Ox$gO!_$YO!a$]O~Ow$iO~Ox$gO~O`fO!QaO!XcO!ZdO#R#iOx#UP!V#UP~P+rOw$kO~P)vOT!UOU!VOw$kO~Ox$lO~O#R$mO~O#R$nO~Ohq~",
|
stateData: "@x~O!oOS!pOS~O_PO`fOaWOb^OcROhWOpWOqWO!QWO!VaO!XcO!ZdO!u]O!xQO#PTO#QUO#RiO~O_mOaWOb^OcROhWOpWOqWOtlO!OnO!QWO!u]O!xQO#PTO#QUO!TjX#RjX#^jX#WjXyjX|jX}jX~OP!vXQ!vXR!vXS!vXT!vXU!vXW!vXX!vXY!vXZ!vX[!vX]!vX^!vX~P!aOmtO!xwO!zrO!{sO~O_xOwvP~O_mOaWOb^OhWOpWOqWOtlO!QWO!u]O!xQO#PTO#QUO#R{O~O#V!OO~P%XO_mOaWOb^OcROhWOpWOqWOtlO!OnO!QWO!u]O!xQO#PTO#QUO~OP!wXQ!wXR!wXS!wXT!wXU!wXW!wXX!wXY!wXZ!wX[!wX]!wX^!wX#R!wX#^!wX#W!wXy!wX|!wX}!wX~P&ZOP!vXQ!vXR!vXS!vXT!vXU!vXW!vXX!vXY!vXZ!vX[!vX]!vX^!vX~O#R!rX#^!rXy!rX|!rX}!rX~P(hOT!UOU!VOW!TOX!TOY!TOZ!TO[!TO]!TO~OP!ROQ!ROR!SOS!SO^!QO~P)vO#R!rX#^!rXy!rX|!rX}!rX~OP!ROQ!ROR!SOS!SO~P*uOT!UOU!VO~P*uO_POaWOb^OcROhWOpWOqWO!QWO!u]O!xQO#PTO#QUO~O!t!]O~O!T!^O~P*uOw!`O~O_mOaWOb^OhWOpWOqWO!QWO!u]O!xQO#PTO#QUO~OV!dO~O#R!eO#^!eO~OcRO!O!gO~P,{O!Tfa#Rfa#^fa#Wfayfa|fa}fa~P&ZO_!iO!u]O~O!x!jO!z!jO!{!jO!|!jO!}!jO#O!jO~OmtO!x!lO!zrO!{sO~O_xOwvX~Ow!nO~O#V!qO~P%XOtlO#R!sO#V!uO~O#R!vO#V!qO~P,{O#W#QO~P(hOP!ROQ!ROR!SOS!SO#W#QO~OT!UOU!VO#W#QO~O!T!^O#W#QO~O_#ROh#RO!u]O~O_#SOb^O!u]O~O!T!^O#Rea#^ea#Weayea|ea}ea~O`fO!VaO!XcO!ZdO#R#XO~P+rOw#YO~P)vOT!UOU!VOw#YO~O`fO!VaO!XcO!ZdO~P+rO`fO!VaO!XcO!ZdO#R#]O~P+rOtlO#R!sO#V#_O~O#R!vO#V#aO~P,{O^!QORkiSki#Rki#^ki#Wkiyki|ki}ki~OPkiQki~P4fOP!ROQ!RO~P4fOP!ROQ!RORkiSki#Rki#^ki#Wkiyki|ki}ki~OW!TOX!TOY!TOZ!TO[!TO]!TOT!Ri#R!Ri#^!Ri#W!Riw!Riy!Ri|!Ri}!Ri~OU!VO~P6ZOU!VO~P6mOU!Ri~P6ZOy#dO|#eO}#fO~O`fO!VaO!XcO!ZdO#R#iOy#TP|#TP}#TP~P+rO`fO!VaO!XcO!ZdO#R#pO~P+rOy#dO|#eO}#qO~OtlO#R!sO#V#uO~O#R!vO#V#vO~P,{O_#wO~Ow#xO~O}#yO~O|#eO}#yO~O#R#{O~O`fO!VaO!XcO!ZdO#R#iOy#TX|#TX}#TX!_#TX!a#TX~P+rOy#dO|#eO}#}O~O}$QO~O`fO!VaO!XcO!ZdO#R#iO}#TP!_#TP!a#TP~P+rO}$TO~O|#eO}$TO~Oy#dO|#eO}$VO~Ow$YO~O`fO!VaO!XcO!ZdO#R$ZO~P+rO}$]O~O}$^O~O|#eO}$^O~O}$dO!_$`O!a$cO~O}$fO~O}$gO~O|#eO}$gO~O`fO!VaO!XcO!ZdO#R$iO~P+rO`fO!VaO!XcO!ZdO#R#iO}#TP~P+rO}$lO~O}$pO!_$`O!a$cO~Ow$rO~O}$pO~O}$sO~O`fO!VaO!XcO!ZdO#R#iO|#TP}#TP~P+rOw$uO~P)vOT!UOU!VOw$uO~O}$vO~O#R$wO~O#R$xO~Ohq~",
|
||||||
goto: "2l#^PPPPPPPPPPPPPPPPPPPPP#_#t$YP%X#t&^&yP's'sPP&y'wP([({PPP&yP)O)qP)xP*[P*b*kP)xP)xP*w*z+TP+XP)x+_+e+k+q+w,T,_,i,r,yPPPP-P-T-uPP._/uP0sPPPPPPPP0w0w1bPP1o1v1v2Y2YpgOk!`!d!n#X#Y#]#k#p#v$S$T$`$m$nR!Z]u_O]k!^!`!d!n#X#Y#]#k#p#v$S$T$`$m$nrPO]k!`!d!n#X#Y#]#k#p#v$S$T$`$m$nzmPUVcdlq|!P!Q!R!S!T!U!V!r!w#S#T#`$YR#S!^rVO]k!`!d!n#X#Y#]#k#p#v$S$T$`$m$nzWPUVcdlq|!P!Q!R!S!T!U!V!r!w#S#T#`$YQ!irQ#R!]R#T!^pZOk!`!d!n#X#Y#]#k#p#v$S$T$`$m$nQ!X]Q!x!RR!{!S!oWOPUV]cdklq|!P!Q!R!S!T!U!V!`!d!n!r!w#S#T#X#Y#]#`#k#p#v$S$T$Y$`$m$nTtQvYoPVq#S#TQ}UQ!p|X!s}!p!t#^pgOk!`!d!n#X#Y#]#k#p#v$S$T$`$m$nYnPVq#S#TQ!Z]R!glRzRp[Ok!`!d!n#X#Y#]#k#p#v$S$T$`$m$nQ!Y]Q!cdQ!|!VQ#O!UR$e$YZoPVq#S#TqgOk!`!d!n#X#Y#]#k#p#v$S$T$`$m$nQ#h#WR#}#mQ#m#XQ$b$TR$j$`Q#g#WQ#x#hQ#|#mR$X#}R#o#YQ$Q#pQ$o$mR$p$nT$Z$Q$[Q$_$QR$h$[QkOR!fkQvQR!kvQ|UR!o|QyRR!my^#k#X#]#p$T$`$m$nR#z#kQ!t}Q#^!pT#b!t#^Q!w!PQ#`!rT#c!w#`WqPV#S#TR!hqS!_`![R#V!_Q$[$QR$f$[TjOkShOkQ#W!`Q#Z!dQ#[!n`#j#X#]#k#p$T$`$m$nQ#n#YQ$U#vR$a$Sp`Ok!`!d!n#X#Y#]#k#p#v$S$T$`$m$nQ![]R#U!^rYO]k!`!d!n#X#Y#]#k#p#v$S$T$`$m$nYnPVq#S#TQ!PUQ!acQ!bdQ!glQ!r|W!v!P!r!w#`Q!x!QQ!y!RQ!z!SQ!|!TQ!}!UQ#P!VR$d$YpXOk!`!d!n#X#Y#]#k#p#v$S$T$`$m$nzmPUVcdlq|!P!Q!R!S!T!U!V!r!w#S#T#`$YR!W]TuQv!PSOPV]klq!`!d!n#S#T#X#Y#]#k#p#v$S$T$`$m$nU#l#X$T$`Q#r#]V$P#p$m$nZpPVq#S#TqbOk!`!d!n#X#Y#]#k#p#v$S$T$`$m$nqeOk!`!d!n#X#Y#]#k#p#v$S$T$`$m$n",
|
goto: "3O#^PPPPPPPPPPPPPPPPPPPPP#_#t$YP%X#t&^&yP's'sPP&y'wP([({P)OP)[)ePPP&yP)}*pP*wP*wP*wP+Z+^+gP+kP*w+q+w+},T,Z,g,q,{-U-]PPPP-c-g.XPP.q0XP1VPPPPPPPP1Z1t1ZPP2R2Y2Y2l2lpgOk!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xR!Z]u_O]k!^!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xrPO]k!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xzmPUVcdlq|!P!Q!R!S!T!U!V!r!w#S#T#`$`R#S!^rVO]k!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xzWPUVcdlq|!P!Q!R!S!T!U!V!r!w#S#T#`$`Q!irQ#R!]R#T!^pZOk!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xQ!X]Q!x!RR!{!S!oWOPUV]cdklq|!P!Q!R!S!T!U!V!`!d!n!r!w#S#T#X#Y#]#`#k#p#x$Y$Z$`$i$w$xTtQvYoPVq#S#TQ}UQ!p|X!s}!p!t#^pgOk!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xYnPVq#S#TQ!Z]R!glRzRQ#h#WQ#s#[Q$P#mR$X#tQ#m#XQ$k$ZR$t$iQ#g#WQ#r#[Q#z#hQ$O#mQ$U#sQ$W#tQ$_$PR$h$Xp[Ok!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xQ!Y]Q!cdQ!|!VQ#O!UR$n$`ZoPVq#S#TqgOk!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xR#o#YQ$S#pQ$y$wR$z$xT$a$S$bQ$e$SR$q$bQkOR!fkQvQR!kvQ|UR!o|QyRR!my^#k#X#]#p$Z$i$w$xR#|#kQ!t}Q#^!pT#b!t#^Q!w!PQ#`!rT#c!w#`WqPV#S#TR!hqS!_`![R#V!_Q$b$SR$o$bTjOkShOkQ#W!`Q#Z!dQ#[!n`#j#X#]#k#p$Z$i$w$xQ#n#YQ$[#xR$j$Yp`Ok!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xQ![]R#U!^rYO]k!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xYnPVq#S#TQ!PUQ!acQ!bdQ!glQ!r|W!v!P!r!w#`Q!x!QQ!y!RQ!z!SQ!|!TQ!}!UQ#P!VR$m$`pXOk!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xzmPUVcdlq|!P!Q!R!S!T!U!V!r!w#S#T#`$`R!W]TuQv!PSOPV]klq!`!d!n#S#T#X#Y#]#k#p#x$Y$Z$i$w$xU#l#X$Z$iQ#t#]V$R#p$w$xZpPVq#S#TqbOk!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$xqeOk!`!d!n#X#Y#]#k#p#x$Y$Z$i$w$x",
|
||||||
nodeNames: "⚠ Star Slash Plus Minus And Or Eq EqEq Neq Lt Lte Gt Gte Modulo 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 keyword Underscore Array Null ConditionalOp PositionalArg operator TryExpr keyword CatchExpr keyword TryBlock FinallyExpr keyword ThrowStatement keyword IfExpr keyword SingleLineThenBlock ThenBlock ElseIfExpr keyword ElseExpr keyword Assign",
|
nodeNames: "⚠ Star Slash Plus Minus And Or Eq EqEq Neq Lt Lte Gt Gte Modulo 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 Assign",
|
||||||
maxTerm: 106,
|
maxTerm: 106,
|
||||||
context: trackScope,
|
context: trackScope,
|
||||||
nodeProps: [
|
nodeProps: [
|
||||||
|
|
@ -19,9 +19,9 @@ export const parser = LRParser.deserialize({
|
||||||
propSources: [highlighting],
|
propSources: [highlighting],
|
||||||
skippedNodes: [0],
|
skippedNodes: [0],
|
||||||
repeatNodeCount: 10,
|
repeatNodeCount: 10,
|
||||||
tokenData: "AO~R|OX#{XY$jYZ%TZp#{pq$jqs#{st%ntu'Vuw#{wx'[xy'ayz'zz{#{{|(e|}#{}!O(e!O!P#{!P!Q+X!Q![)S![!]3t!]!^%T!^!}#{!}#O4_#O#P6T#P#Q6Y#Q#R#{#R#S6s#S#T#{#T#Y7^#Y#Z8l#Z#b7^#b#c<z#c#f7^#f#g=q#g#h7^#h#i>h#i#o7^#o#p#{#p#q@`#q;'S#{;'S;=`$d<%l~#{~O#{~~@yS$QUmSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{S$gP;=`<%l#{^$qUmS!oYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UmS#RQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%uZmS!pYOY%nYZ#{Zt%ntu&huw%nwx&hx#O%n#O#P&h#P;'S%n;'S;=`'P<%lO%nY&mS!pYOY&hZ;'S&h;'S;=`&y<%lO&hY&|P;=`<%l&h^'SP;=`<%l%n~'[O!z~~'aO!x~U'hUmS!uQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(RUmS#WQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(jWmSOt#{uw#{x!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U)ZYmShQOt#{uw#{x!O#{!O!P)y!P!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U*OWmSOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U*oWmShQOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U+^WmSOt#{uw#{x!P#{!P!Q+v!Q#O#{#P;'S#{;'S;=`$d<%lO#{U+{^mSOY,wYZ#{Zt,wtu-zuw,wwx-zx!P,w!P!Q#{!Q!},w!}#O2m#O#P0Y#P;'S,w;'S;=`3n<%lO,wU-O^mSqQOY,wYZ#{Zt,wtu-zuw,wwx-zx!P,w!P!Q0o!Q!},w!}#O2m#O#P0Y#P;'S,w;'S;=`3n<%lO,wQ.PXqQOY-zZ!P-z!P!Q.l!Q!}-z!}#O/Z#O#P0Y#P;'S-z;'S;=`0i<%lO-zQ.oP!P!Q.rQ.wUqQ#Z#[.r#]#^.r#a#b.r#g#h.r#i#j.r#m#n.rQ/^VOY/ZZ#O/Z#O#P/s#P#Q-z#Q;'S/Z;'S;=`0S<%lO/ZQ/vSOY/ZZ;'S/Z;'S;=`0S<%lO/ZQ0VP;=`<%l/ZQ0]SOY-zZ;'S-z;'S;=`0i<%lO-zQ0lP;=`<%l-zU0tWmSOt#{uw#{x!P#{!P!Q1^!Q#O#{#P;'S#{;'S;=`$d<%lO#{U1ebmSqQOt#{uw#{x#O#{#P#Z#{#Z#[1^#[#]#{#]#^1^#^#a#{#a#b1^#b#g#{#g#h1^#h#i#{#i#j1^#j#m#{#m#n1^#n;'S#{;'S;=`$d<%lO#{U2r[mSOY2mYZ#{Zt2mtu/Zuw2mwx/Zx#O2m#O#P/s#P#Q,w#Q;'S2m;'S;=`3h<%lO2mU3kP;=`<%l2mU3qP;=`<%l,wU3{UmSwQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U4fW#QQmSOt#{uw#{x!_#{!_!`5O!`#O#{#P;'S#{;'S;=`$d<%lO#{U5TVmSOt#{uw#{x#O#{#P#Q5j#Q;'S#{;'S;=`$d<%lO#{U5qU#PQmSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~6YO!{~U6aU#VQmSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U6zUmSyQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U7cYmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#o7^#o;'S#{;'S;=`$d<%lO#{U8YUtQmSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U8qZmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#U9d#U#o7^#o;'S#{;'S;=`$d<%lO#{U9i[mSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#`7^#`#a:_#a#o7^#o;'S#{;'S;=`$d<%lO#{U:d[mSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#g7^#g#h;Y#h#o7^#o;'S#{;'S;=`$d<%lO#{U;_[mSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#X7^#X#Y<T#Y#o7^#o;'S#{;'S;=`$d<%lO#{U<[YpQmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#o7^#o;'S#{;'S;=`$d<%lO#{^=RY!|WmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#o7^#o;'S#{;'S;=`$d<%lO#{^=xY#OWmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#o7^#o;'S#{;'S;=`$d<%lO#{^>o[!}WmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#f7^#f#g?e#g#o7^#o;'S#{;'S;=`$d<%lO#{U?j[mSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#i7^#i#j;Y#j#o7^#o;'S#{;'S;=`$d<%lO#{U@gU!OQmSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~AOO#^~",
|
tokenData: "AO~R|OX#{XY$jYZ%TZp#{pq$jqs#{st%ntu'Vuw#{wx'[xy'ayz'zz{#{{|(e|}#{}!O(e!O!P#{!P!Q+X!Q![)S![!]3t!]!^%T!^!}#{!}#O4_#O#P6T#P#Q6Y#Q#R#{#R#S6s#S#T#{#T#Y7^#Y#Z8l#Z#b7^#b#c<z#c#f7^#f#g=q#g#h7^#h#i>h#i#o7^#o#p#{#p#q@`#q;'S#{;'S;=`$d<%l~#{~O#{~~@yS$QUmSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{S$gP;=`<%l#{^$qUmS!oYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UmS#RQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%uZmS!pYOY%nYZ#{Zt%ntu&huw%nwx&hx#O%n#O#P&h#P;'S%n;'S;=`'P<%lO%nY&mS!pYOY&hZ;'S&h;'S;=`&y<%lO&hY&|P;=`<%l&h^'SP;=`<%l%n~'[O!z~~'aO!x~U'hUmS!uQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(RUmS#WQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(jWmSOt#{uw#{x!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U)ZYmShQOt#{uw#{x!O#{!O!P)y!P!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U*OWmSOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U*oWmShQOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U+^WmSOt#{uw#{x!P#{!P!Q+v!Q#O#{#P;'S#{;'S;=`$d<%lO#{U+{^mSOY,wYZ#{Zt,wtu-zuw,wwx-zx!P,w!P!Q#{!Q!},w!}#O2m#O#P0Y#P;'S,w;'S;=`3n<%lO,wU-O^mSqQOY,wYZ#{Zt,wtu-zuw,wwx-zx!P,w!P!Q0o!Q!},w!}#O2m#O#P0Y#P;'S,w;'S;=`3n<%lO,wQ.PXqQOY-zZ!P-z!P!Q.l!Q!}-z!}#O/Z#O#P0Y#P;'S-z;'S;=`0i<%lO-zQ.oP!P!Q.rQ.wUqQ#Z#[.r#]#^.r#a#b.r#g#h.r#i#j.r#m#n.rQ/^VOY/ZZ#O/Z#O#P/s#P#Q-z#Q;'S/Z;'S;=`0S<%lO/ZQ/vSOY/ZZ;'S/Z;'S;=`0S<%lO/ZQ0VP;=`<%l/ZQ0]SOY-zZ;'S-z;'S;=`0i<%lO-zQ0lP;=`<%l-zU0tWmSOt#{uw#{x!P#{!P!Q1^!Q#O#{#P;'S#{;'S;=`$d<%lO#{U1ebmSqQOt#{uw#{x#O#{#P#Z#{#Z#[1^#[#]#{#]#^1^#^#a#{#a#b1^#b#g#{#g#h1^#h#i#{#i#j1^#j#m#{#m#n1^#n;'S#{;'S;=`$d<%lO#{U2r[mSOY2mYZ#{Zt2mtu/Zuw2mwx/Zx#O2m#O#P/s#P#Q,w#Q;'S2m;'S;=`3h<%lO2mU3kP;=`<%l2mU3qP;=`<%l,wU3{UmSwQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U4fW#QQmSOt#{uw#{x!_#{!_!`5O!`#O#{#P;'S#{;'S;=`$d<%lO#{U5TVmSOt#{uw#{x#O#{#P#Q5j#Q;'S#{;'S;=`$d<%lO#{U5qU#PQmSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~6YO!{~U6aU#VQmSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U6zUmS!OQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U7cYmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#o7^#o;'S#{;'S;=`$d<%lO#{U8YUtQmSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U8qZmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#U9d#U#o7^#o;'S#{;'S;=`$d<%lO#{U9i[mSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#`7^#`#a:_#a#o7^#o;'S#{;'S;=`$d<%lO#{U:d[mSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#g7^#g#h;Y#h#o7^#o;'S#{;'S;=`$d<%lO#{U;_[mSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#X7^#X#Y<T#Y#o7^#o;'S#{;'S;=`$d<%lO#{U<[YpQmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#o7^#o;'S#{;'S;=`$d<%lO#{^=RY!|WmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#o7^#o;'S#{;'S;=`$d<%lO#{^=xY#OWmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#o7^#o;'S#{;'S;=`$d<%lO#{^>o[!}WmSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#f7^#f#g?e#g#o7^#o;'S#{;'S;=`$d<%lO#{U?j[mSOt#{uw#{x!_#{!_!`8R!`#O#{#P#T#{#T#i7^#i#j;Y#j#o7^#o;'S#{;'S;=`$d<%lO#{U@gU!TQmSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~AOO#^~",
|
||||||
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!t~~", 11)],
|
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!t~~", 11)],
|
||||||
topRules: {"Program":[0,20]},
|
topRules: {"Program":[0,20]},
|
||||||
specialized: [{term: 15, get: (value: any, stack: any) => (specializeKeyword(value, stack) << 1), external: specializeKeyword},{term: 15, get: (value: keyof typeof spec_Identifier) => spec_Identifier[value] || -1}],
|
specialized: [{term: 15, get: (value: any, stack: any) => (specializeKeyword(value, stack) << 1), external: specializeKeyword},{term: 15, get: (value: keyof typeof spec_Identifier) => spec_Identifier[value] || -1}],
|
||||||
tokenPrec: 1415
|
tokenPrec: 1463
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ describe('try/catch/finally/throw', () => {
|
||||||
|
|
||||||
test('parses throw statement with string', () => {
|
test('parses throw statement with string', () => {
|
||||||
expect("throw 'error message'").toMatchTree(`
|
expect("throw 'error message'").toMatchTree(`
|
||||||
ThrowStatement
|
Throw
|
||||||
keyword throw
|
keyword throw
|
||||||
String
|
String
|
||||||
StringFragment error message
|
StringFragment error message
|
||||||
|
|
@ -136,7 +136,7 @@ describe('try/catch/finally/throw', () => {
|
||||||
|
|
||||||
test('parses throw statement with identifier', () => {
|
test('parses throw statement with identifier', () => {
|
||||||
expect('throw error-object').toMatchTree(`
|
expect('throw error-object').toMatchTree(`
|
||||||
ThrowStatement
|
Throw
|
||||||
keyword throw
|
keyword throw
|
||||||
Identifier error-object
|
Identifier error-object
|
||||||
`)
|
`)
|
||||||
|
|
@ -144,7 +144,7 @@ describe('try/catch/finally/throw', () => {
|
||||||
|
|
||||||
test('parses throw statement with dict', () => {
|
test('parses throw statement with dict', () => {
|
||||||
expect('throw [type=validation-error message=failed]').toMatchTree(`
|
expect('throw [type=validation-error message=failed]').toMatchTree(`
|
||||||
ThrowStatement
|
Throw
|
||||||
keyword throw
|
keyword throw
|
||||||
Dict
|
Dict
|
||||||
NamedArg
|
NamedArg
|
||||||
|
|
@ -175,3 +175,104 @@ describe('try/catch/finally/throw', () => {
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('function-level exception handling', () => {
|
||||||
|
test('parses function with catch', () => {
|
||||||
|
expect(`read-file = do path:
|
||||||
|
read-data path
|
||||||
|
catch e:
|
||||||
|
empty-string
|
||||||
|
end`).toMatchTree(`
|
||||||
|
Assign
|
||||||
|
AssignableIdentifier read-file
|
||||||
|
Eq =
|
||||||
|
FunctionDef
|
||||||
|
Do do
|
||||||
|
Params
|
||||||
|
Identifier path
|
||||||
|
colon :
|
||||||
|
FunctionCall
|
||||||
|
Identifier read-data
|
||||||
|
PositionalArg
|
||||||
|
Identifier path
|
||||||
|
CatchExpr
|
||||||
|
keyword catch
|
||||||
|
Identifier e
|
||||||
|
colon :
|
||||||
|
TryBlock
|
||||||
|
FunctionCallOrIdentifier
|
||||||
|
Identifier empty-string
|
||||||
|
keyword end
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('parses function with finally', () => {
|
||||||
|
expect(`cleanup-task = do x:
|
||||||
|
do-work x
|
||||||
|
finally:
|
||||||
|
close-resources
|
||||||
|
end`).toMatchTree(`
|
||||||
|
Assign
|
||||||
|
AssignableIdentifier cleanup-task
|
||||||
|
Eq =
|
||||||
|
FunctionDef
|
||||||
|
Do do
|
||||||
|
Params
|
||||||
|
Identifier x
|
||||||
|
colon :
|
||||||
|
FunctionCall
|
||||||
|
Identifier do-work
|
||||||
|
PositionalArg
|
||||||
|
Identifier x
|
||||||
|
FinallyExpr
|
||||||
|
keyword finally
|
||||||
|
colon :
|
||||||
|
TryBlock
|
||||||
|
FunctionCallOrIdentifier
|
||||||
|
Identifier close-resources
|
||||||
|
keyword end
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('parses function with catch and finally', () => {
|
||||||
|
expect(`safe-operation = do x:
|
||||||
|
risky-work x
|
||||||
|
catch err:
|
||||||
|
log err
|
||||||
|
default-value
|
||||||
|
finally:
|
||||||
|
cleanup
|
||||||
|
end`).toMatchTree(`
|
||||||
|
Assign
|
||||||
|
AssignableIdentifier safe-operation
|
||||||
|
Eq =
|
||||||
|
FunctionDef
|
||||||
|
Do do
|
||||||
|
Params
|
||||||
|
Identifier x
|
||||||
|
colon :
|
||||||
|
FunctionCall
|
||||||
|
Identifier risky-work
|
||||||
|
PositionalArg
|
||||||
|
Identifier x
|
||||||
|
CatchExpr
|
||||||
|
keyword catch
|
||||||
|
Identifier err
|
||||||
|
colon :
|
||||||
|
TryBlock
|
||||||
|
FunctionCall
|
||||||
|
Identifier log
|
||||||
|
PositionalArg
|
||||||
|
Identifier err
|
||||||
|
FunctionCallOrIdentifier
|
||||||
|
Identifier default-value
|
||||||
|
FinallyExpr
|
||||||
|
keyword finally
|
||||||
|
colon :
|
||||||
|
TryBlock
|
||||||
|
FunctionCallOrIdentifier
|
||||||
|
Identifier cleanup
|
||||||
|
keyword end
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user