Compare commits
13 Commits
4fc1a965eb
...
67e0db090b
| Author | SHA1 | Date | |
|---|---|---|---|
| 67e0db090b | |||
| 24e0b49679 | |||
| 70ac5544a9 | |||
| 7756306e1d | |||
| 7bcd582dc6 | |||
| 6f531a2ebf | |||
| e68624b608 | |||
| 2fab792c1a | |||
| f1eaafee19 | |||
| 950eef0e69 | |||
| dc557deb40 | |||
| ee0e6c6c41 | |||
| 5f4bf60062 |
|
|
@ -54,6 +54,7 @@ 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
|
||||||
|
|
||||||
|
|
@ -388,9 +389,7 @@ export class Compiler {
|
||||||
return instructions
|
return instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
case terms.ThenBlock:
|
case terms.Block: {
|
||||||
case terms.SingleLineThenBlock:
|
|
||||||
case terms.TryBlock: {
|
|
||||||
const children = getAllChildren(node)
|
const children = getAllChildren(node)
|
||||||
const instructions: ProgramItem[] = []
|
const instructions: ProgramItem[] = []
|
||||||
|
|
||||||
|
|
@ -674,6 +673,24 @@ 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.`,
|
||||||
|
|
|
||||||
|
|
@ -154,18 +154,18 @@ describe('compiler', () => {
|
||||||
end`).toEvaluateTo('white')
|
end`).toEvaluateTo('white')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('if elseif', () => {
|
test('if else if', () => {
|
||||||
expect(`if false:
|
expect(`if false:
|
||||||
boromir
|
boromir
|
||||||
elseif true:
|
else if true:
|
||||||
frodo
|
frodo
|
||||||
end`).toEvaluateTo('frodo')
|
end`).toEvaluateTo('frodo')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('if elseif else', () => {
|
test('if else if else', () => {
|
||||||
expect(`if false:
|
expect(`if false:
|
||||||
destroyed
|
destroyed
|
||||||
elseif true:
|
else if true:
|
||||||
fire
|
fire
|
||||||
else:
|
else:
|
||||||
darkness
|
darkness
|
||||||
|
|
@ -173,9 +173,9 @@ describe('compiler', () => {
|
||||||
|
|
||||||
expect(`if false:
|
expect(`if false:
|
||||||
king
|
king
|
||||||
elseif false:
|
else if false:
|
||||||
elf
|
elf
|
||||||
elseif true:
|
else if true:
|
||||||
dwarf
|
dwarf
|
||||||
else:
|
else:
|
||||||
scattered
|
scattered
|
||||||
|
|
|
||||||
|
|
@ -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 === null ? buffer.pop() : a)
|
.map(a => a === TAG_TOKEN ? buffer.pop() : a)
|
||||||
.reverse().join(' ')
|
.reverse().join(' ')
|
||||||
.replaceAll(` ${NOSPACE_TOKEN} `, '')
|
.replaceAll(` ${NOSPACE_TOKEN} `, '')
|
||||||
|
|
||||||
|
|
@ -50,13 +50,16 @@ 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', () => {
|
||||||
|
|
|
||||||
48
src/compiler/tests/while.test.ts
Normal file
48
src/compiler/tests/while.test.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
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')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -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 [_keyword, conditional, _colon, thenBlock] = parts
|
const [_else, _if, 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 TryBlock or statement
|
// First child is always 'try' keyword, second is colon, third is Block
|
||||||
const [tryKeyword, _colon, tryBlock, ...rest] = children
|
const [tryKeyword, _colon, tryBlock, ...rest] = children
|
||||||
|
|
||||||
if (!tryKeyword || !tryBlock) {
|
if (!tryKeyword || !tryBlock) {
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,18 @@
|
||||||
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 }
|
||||||
|
|
||||||
|
|
@ -47,9 +56,9 @@ item {
|
||||||
newlineOrSemicolon // allow blank lines
|
newlineOrSemicolon // allow blank lines
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
consumeToTerminator {
|
consumeToTerminator {
|
||||||
PipeExpr |
|
PipeExpr |
|
||||||
|
WhileExpr |
|
||||||
FunctionCallWithBlock |
|
FunctionCallWithBlock |
|
||||||
ambiguousFunctionCall |
|
ambiguousFunctionCall |
|
||||||
TryExpr |
|
TryExpr |
|
||||||
|
|
@ -71,16 +80,16 @@ pipeOperand {
|
||||||
FunctionCall | FunctionCallOrIdentifier
|
FunctionCall | FunctionCallOrIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WhileExpr {
|
||||||
|
while (ConditionalOp | expression) colon Block end
|
||||||
|
}
|
||||||
|
|
||||||
|
Block {
|
||||||
|
consumeToTerminator | newlineOrSemicolon block
|
||||||
|
}
|
||||||
|
|
||||||
FunctionCallWithBlock {
|
FunctionCallWithBlock {
|
||||||
singleLineFunctionCallWithBlock | multiLineFunctionCallWithBlock
|
ambiguousFunctionCall colon Block CatchExpr? FinallyExpr? end
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
|
|
@ -99,7 +108,6 @@ arg {
|
||||||
PositionalArg | NamedArg
|
PositionalArg | NamedArg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PositionalArg {
|
PositionalArg {
|
||||||
expression | FunctionDef | Underscore
|
expression | FunctionDef | Underscore
|
||||||
}
|
}
|
||||||
|
|
@ -109,71 +117,35 @@ NamedArg {
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionDef {
|
FunctionDef {
|
||||||
singleLineFunctionDef | multilineFunctionDef
|
Do Params colon (consumeToTerminator | newlineOrSemicolon block) CatchExpr? FinallyExpr? end
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
singleLineIf | multilineIf
|
if (ConditionalOp | expression) colon Block ElseIfExpr* ElseExpr? end
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
@specialize[@name=keyword]<Identifier, "elseif"> (ConditionalOp | expression) colon newlineOrSemicolon ThenBlock
|
else if (ConditionalOp | expression) colon Block
|
||||||
}
|
}
|
||||||
|
|
||||||
ElseExpr {
|
ElseExpr {
|
||||||
@specialize[@name=keyword]<Identifier, "else"> colon newlineOrSemicolon ThenBlock
|
else colon Block
|
||||||
}
|
|
||||||
|
|
||||||
ThenBlock {
|
|
||||||
block
|
|
||||||
}
|
|
||||||
|
|
||||||
SingleLineThenBlock {
|
|
||||||
consumeToTerminator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TryExpr {
|
TryExpr {
|
||||||
singleLineTry | multilineTry
|
try colon Block CatchExpr? FinallyExpr? end
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
@specialize[@name=keyword]<Identifier, "catch"> Identifier colon (newlineOrSemicolon TryBlock | consumeToTerminator)
|
catch Identifier colon Block
|
||||||
}
|
}
|
||||||
|
|
||||||
FinallyExpr {
|
FinallyExpr {
|
||||||
@specialize[@name=keyword]<Identifier, "finally"> colon (newlineOrSemicolon TryBlock | consumeToTerminator)
|
finally colon Block
|
||||||
}
|
|
||||||
|
|
||||||
TryBlock {
|
|
||||||
block
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Throw {
|
Throw {
|
||||||
@specialize[@name=keyword]<Identifier, "throw"> (BinOp | ConditionalOp | expression)
|
throw (BinOp | ConditionalOp | expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
ConditionalOp {
|
ConditionalOp {
|
||||||
|
|
@ -192,7 +164,7 @@ Params {
|
||||||
}
|
}
|
||||||
|
|
||||||
NamedParam {
|
NamedParam {
|
||||||
NamedArgPrefix (String | Number | Boolean | @specialize[@name=Null]<Identifier, "null">)
|
NamedArgPrefix (String | Number | Boolean | null)
|
||||||
}
|
}
|
||||||
|
|
||||||
Assign {
|
Assign {
|
||||||
|
|
@ -230,7 +202,6 @@ expression {
|
||||||
}
|
}
|
||||||
|
|
||||||
String { "'" stringContent* "'" }
|
String { "'" stringContent* "'" }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stringContent {
|
stringContent {
|
||||||
|
|
@ -266,7 +237,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 | @specialize[@name=Null]<Identifier, "null">
|
ParenExpr | Word | String | Number | Boolean | Regex | Dict | Array | null
|
||||||
}
|
}
|
||||||
|
|
||||||
block {
|
block {
|
||||||
|
|
|
||||||
|
|
@ -47,20 +47,19 @@ export const
|
||||||
Null = 45,
|
Null = 45,
|
||||||
colon = 46,
|
colon = 46,
|
||||||
CatchExpr = 47,
|
CatchExpr = 47,
|
||||||
keyword = 70,
|
keyword = 68,
|
||||||
TryBlock = 49,
|
Block = 49,
|
||||||
FinallyExpr = 50,
|
FinallyExpr = 50,
|
||||||
Underscore = 53,
|
Underscore = 53,
|
||||||
Array = 54,
|
Array = 54,
|
||||||
ConditionalOp = 55,
|
ConditionalOp = 55,
|
||||||
PositionalArg = 56,
|
PositionalArg = 56,
|
||||||
FunctionCallWithBlock = 58,
|
WhileExpr = 58,
|
||||||
TryExpr = 59,
|
FunctionCallWithBlock = 60,
|
||||||
Throw = 61,
|
TryExpr = 61,
|
||||||
IfExpr = 63,
|
Throw = 63,
|
||||||
SingleLineThenBlock = 65,
|
IfExpr = 65,
|
||||||
ThenBlock = 66,
|
|
||||||
ElseIfExpr = 67,
|
ElseIfExpr = 67,
|
||||||
ElseExpr = 69,
|
ElseExpr = 69,
|
||||||
CompoundAssign = 71,
|
CompoundAssign = 70,
|
||||||
Assign = 72
|
Assign = 71
|
||||||
|
|
|
||||||
|
|
@ -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, try:120, throw:124, if:128, elseif:136, else:140}
|
const spec_Identifier = {__proto__:null,null:90, catch:96, finally:102, end:104, while:118, try:124, throw:128, if:132, else:136}
|
||||||
export const parser = LRParser.deserialize({
|
export const parser = LRParser.deserialize({
|
||||||
version: 14,
|
version: 14,
|
||||||
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}",
|
states: "9OQYQbOOO#zQcO'#C{O$zOSO'#C}OOQa'#DT'#DTO&TQbO'#DdO'iQcO'#E]OOQa'#E]'#E]O(lQcO'#E]O)nQcO'#E[O*UQRO'#C|O+eQcO'#EWO+uQcO'#EWO,PQbO'#CzO,wOpO'#CxOOQ`'#EX'#EXO,|QbO'#EWO-WQRO'#DtOOQ`'#EW'#EWO-lQQO'#EVOOQ`'#EV'#EVOOQ`'#Dv'#DvQYQbOOO-tQbO'#DWO.PQbO'#DhO.tQQO'#DkO.PQbO'#DmO.PQbO'#DoO.yQbO'#DUOOQa'#E['#E[OOQ`'#Df'#DfOOQ`'#Ek'#EkOOQ`'#EO'#EOO/TQbO,59cO/}QbO'#DPO0VQWO'#DQOOOO'#E_'#E_OOOO'#Dw'#DwO0kOSO,59iOOQa,59i,59iOOQ`'#Dx'#DxO0yQbO,5:OO1QQQO,59oOOQa,5:O,5:OO1]QbO,5:OO1gQbO,5:aO.PQbO,59hO.PQbO,59hO.PQbO,59hO.PQbO,5:PO.PQbO,5:PO.PQbO,5:PO1zQRO,59fO2RQRO,59fO2dQRO,59fO2_QQO,59fO2oQQO,59fO2wObO,59dO3SQbO'#EPO3_QbO,59bO3yQbO,5:UO1gQbO,5:`OOQ`,5:q,5:qOOQ`-E7t-E7tOOQ`'#Dy'#DyO4aQbO'#DXO4lQbO'#DYOOQO'#Dz'#DzO4dQQO'#DXO4zQQO,59rO5kQRO,5:SO5rQRO,5:SO3yQbO,5:VO5}QcO,5:XO6yQcO,5:XO7ZQcO,5:XO7eQRO,5:ZO7lQRO,5:ZOOQ`,59p,59pOOQ`-E7|-E7|OOOO,59k,59kOOOO,59l,59lOOOO-E7u-E7uOOQa1G/T1G/TOOQ`-E7v-E7vO7wQQO1G/ZOOQa1G/j1G/jO8SQbO1G/jOOQO'#D|'#D|O7wQQO1G/ZOOQa1G/Z1G/ZOOQ`'#D}'#D}O8SQbO1G/jOOQ`1G/{1G/{OOQa1G/S1G/SO9OQcO1G/SO9YQcO1G/SO9dQcO1G/SOOQa1G/k1G/kO;YQcO1G/kO;aQcO1G/kO;hQcO1G/kOOQa1G/Q1G/QOOQa1G/O1G/OO!dQbO'#C{O;oQbO'#CwOOQ`,5:k,5:kOOQ`-E7}-E7}OOQ`'#D_'#D_O;|QbO'#D_O<pQbO1G/pOOQ`1G/z1G/zOOQ`-E7w-E7wO<{QQO,59sOOQO,59t,59tOOQO-E7x-E7xO=TQbO1G/^O3yQbO1G/nO=kQbO1G/qO3yQbO1G/uO=vQQO7+$uOOQa7+$u7+$uO>RQbO7+%UOOQa7+%U7+%UOOQO-E7z-E7zOOQ`-E7{-E7{OOQ`'#D{'#D{O>]QQO'#D{O>bQbO'#EhOOQ`,59y,59yO?UQbO'#D]O?ZQQO'#D`OOQ`7+%[7+%[O?`QbO7+%[O?eQbO7+%[O?mQbO7+$xO?xQbO7+$xO@iQbO7+%YOOQ`7+%]7+%]O@nQbO7+%]O@sQbO7+%]O@{QbO7+%aOOQa<<Ha<<HaOOQa<<Hp<<HpOOQ`,5:g,5:gOOQ`-E7y-E7yOATQQO,59wO3yQbO,59zOOQ`<<Hv<<HvOAYQbO<<HvOOQ`<<Hd<<HdOA_QbO<<HdOAdQbO<<HdOAlQbO<<HdOOQ`<<Ht<<HtOOQ`<<Hw<<HwOAwQbO<<HwOOQ`'#EQ'#EQOA|QbO<<H{OBUQbO'#DsOOQ`<<H{<<H{OB^QbO<<H{O3yQbO1G/cOOQ`1G/f1G/fOOQ`AN>bAN>bOOQ`AN>OAN>OOBcQbOAN>OOBhQbOAN>OOOQ`AN>cAN>cOOQ`-E8O-E8OOOQ`AN>gAN>gOBpQbOAN>gO.PQbO,5:]O3yQbO,5:_OOQ`7+$}7+$}OOQ`G23jG23jOBuQbOG23jPBXQbO'#DqOOQ`G24RG24ROBzQRO1G/wOCRQRO1G/wOOQ`1G/y1G/yOOQ`LD)ULD)UO3yQbO7+%cOOQ`<<H}<<H}",
|
||||||
stateData: "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~",
|
stateData: "Ca~O!wOS!xOS~OdPOe`OfUOg]OhfOmUOuUOvUO}UO!]gO!`hO!biO!djO!}[O#QQO#XRO#YSO#ZcO~OdlOfUOg]OhfOmUOuUOvUOykO}UO!VmO!}[O#QQO#XRO#YSO!ZoX#ZoX#`oX#^oX!QoX!ToX!UoX!foX~OP#OXQ#OXR#OXS#OXT#OXU#OXW#OXX#OXY#OXZ#OX[#OX]#OX^#OX!OoX~P!dOrsO#QvO#SqO#TrO~OdlOfUOg]OmUOuUOvUOykO}UO!}[O#QQO#XRO#YSO#ZwO~O#]zO~P%YOP#PXQ#PXR#PXS#PXT#PXU#PXW#PXX#PXY#PXZ#PX[#PX]#PX^#PX#Z#PX#`#PX!Q#PX!T#PX!U#PX!f#PX~OdlOfUOg]OhfOmUOuUOvUOykO}UO!VmO!}[O#QQO#XRO#YSO#^#PX~P&[OV|O~P&[OP#OXQ#OXR#OXS#OXT#OXU#OXW#OXX#OXY#OXZ#OX[#OX]#OX^#OX~O#Z!zX#`!zX!Q!zX!T!zX!U!zX!f!zX~P(sOP!OOQ!OOR!POS!POT!ROU!SOW!QOX!QOY!QOZ!QO[!QO]!QO^}O~O#Z!zX#`!zX!Q!zX!T!zX!U!zX!f!zX~OP!OOQ!OOR!POS!PO~P+POT!ROU!SO~P+POdPOfUOg]OhfOmUOuUOvUO}UO!}[O#QQO#XRO#YSO~O!|!YO~O!O!]O!Z!ZO~P+POV|O_!^O`!^Oa!^Ob!^Oc!^O~O#Z!_O#`!_O~Od!aOy!cO!O{P~OdlOfUOg]OmUOuUOvUO}UO!}[O#QQO#XRO#YSO~O!O!iO~OhfO!V!oO~P.POhfOykO!VmO!Oka!Zka#Zka#`ka#^ka!Qka!Tka!Uka!fka~P.POd!qO!}[O~O#Q!rO#S!rO#T!rO#U!rO#V!rO#W!rO~OrsO#Q!tO#SqO#TrO~O#]!wO~P%YOykO#Z!yO#]!{O~O#Z!|O#]!wO~P.POe`O!]gO!`hO!biO!djO~P,PO#^#XO~P(sOP!OOQ!OOR!POS!PO#^#XO~OT!ROU!SO#^#XO~O!Z!ZO#^#XO~Od#YOm#YO!}[O~Od#ZOg]O!}[O~O!Z!ZO#Zja#`ja#^ja!Qja!Tja!Uja!fja~Oe`O!]gO!`hO!biO!djO#Z#`O~P,POd!aOy!cO!O{X~Om#eOu#eO}#eO#QQO~O!O#gO~OT!ROU!SOW!QOX!QOY!QOZ!QO[!QO]!QO~O!O#hO~P5POT!ROU!SO!O#hO~O#Z!aa#`!aa!Q!aa!T!aa!U!aa!f!aa~P*UO#Z!aa#`!aa!Q!aa!T!aa!U!aa!f!aa~OP!OOQ!OOR!POS!PO~P6eOT!ROU!SO~P6eO!O#jO~P5POT!ROU!SO!O#jO~OykO#Z!yO#]#lO~O#Z!|O#]#nO~P.PO^}ORpiSpi#Zpi#`pi#^pi!Qpi!Tpi!Upi!fpi~OPpiQpi~P8^OP!OOQ!OO~P8^OP!OOQ!OORpiSpi#Zpi#`pi#^pi!Qpi!Tpi!Upi!fpi~OW!QOX!QOY!QOZ!QO[!QO]!QOT!Xi#Z!Xi#`!Xi#^!Xi!O!Xi!Q!Xi!T!Xi!U!Xi!f!Xi~OU!SO~P:XOU!SO~P:kOU!Xi~P:XOhfOykO!VmO~P.POe`O!]gO!`hO!biO!djO#Z#qO!Q#[P!T#[P!U#[P!f#[P~P,PO!Q#uO!T#vO!U#wO~Oy!cO!O{a~Oe`O!]gO!`hO!biO!djO#Z#{O~P,PO!Q#uO!T#vO!U#}O~OykO#Z!yO#]$RO~O#Z!|O#]$SO~P.PO#Z$TO~Oe`O!]gO!`hO!biO!djO#Z#qO!Q#[X!T#[X!U#[X!f#[X~P,POd$VO~O!O$WO~O!U$XO~O!T#vO!U$XO~O!Q#uO!T#vO!U$ZO~Oe`O!]gO!`hO!biO!djO#Z#qO!Q#[P!T#[P!U#[P~P,PO!U$_O~O!U$`O~O!T#vO!U$`O~O!U$eO!f$dO~O!O$gO~O!U$iO~O!U$jO~O!T#vO!U$jO~O!Q#uO!T#vO!U$jO~O!U$mO~O!U$oO!f$dO~O!O$rO!d$qO~O!U$oO~O!U$tO~O!T#vO!U$tO~O!U$wO~O!U${O~O!O$|O~P5POT!ROU!SO!O$|O~Omv~",
|
||||||
goto: "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",
|
goto: "3}#`PPPPPPPPPPPPPPPPPPPPPPPPPP#a#v$[P%[#v&b'QP(O(OPP(S(}P)b*R*UPP*[P*h+QPPP+h,e-^P-eP-e-eP-eP-eP-wP-{-e-e.R.X._.e.k.u.|/W/b/k/rPPPP/x/|0jPP1S2mP3lPPPPPPPP3pPP3vpaOe|!]!^!i#`#g#h#j#s#{$W$g$r$|R!W[u^O[e|!Z!]!^!i#`#g#h#j#s#{$W$g$r$|rPO[e|!]!^!i#`#g#h#j#s#{$W$g$r$||lPSTgijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qR#Z!ZrTO[e|!]!^!i#`#g#h#j#s#{$W$g$r$||UPSTgijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qQ!qqQ#Y!YR#[!ZpYOe|!]!^!i#`#g#h#j#s#{$W$g$r$|Q!U[Q!kiQ#P!OR#S!P!pUOPST[egijkpx{|}!O!P!Q!R!S!]!^!i!x!}#Z#[#`#g#h#j#m#s#{$W$g$q$r$|R#e!cTsQu!qUOPST[egijkpx{|}!O!P!Q!R!S!]!^!i!x!}#Z#[#`#g#h#j#m#s#{$W$g$q$r$|YnPTp#Z#[QySQ!vxX!yy!v!z#kpaOe|!]!^!i#`#g#h#j#s#{$W$g$r$|YmPTp#Z#[Q!W[R!okR!ffX!df!b!e#dQ#y#aQ$P#iQ$]#zR$l$^Q#a!]Q#i!iQ#|#hQ$Q#jQ$h$WQ$s$gQ$z$rR$}$|Q#x#aQ$O#iQ$Y#yQ$[#zQ$a$PS$k$]$^R$u$l!OUPST[gijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qqVOe|!]!^!i#`#g#h#j#s#{$W$g$r$|pZOe|!]!^!i#`#g#h#j#s#{$W$g$r$|Q!V[Q!hgQ!liQ!njQ#T!SQ#V!RR$y$qZnPTp#Z#[qaOe|!]!^!i#`#g#h#j#s#{$W$g$r$|T$b$Q$cQ$f$QR$p$cQeOR!`eQuQR!suQxSR!uxQ!bfR#c!bQ!efQ#d!bT#f!e#dS#s#`#{R$U#sQ!zyQ#k!vT#o!z#kQ!}{Q#m!xT#p!}#mWpPT#Z#[R!ppS![_!XR#^![Q$c$QR$n$cTdOeSbOeQ#O|`#_!]!i#h#j$W$g$r$|Q#b!^U#r#`#s#{R#z#gp_Oe|!]!^!i#`#g#h#j#s#{$W$g$r$|Q!X[R#]!ZrXO[e|!]!^!i#`#g#h#j#s#{$W$g$r$|YmPTp#Z#[Q{SQ!ggQ!jiQ!mjQ!okQ!xxW!|{!x!}#mQ#P}Q#Q!OQ#R!PQ#T!QQ#U!RQ#W!SR$x$qpWOe|!]!^!i#`#g#h#j#s#{$W$g$r$||lPSTgijkpx{}!O!P!Q!R!S!x!}#Z#[#m$qR!T[TtQuQ#t#`R$^#{ZoPTp#Z#[",
|
||||||
nodeNames: "⚠ Star Slash Plus Minus And Or Eq EqEq Neq Lt Lte Gt Gte Modulo PlusEq MinusEq StarEq SlashEq ModuloEq Identifier AssignableIdentifier Word IdentifierBeforeDot Do Program PipeExpr FunctionCall DotGet Number ParenExpr FunctionCallOrIdentifier BinOp String StringFragment Interpolation EscapeSeq Boolean Regex Dict NamedArg NamedArgPrefix FunctionDef Params NamedParam Null colon CatchExpr keyword TryBlock FinallyExpr keyword keyword Underscore Array ConditionalOp PositionalArg operator FunctionCallWithBlock TryExpr keyword Throw keyword IfExpr keyword SingleLineThenBlock ThenBlock ElseIfExpr keyword ElseExpr keyword CompoundAssign Assign",
|
nodeNames: "⚠ Star Slash Plus Minus And Or Eq EqEq Neq Lt Lte Gt Gte Modulo PlusEq MinusEq StarEq SlashEq ModuloEq Identifier AssignableIdentifier Word IdentifierBeforeDot Do Program PipeExpr FunctionCall DotGet Number ParenExpr FunctionCallOrIdentifier BinOp String StringFragment Interpolation EscapeSeq Boolean Regex Dict NamedArg NamedArgPrefix FunctionDef Params NamedParam Null colon CatchExpr keyword Block FinallyExpr keyword keyword Underscore Array ConditionalOp PositionalArg operator WhileExpr keyword FunctionCallWithBlock TryExpr keyword Throw keyword IfExpr keyword ElseIfExpr keyword ElseExpr CompoundAssign Assign",
|
||||||
maxTerm: 117,
|
maxTerm: 108,
|
||||||
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!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~",
|
tokenData: "C_~R|OX#{XY$jYZ%TZp#{pq$jqs#{st%ntu'Vuw#{wx'[xy'ayz'zz{#{{|(e|}#{}!O+X!O!P#{!P!Q-n!Q![)S![!]6Z!]!^%T!^!}#{!}#O6t#O#P8j#P#Q8o#Q#R#{#R#S9Y#S#T#{#T#Y,Y#Y#Z9s#Z#b,Y#b#c>q#c#f,Y#f#g?n#g#h,Y#h#i@k#i#o,Y#o#p#{#p#qBo#q;'S#{;'S;=`$d<%l~#{~O#{~~CYS$QUrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{S$gP;=`<%l#{^$qUrS!wYOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U%[UrS#ZQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{^%uZrS!xYOY%nYZ#{Zt%ntu&huw%nwx&hx#O%n#O#P&h#P;'S%n;'S;=`'P<%lO%nY&mS!xYOY&hZ;'S&h;'S;=`&y<%lO&hY&|P;=`<%l&h^'SP;=`<%l%n~'[O#S~~'aO#Q~U'hUrS!}QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(RUrS#^QOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U(jWrSOt#{uw#{x!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U)ZYrSmQOt#{uw#{x!O#{!O!P)y!P!Q#{!Q![)S![#O#{#P;'S#{;'S;=`$d<%lO#{U*OWrSOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U*oWrSmQOt#{uw#{x!Q#{!Q![*h![#O#{#P;'S#{;'S;=`$d<%lO#{U+^^rSOt#{uw#{x}#{}!O,Y!O!Q#{!Q![)S![!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{U,_[rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{U-[UyQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U-sWrSOt#{uw#{x!P#{!P!Q.]!Q#O#{#P;'S#{;'S;=`$d<%lO#{U.b^rSOY/^YZ#{Zt/^tu0auw/^wx0ax!P/^!P!Q#{!Q!}/^!}#O5S#O#P2o#P;'S/^;'S;=`6T<%lO/^U/e^rSvQOY/^YZ#{Zt/^tu0auw/^wx0ax!P/^!P!Q3U!Q!}/^!}#O5S#O#P2o#P;'S/^;'S;=`6T<%lO/^Q0fXvQOY0aZ!P0a!P!Q1R!Q!}0a!}#O1p#O#P2o#P;'S0a;'S;=`3O<%lO0aQ1UP!P!Q1XQ1^UvQ#Z#[1X#]#^1X#a#b1X#g#h1X#i#j1X#m#n1XQ1sVOY1pZ#O1p#O#P2Y#P#Q0a#Q;'S1p;'S;=`2i<%lO1pQ2]SOY1pZ;'S1p;'S;=`2i<%lO1pQ2lP;=`<%l1pQ2rSOY0aZ;'S0a;'S;=`3O<%lO0aQ3RP;=`<%l0aU3ZWrSOt#{uw#{x!P#{!P!Q3s!Q#O#{#P;'S#{;'S;=`$d<%lO#{U3zbrSvQOt#{uw#{x#O#{#P#Z#{#Z#[3s#[#]#{#]#^3s#^#a#{#a#b3s#b#g#{#g#h3s#h#i#{#i#j3s#j#m#{#m#n3s#n;'S#{;'S;=`$d<%lO#{U5X[rSOY5SYZ#{Zt5Stu1puw5Swx1px#O5S#O#P2Y#P#Q/^#Q;'S5S;'S;=`5}<%lO5SU6QP;=`<%l5SU6WP;=`<%l/^U6bUrS!OQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U6{W#YQrSOt#{uw#{x!_#{!_!`7e!`#O#{#P;'S#{;'S;=`$d<%lO#{U7jVrSOt#{uw#{x#O#{#P#Q8P#Q;'S#{;'S;=`$d<%lO#{U8WU#XQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~8oO#T~U8vU#]QrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9aUrS!VQOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{U9x]rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#U:q#U#o,Y#o;'S#{;'S;=`$d<%lO#{U:v^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#`,Y#`#a;r#a#o,Y#o;'S#{;'S;=`$d<%lO#{U;w^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#g,Y#g#h<s#h#o,Y#o;'S#{;'S;=`$d<%lO#{U<x^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#X,Y#X#Y=t#Y#o,Y#o;'S#{;'S;=`$d<%lO#{U={[uQrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^>x[#UWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^?u[#WWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#o,Y#o;'S#{;'S;=`$d<%lO#{^@r^#VWrSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#f,Y#f#gAn#g#o,Y#o;'S#{;'S;=`$d<%lO#{UAs^rSOt#{uw#{x}#{}!O,Y!O!_#{!_!`-T!`#O#{#P#T#{#T#i,Y#i#j<s#j#o,Y#o;'S#{;'S;=`$d<%lO#{UBvU!ZQrSOt#{uw#{x#O#{#P;'S#{;'S;=`$d<%lO#{~C_O#`~",
|
||||||
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!}~~", 11)],
|
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: 1705
|
tokenPrec: 1578
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -752,7 +752,7 @@ Assign
|
||||||
EqEq ==
|
EqEq ==
|
||||||
Number 5
|
Number 5
|
||||||
colon :
|
colon :
|
||||||
ThenBlock
|
Block
|
||||||
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 :
|
||||||
ThenBlock
|
Block
|
||||||
Boolean true
|
Boolean true
|
||||||
keyword end
|
keyword end
|
||||||
keyword end
|
keyword end
|
||||||
|
|
|
||||||
|
|
@ -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/elseif/else', () => {
|
describe('if/else if/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/elseif/else', () => {
|
||||||
EqEq ==
|
EqEq ==
|
||||||
Number 1
|
Number 1
|
||||||
colon :
|
colon :
|
||||||
SingleLineThenBlock
|
Block
|
||||||
String
|
String
|
||||||
StringFragment cool
|
StringFragment cool
|
||||||
keyword end
|
keyword end
|
||||||
|
|
@ -26,7 +26,7 @@ describe('if/elseif/else', () => {
|
||||||
keyword if
|
keyword if
|
||||||
Identifier x
|
Identifier x
|
||||||
colon :
|
colon :
|
||||||
SingleLineThenBlock
|
Block
|
||||||
Number 2
|
Number 2
|
||||||
keyword end
|
keyword end
|
||||||
`)
|
`)
|
||||||
|
|
@ -44,7 +44,7 @@ describe('if/elseif/else', () => {
|
||||||
Lt <
|
Lt <
|
||||||
Number 9
|
Number 9
|
||||||
colon :
|
colon :
|
||||||
ThenBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier yes
|
Identifier yes
|
||||||
keyword end
|
keyword end
|
||||||
|
|
@ -61,78 +61,81 @@ describe('if/elseif/else', () => {
|
||||||
keyword if
|
keyword if
|
||||||
Identifier with-else
|
Identifier with-else
|
||||||
colon :
|
colon :
|
||||||
ThenBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier x
|
Identifier x
|
||||||
ElseExpr
|
ElseExpr
|
||||||
keyword else
|
keyword else
|
||||||
colon :
|
colon :
|
||||||
ThenBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier y
|
Identifier y
|
||||||
keyword end
|
keyword end
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('parses multiline if with elseif', () => {
|
test('parses multiline if with else if', () => {
|
||||||
expect(`if with-elseif:
|
expect(`if with-else-if:
|
||||||
x
|
x
|
||||||
elseif another-condition:
|
else if another-condition:
|
||||||
y
|
y
|
||||||
end`).toMatchTree(`
|
end`).toMatchTree(`
|
||||||
IfExpr
|
IfExpr
|
||||||
keyword if
|
keyword if
|
||||||
Identifier with-elseif
|
Identifier with-else-if
|
||||||
colon :
|
colon :
|
||||||
ThenBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier x
|
Identifier x
|
||||||
ElseIfExpr
|
ElseIfExpr
|
||||||
keyword elseif
|
keyword else
|
||||||
|
keyword if
|
||||||
Identifier another-condition
|
Identifier another-condition
|
||||||
colon :
|
colon :
|
||||||
ThenBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier y
|
Identifier y
|
||||||
keyword end
|
keyword end
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('parses multiline if with multiple elseif and else', () => {
|
test('parses multiline if with multiple else if and else', () => {
|
||||||
expect(`if with-elseif-else:
|
expect(`if with-else-if-else:
|
||||||
x
|
x
|
||||||
elseif another-condition:
|
else if another-condition:
|
||||||
y
|
y
|
||||||
elseif yet-another-condition:
|
else if yet-another-condition:
|
||||||
z
|
z
|
||||||
else:
|
else:
|
||||||
oh-no
|
oh-no
|
||||||
end`).toMatchTree(`
|
end`).toMatchTree(`
|
||||||
IfExpr
|
IfExpr
|
||||||
keyword if
|
keyword if
|
||||||
Identifier with-elseif-else
|
Identifier with-else-if-else
|
||||||
colon :
|
colon :
|
||||||
ThenBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier x
|
Identifier x
|
||||||
ElseIfExpr
|
ElseIfExpr
|
||||||
keyword elseif
|
keyword else
|
||||||
|
keyword if
|
||||||
Identifier another-condition
|
Identifier another-condition
|
||||||
colon :
|
colon :
|
||||||
ThenBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier y
|
Identifier y
|
||||||
ElseIfExpr
|
ElseIfExpr
|
||||||
keyword elseif
|
keyword else
|
||||||
|
keyword if
|
||||||
Identifier yet-another-condition
|
Identifier yet-another-condition
|
||||||
colon :
|
colon :
|
||||||
ThenBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier z
|
Identifier z
|
||||||
ElseExpr
|
ElseExpr
|
||||||
keyword else
|
keyword else
|
||||||
colon :
|
colon :
|
||||||
ThenBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier oh-no
|
Identifier oh-no
|
||||||
keyword end
|
keyword end
|
||||||
|
|
@ -148,9 +151,124 @@ describe('if/elseif/else', () => {
|
||||||
keyword if
|
keyword if
|
||||||
Boolean true
|
Boolean true
|
||||||
colon :
|
colon :
|
||||||
SingleLineThenBlock
|
Block
|
||||||
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`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -12,14 +12,14 @@ describe('try/catch/finally/throw', () => {
|
||||||
TryExpr
|
TryExpr
|
||||||
keyword try
|
keyword try
|
||||||
colon :
|
colon :
|
||||||
TryBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier risky-operation
|
Identifier risky-operation
|
||||||
CatchExpr
|
CatchExpr
|
||||||
keyword catch
|
keyword catch
|
||||||
Identifier err
|
Identifier err
|
||||||
colon :
|
colon :
|
||||||
TryBlock
|
Block
|
||||||
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 :
|
||||||
TryBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier do-work
|
Identifier do-work
|
||||||
FinallyExpr
|
FinallyExpr
|
||||||
keyword finally
|
keyword finally
|
||||||
colon :
|
colon :
|
||||||
TryBlock
|
Block
|
||||||
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 :
|
||||||
TryBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier risky-operation
|
Identifier risky-operation
|
||||||
CatchExpr
|
CatchExpr
|
||||||
keyword catch
|
keyword catch
|
||||||
Identifier err
|
Identifier err
|
||||||
colon :
|
colon :
|
||||||
TryBlock
|
Block
|
||||||
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 :
|
||||||
TryBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier cleanup
|
Identifier cleanup
|
||||||
keyword end
|
keyword end
|
||||||
|
|
@ -91,15 +91,17 @@ describe('try/catch/finally/throw', () => {
|
||||||
TryExpr
|
TryExpr
|
||||||
keyword try
|
keyword try
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier parse-number
|
FunctionCall
|
||||||
PositionalArg
|
Identifier parse-number
|
||||||
Identifier input
|
PositionalArg
|
||||||
|
Identifier input
|
||||||
CatchExpr
|
CatchExpr
|
||||||
keyword catch
|
keyword catch
|
||||||
Identifier err
|
Identifier err
|
||||||
colon :
|
colon :
|
||||||
Number 0
|
Block
|
||||||
|
Number 0
|
||||||
keyword end
|
keyword end
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
@ -109,18 +111,21 @@ describe('try/catch/finally/throw', () => {
|
||||||
TryExpr
|
TryExpr
|
||||||
keyword try
|
keyword try
|
||||||
colon :
|
colon :
|
||||||
FunctionCallOrIdentifier
|
Block
|
||||||
Identifier work
|
FunctionCallOrIdentifier
|
||||||
|
Identifier work
|
||||||
CatchExpr
|
CatchExpr
|
||||||
keyword catch
|
keyword catch
|
||||||
Identifier err
|
Identifier err
|
||||||
colon :
|
colon :
|
||||||
Number 0
|
Block
|
||||||
|
Number 0
|
||||||
FinallyExpr
|
FinallyExpr
|
||||||
keyword finally
|
keyword finally
|
||||||
colon :
|
colon :
|
||||||
FunctionCallOrIdentifier
|
Block
|
||||||
Identifier cleanup
|
FunctionCallOrIdentifier
|
||||||
|
Identifier cleanup
|
||||||
keyword end
|
keyword end
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
@ -164,13 +169,15 @@ describe('try/catch/finally/throw', () => {
|
||||||
TryExpr
|
TryExpr
|
||||||
keyword try
|
keyword try
|
||||||
colon :
|
colon :
|
||||||
FunctionCallOrIdentifier
|
Block
|
||||||
Identifier work
|
FunctionCallOrIdentifier
|
||||||
|
Identifier work
|
||||||
CatchExpr
|
CatchExpr
|
||||||
keyword catch
|
keyword catch
|
||||||
Identifier err
|
Identifier err
|
||||||
colon :
|
colon :
|
||||||
Number 0
|
Block
|
||||||
|
Number 0
|
||||||
keyword end
|
keyword end
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
@ -199,7 +206,7 @@ describe('function-level exception handling', () => {
|
||||||
keyword catch
|
keyword catch
|
||||||
Identifier e
|
Identifier e
|
||||||
colon :
|
colon :
|
||||||
TryBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier empty-string
|
Identifier empty-string
|
||||||
keyword end
|
keyword end
|
||||||
|
|
@ -227,7 +234,7 @@ describe('function-level exception handling', () => {
|
||||||
FinallyExpr
|
FinallyExpr
|
||||||
keyword finally
|
keyword finally
|
||||||
colon :
|
colon :
|
||||||
TryBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier close-resources
|
Identifier close-resources
|
||||||
keyword end
|
keyword end
|
||||||
|
|
@ -259,7 +266,7 @@ describe('function-level exception handling', () => {
|
||||||
keyword catch
|
keyword catch
|
||||||
Identifier err
|
Identifier err
|
||||||
colon :
|
colon :
|
||||||
TryBlock
|
Block
|
||||||
FunctionCall
|
FunctionCall
|
||||||
Identifier log
|
Identifier log
|
||||||
PositionalArg
|
PositionalArg
|
||||||
|
|
@ -269,7 +276,7 @@ describe('function-level exception handling', () => {
|
||||||
FinallyExpr
|
FinallyExpr
|
||||||
keyword finally
|
keyword finally
|
||||||
colon :
|
colon :
|
||||||
TryBlock
|
Block
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier cleanup
|
Identifier cleanup
|
||||||
keyword end
|
keyword end
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,13 @@ describe('single line function blocks', () => {
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier trap
|
Identifier trap
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier echo
|
FunctionCall
|
||||||
PositionalArg
|
Identifier echo
|
||||||
Identifier bye
|
PositionalArg
|
||||||
PositionalArg
|
Identifier bye
|
||||||
Identifier bye
|
PositionalArg
|
||||||
|
Identifier bye
|
||||||
keyword end`
|
keyword end`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -27,12 +28,13 @@ describe('single line function blocks', () => {
|
||||||
PositionalArg
|
PositionalArg
|
||||||
Word EXIT
|
Word EXIT
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier echo
|
FunctionCall
|
||||||
PositionalArg
|
Identifier echo
|
||||||
Identifier bye
|
PositionalArg
|
||||||
PositionalArg
|
Identifier bye
|
||||||
Identifier bye
|
PositionalArg
|
||||||
|
Identifier bye
|
||||||
keyword end`
|
keyword end`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -47,12 +49,13 @@ describe('single line function blocks', () => {
|
||||||
String
|
String
|
||||||
StringFragment exit
|
StringFragment exit
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier echo
|
FunctionCall
|
||||||
PositionalArg
|
Identifier echo
|
||||||
Identifier bye
|
PositionalArg
|
||||||
PositionalArg
|
Identifier bye
|
||||||
Identifier bye
|
PositionalArg
|
||||||
|
Identifier bye
|
||||||
keyword end`
|
keyword end`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -73,12 +76,13 @@ describe('single line function blocks', () => {
|
||||||
String
|
String
|
||||||
StringFragment EXIT
|
StringFragment EXIT
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier echo
|
FunctionCall
|
||||||
PositionalArg
|
Identifier echo
|
||||||
Identifier bye
|
PositionalArg
|
||||||
PositionalArg
|
Identifier bye
|
||||||
Identifier bye
|
PositionalArg
|
||||||
|
Identifier bye
|
||||||
keyword end`
|
keyword end`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -95,12 +99,13 @@ end
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier trap
|
Identifier trap
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier echo
|
FunctionCall
|
||||||
PositionalArg
|
Identifier echo
|
||||||
Identifier bye
|
PositionalArg
|
||||||
PositionalArg
|
Identifier bye
|
||||||
Identifier bye
|
PositionalArg
|
||||||
|
Identifier bye
|
||||||
keyword end`
|
keyword end`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -116,12 +121,13 @@ end`).toMatchTree(`
|
||||||
PositionalArg
|
PositionalArg
|
||||||
Word EXIT
|
Word EXIT
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier echo
|
FunctionCall
|
||||||
PositionalArg
|
Identifier echo
|
||||||
Identifier bye
|
PositionalArg
|
||||||
PositionalArg
|
Identifier bye
|
||||||
Identifier bye
|
PositionalArg
|
||||||
|
Identifier bye
|
||||||
keyword end`
|
keyword end`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -142,12 +148,13 @@ end`).toMatchTree(`
|
||||||
NamedArgPrefix code=
|
NamedArgPrefix code=
|
||||||
Number 1
|
Number 1
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier echo
|
FunctionCall
|
||||||
PositionalArg
|
Identifier echo
|
||||||
Identifier bye
|
PositionalArg
|
||||||
PositionalArg
|
Identifier bye
|
||||||
Identifier bye
|
PositionalArg
|
||||||
|
Identifier bye
|
||||||
keyword end`
|
keyword end`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -172,12 +179,13 @@ end`).toMatchTree(`
|
||||||
String
|
String
|
||||||
StringFragment EXIT
|
StringFragment EXIT
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier echo
|
FunctionCall
|
||||||
PositionalArg
|
Identifier echo
|
||||||
Identifier bye
|
PositionalArg
|
||||||
PositionalArg
|
Identifier bye
|
||||||
Identifier bye
|
PositionalArg
|
||||||
|
Identifier bye
|
||||||
keyword end`
|
keyword end`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -195,26 +203,27 @@ end`).toMatchTree(`
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier head
|
Identifier head
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier title
|
FunctionCall
|
||||||
PositionalArg
|
Identifier title
|
||||||
Word What
|
PositionalArg
|
||||||
PositionalArg
|
Word What
|
||||||
Identifier up
|
PositionalArg
|
||||||
FunctionCall
|
Identifier up
|
||||||
Identifier meta
|
FunctionCall
|
||||||
PositionalArg
|
Identifier meta
|
||||||
Word charSet=UTF-8
|
PositionalArg
|
||||||
FunctionCall
|
Word charSet=UTF-8
|
||||||
Identifier meta
|
FunctionCall
|
||||||
NamedArg
|
Identifier meta
|
||||||
NamedArgPrefix name=
|
NamedArg
|
||||||
String
|
NamedArgPrefix name=
|
||||||
StringFragment viewport
|
String
|
||||||
NamedArg
|
StringFragment viewport
|
||||||
NamedArgPrefix content=
|
NamedArg
|
||||||
String
|
NamedArgPrefix content=
|
||||||
StringFragment width=device-width, initial-scale=1, viewport-fit=cover
|
String
|
||||||
|
StringFragment width=device-width, initial-scale=1, viewport-fit=cover
|
||||||
keyword end
|
keyword end
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
@ -230,22 +239,23 @@ end`).toMatchTree(`
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier list
|
Identifier list
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier li
|
FunctionCall
|
||||||
NamedArg
|
Identifier li
|
||||||
NamedArgPrefix border-bottom=
|
NamedArg
|
||||||
String
|
NamedArgPrefix border-bottom=
|
||||||
StringFragment 1px solid black
|
String
|
||||||
PositionalArg
|
StringFragment 1px solid black
|
||||||
Identifier one
|
PositionalArg
|
||||||
FunctionCall
|
Identifier one
|
||||||
Identifier li
|
FunctionCall
|
||||||
PositionalArg
|
Identifier li
|
||||||
Identifier two
|
PositionalArg
|
||||||
FunctionCall
|
Identifier two
|
||||||
Identifier li
|
FunctionCall
|
||||||
PositionalArg
|
Identifier li
|
||||||
Identifier three
|
PositionalArg
|
||||||
|
Identifier three
|
||||||
keyword end`)
|
keyword end`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -260,33 +270,34 @@ end`)
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier p
|
Identifier p
|
||||||
colon :
|
colon :
|
||||||
FunctionCall
|
Block
|
||||||
Identifier h1
|
FunctionCall
|
||||||
NamedArg
|
Identifier h1
|
||||||
NamedArgPrefix class=
|
NamedArg
|
||||||
Identifier bright
|
NamedArgPrefix class=
|
||||||
NamedArg
|
Identifier bright
|
||||||
NamedArgPrefix style=
|
NamedArg
|
||||||
String
|
NamedArgPrefix style=
|
||||||
StringFragment font-family: helvetica
|
String
|
||||||
PositionalArg
|
StringFragment font-family: helvetica
|
||||||
Word Heya
|
PositionalArg
|
||||||
FunctionCall
|
Word Heya
|
||||||
Identifier h2
|
FunctionCall
|
||||||
PositionalArg
|
Identifier h2
|
||||||
Identifier man
|
PositionalArg
|
||||||
PositionalArg
|
Identifier man
|
||||||
Identifier that
|
PositionalArg
|
||||||
PositionalArg
|
Identifier that
|
||||||
Identifier is
|
PositionalArg
|
||||||
PositionalArg
|
Identifier is
|
||||||
ParenExpr
|
PositionalArg
|
||||||
FunctionCall
|
ParenExpr
|
||||||
Identifier b
|
FunctionCall
|
||||||
PositionalArg
|
Identifier b
|
||||||
Identifier wild
|
PositionalArg
|
||||||
PositionalArg
|
Identifier wild
|
||||||
Word !
|
PositionalArg
|
||||||
|
Word !
|
||||||
keyword end`)
|
keyword end`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
Loading…
Reference in New Issue
Block a user