Compare commits
5 Commits
0aeaed60c3
...
0d631ccf84
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d631ccf84 | |||
| 2fa432ea3f | |||
| 78849c7d36 | |||
| f31be80bb0 | |||
| 789481f4ef |
|
|
@ -238,11 +238,31 @@ export class Compiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
case terms.Assign: {
|
case terms.Assign: {
|
||||||
const { identifier, right } = getAssignmentParts(node)
|
const assignParts = getAssignmentParts(node)
|
||||||
const instructions: ProgramItem[] = []
|
const instructions: ProgramItem[] = []
|
||||||
instructions.push(...this.#compileNode(right, input))
|
|
||||||
instructions.push(['DUP']) // Keep a copy on the stack after storing
|
// right-hand side
|
||||||
const identifierName = input.slice(identifier.from, identifier.to)
|
instructions.push(...this.#compileNode(assignParts.right, input))
|
||||||
|
|
||||||
|
// array destructuring: [ a b ] = [ 1 2 3 4 ]
|
||||||
|
if ('arrayPattern' in assignParts) {
|
||||||
|
const identifiers = assignParts.arrayPattern ?? []
|
||||||
|
if (identifiers.length === 0) return instructions
|
||||||
|
|
||||||
|
for (let i = 0; i < identifiers.length; i++) {
|
||||||
|
instructions.push(['DUP'])
|
||||||
|
instructions.push(['PUSH', i])
|
||||||
|
instructions.push(['DOT_GET'])
|
||||||
|
instructions.push(['STORE', input.slice(identifiers[i]!.from, identifiers[i]!.to)])
|
||||||
|
}
|
||||||
|
|
||||||
|
// original array still on stack as the return value
|
||||||
|
return instructions
|
||||||
|
}
|
||||||
|
|
||||||
|
// simple assignment: x = value
|
||||||
|
instructions.push(['DUP'])
|
||||||
|
const identifierName = input.slice(assignParts.identifier.from, assignParts.identifier.to)
|
||||||
instructions.push(['STORE', identifierName])
|
instructions.push(['STORE', identifierName])
|
||||||
|
|
||||||
return instructions
|
return instructions
|
||||||
|
|
|
||||||
|
|
@ -64,36 +64,26 @@ describe('compiler', () => {
|
||||||
expect('sum = 2 + 3; sum').toEvaluateTo(5)
|
expect('sum = 2 + 3; sum').toEvaluateTo(5)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('compound assignment +=', () => {
|
test('array destructuring with two variables', () => {
|
||||||
expect('x = 10; x += 5; x').toEvaluateTo(15)
|
expect('[ a b ] = [ 1 2 3 4 ]; a').toEvaluateTo(1)
|
||||||
|
expect('[ a b ] = [ 1 2 3 4 ]; b').toEvaluateTo(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('compound assignment -= ', () => {
|
test('array destructuring with one variable', () => {
|
||||||
expect('x = 10; x -= 3; x').toEvaluateTo(7)
|
expect('[ x ] = [ 42 ]; x').toEvaluateTo(42)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('compound assignment *=', () => {
|
test('array destructuring with missing elements assigns null', () => {
|
||||||
expect('x = 5; x *= 3; x').toEvaluateTo(15)
|
expect('[ a b c ] = [ 1 2 ]; c').toEvaluateTo(null)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('compound assignment /=', () => {
|
test('array destructuring returns the original array', () => {
|
||||||
expect('x = 20; x /= 4; x').toEvaluateTo(5)
|
expect('[ a b ] = [ 1 2 3 4 ]').toEvaluateTo([1, 2, 3, 4])
|
||||||
})
|
})
|
||||||
|
|
||||||
test('compound assignment %=', () => {
|
test('array destructuring with emoji identifiers', () => {
|
||||||
expect('x = 17; x %= 5; x').toEvaluateTo(2)
|
expect('[ 🚀 💎 ] = [ 1 2 ]; 🚀').toEvaluateTo(1)
|
||||||
})
|
expect('[ 🚀 💎 ] = [ 1 2 ]; 💎').toEvaluateTo(2)
|
||||||
|
|
||||||
test('compound assignment with expression', () => {
|
|
||||||
expect('x = 10; x += 2 + 3; x').toEvaluateTo(15)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('compound assignment returns value', () => {
|
|
||||||
expect('x = 5; x += 10; x').toEvaluateTo(15)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('compound assignment fails on undefined variable', () => {
|
|
||||||
expect('undefined-var += 5').toFailEvaluation()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('parentheses', () => {
|
test('parentheses', () => {
|
||||||
|
|
|
||||||
|
|
@ -40,15 +40,23 @@ export const getAssignmentParts = (node: SyntaxNode) => {
|
||||||
const children = getAllChildren(node)
|
const children = getAllChildren(node)
|
||||||
const [left, equals, right] = children
|
const [left, equals, right] = children
|
||||||
|
|
||||||
if (!left || left.type.id !== terms.AssignableIdentifier) {
|
if (!equals || !right) {
|
||||||
throw new CompilerError(
|
throw new CompilerError(
|
||||||
`Assign left child must be an AssignableIdentifier, got ${left ? left.type.name : 'none'}`,
|
`Assign expected 3 children, got ${children.length}`,
|
||||||
node.from,
|
node.from,
|
||||||
node.to
|
node.to
|
||||||
)
|
)
|
||||||
} else if (!equals || !right) {
|
}
|
||||||
|
|
||||||
|
// array destructuring
|
||||||
|
if (left && left.type.id === terms.Array) {
|
||||||
|
const identifiers = getAllChildren(left).filter(child => child.type.id === terms.Identifier)
|
||||||
|
return { arrayPattern: identifiers, right }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!left || left.type.id !== terms.AssignableIdentifier) {
|
||||||
throw new CompilerError(
|
throw new CompilerError(
|
||||||
`Assign expected 3 children, got ${children.length}`,
|
`Assign left child must be an AssignableIdentifier or Array, got ${left ? left.type.name : 'none'}`,
|
||||||
node.from,
|
node.from,
|
||||||
node.to
|
node.to
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { ContextTracker, InputStream } from '@lezer/lr'
|
||||||
import * as terms from './shrimp.terms'
|
import * as terms from './shrimp.terms'
|
||||||
|
|
||||||
export class Scope {
|
export class Scope {
|
||||||
constructor(public parent: Scope | null, public vars = new Set<string>()) {}
|
constructor(public parent: Scope | null, public vars = new Set<string>()) { }
|
||||||
|
|
||||||
has(name: string): boolean {
|
has(name: string): boolean {
|
||||||
return this.vars.has(name) || (this.parent?.has(name) ?? false)
|
return this.vars.has(name) || (this.parent?.has(name) ?? false)
|
||||||
|
|
@ -42,7 +42,7 @@ export class Scope {
|
||||||
|
|
||||||
// Tracker context that combines Scope with temporary pending identifiers
|
// Tracker context that combines Scope with temporary pending identifiers
|
||||||
class TrackerContext {
|
class TrackerContext {
|
||||||
constructor(public scope: Scope, public pendingIds: string[] = []) {}
|
constructor(public scope: Scope, public pendingIds: string[] = []) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract identifier text from input stream
|
// Extract identifier text from input stream
|
||||||
|
|
@ -75,6 +75,12 @@ export const trackScope = new ContextTracker<TrackerContext>({
|
||||||
return new TrackerContext(context.scope, [...context.pendingIds, text])
|
return new TrackerContext(context.scope, [...context.pendingIds, text])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track identifiers in array destructuring: [ a b ] = ...
|
||||||
|
if (!inParams && term === terms.Identifier && isArrayDestructuring(input)) {
|
||||||
|
const text = readIdentifierText(input, input.pos, stack.pos)
|
||||||
|
return new TrackerContext(Scope.add(context.scope, text), context.pendingIds)
|
||||||
|
}
|
||||||
|
|
||||||
return context
|
return context
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -98,3 +104,26 @@ export const trackScope = new ContextTracker<TrackerContext>({
|
||||||
|
|
||||||
hash: (context) => context.scope.hash(),
|
hash: (context) => context.scope.hash(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Check if we're parsing array destructuring: [ a b ] = ...
|
||||||
|
const isArrayDestructuring = (input: InputStream): boolean => {
|
||||||
|
let pos = 0
|
||||||
|
|
||||||
|
// Find closing bracket
|
||||||
|
while (pos < 200 && input.peek(pos) !== 93 /* ] */) {
|
||||||
|
if (input.peek(pos) === -1) return false // EOF
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.peek(pos) !== 93 /* ] */) return false
|
||||||
|
pos++
|
||||||
|
|
||||||
|
// Skip whitespace
|
||||||
|
while (input.peek(pos) === 32 /* space */ ||
|
||||||
|
input.peek(pos) === 9 /* tab */ ||
|
||||||
|
input.peek(pos) === 10 /* \n */) {
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
|
||||||
|
return input.peek(pos) === 61 /* = */
|
||||||
|
}
|
||||||
|
|
@ -179,7 +179,7 @@ Params {
|
||||||
}
|
}
|
||||||
|
|
||||||
Assign {
|
Assign {
|
||||||
AssignableIdentifier Eq consumeToTerminator
|
(AssignableIdentifier | Array) Eq consumeToTerminator
|
||||||
}
|
}
|
||||||
|
|
||||||
CompoundAssign {
|
CompoundAssign {
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ import {highlighting} from "./highlight"
|
||||||
const spec_Identifier = {__proto__:null,catch:92, finally:98, end:100, null:106, try:116, throw:120, if:124, elseif:132, else:136}
|
const spec_Identifier = {__proto__:null,catch:92, finally:98, end:100, null:106, try:116, throw:120, if:124, elseif:132, else:136}
|
||||||
export const parser = LRParser.deserialize({
|
export const parser = LRParser.deserialize({
|
||||||
version: 14,
|
version: 14,
|
||||||
states: "9UQYQbOOO#tQcO'#C{O$qOSO'#C}O%PQbO'#EfOOQ`'#DW'#DWOOQa'#DT'#DTO&SQbO'#DbO'XQcO'#EZOOQa'#EZ'#EZO)cQcO'#EYO)vQRO'#C|O+SQcO'#EUO+dQcO'#EUO+nQbO'#CzO,fOpO'#CxOOQ`'#EV'#EVO,kQbO'#EUO,rQQO'#ElOOQ`'#Dg'#DgO,wQbO'#DiO,wQbO'#EnOOQ`'#Dk'#DkO-lQRO'#DsOOQ`'#EU'#EUO.QQQO'#ETOOQ`'#ET'#ETOOQ`'#Du'#DuQYQbOOO.YQbO'#DUOOQa'#EY'#EYOOQ`'#De'#DeOOQ`'#Ek'#EkOOQ`'#D|'#D|O.dQbO,59cO.}QbO'#DPO/VQWO'#DQOOOO'#E]'#E]OOOO'#Dv'#DvO/kOSO,59iOOQa,59i,59iOOQ`'#Dx'#DxO/yQbO'#DXO0RQQO,5;QOOQ`'#Dw'#DwO0WQbO,59|O0_QQO,59oOOQa,59|,59|O0jQbO,59|O,wQbO,59hO,wQbO,59hO,wQbO,59hO,wQbO,5:OO,wQbO,5:OO,wQbO,5:OO0tQRO,59fO0{QRO,59fO1^QRO,59fO1XQQO,59fO1iQQO,59fO1qObO,59dO1|QbO'#D}O2XQbO,59bO2pQbO,5;WO3TQcO,5:TO3yQcO,5:TO4ZQcO,5:TO5PQRO,5;YO5WQRO,5;YO5cQbO,5:_O5cQbO,5:`OOQ`,5:o,5:oOOQ`-E7s-E7sOOQ`,59p,59pOOQ`-E7z-E7zOOOO,59k,59kOOOO,59l,59lOOOO-E7t-E7tOOQa1G/T1G/TOOQ`-E7v-E7vO5sQbO1G0lOOQ`-E7u-E7uO6WQQO1G/ZOOQa1G/h1G/hO6cQbO1G/hOOQO'#Dz'#DzO6WQQO1G/ZOOQa1G/Z1G/ZOOQ`'#D{'#D{O6cQbO1G/hOOQa1G/S1G/SO7[QcO1G/SO7fQcO1G/SO7pQcO1G/SOOQa1G/j1G/jO9`QcO1G/jO9gQcO1G/jO9nQcO1G/jOOQa1G/Q1G/QOOQa1G/O1G/OO!aQbO'#C{O&ZQbO'#CwOOQ`,5:i,5:iOOQ`-E7{-E7{O9uQbO1G0rO:QQbO1G0sO:nQbO1G0tOOQ`1G/y1G/yOOQ`1G/z1G/zO;RQbO7+&WO:QQbO7+&YO;^QQO7+$uOOQa7+$u7+$uO;iQbO7+%SOOQa7+%S7+%SOOQO-E7x-E7xOOQ`-E7y-E7yO;sQbO'#DZO;xQQO'#D^OOQ`7+&^7+&^O;}QbO7+&^O<SQbO7+&^OOQ`'#Dy'#DyO<[QQO'#DyO<aQbO'#EgOOQ`'#D]'#D]O=TQbO7+&_OOQ`'#Dm'#DmO=`QbO7+&`O=eQbO7+&aOOQ`<<Ir<<IrO>RQbO<<IrO>WQbO<<IrO>`QbO<<ItOOQa<<Ha<<HaOOQa<<Hn<<HnO>kQQO,59uO>pQbO,59xOOQ`<<Ix<<IxO?TQbO<<IxOOQ`,5:e,5:eOOQ`-E7w-E7wOOQ`<<Iy<<IyO?YQbO<<IyO?_QbO<<IyOOQ`<<Iz<<IzOOQ`'#Dn'#DnO?gQbO<<I{OOQ`AN?^AN?^O?rQbOAN?^OOQ`AN?`AN?`O?wQbOAN?`O?|QbOAN?`O@UQbO1G/aO@iQbO1G/dOOQ`1G/d1G/dOOQ`AN?dAN?dOOQ`AN?eAN?eOAPQbOAN?eO,wQbO'#DoOOQ`'#EO'#EOOAUQbOAN?gOAaQQO'#DqOOQ`AN?gAN?gOAfQbOAN?gOOQ`G24xG24xOOQ`G24zG24zOAkQbOG24zOApQbO7+${OOQ`7+${7+${OOQ`7+%O7+%OOOQ`G25PG25POBZQRO,5:ZOBbQRO,5:ZOOQ`-E7|-E7|OOQ`G25RG25ROBmQbOG25ROBrQQO,5:]OOQ`LD*fLD*fOOQ`<<Hg<<HgOBwQQO1G/uOOQ`LD*mLD*mO@iQbO1G/wO=eQbO7+%aOOQ`7+%c7+%cOOQ`<<H{<<H{",
|
states: "9[QYQbOOO#tQcO'#C{O$qOSO'#C}O%PQbO'#EfOOQ`'#DW'#DWOOQa'#DT'#DTO&SQbO'#DbO'eQcO'#EZOOQa'#EZ'#EZO(hQcO'#EZO)jQcO'#EYO)}QRO'#C|O+ZQcO'#EUO+kQcO'#EUO+uQbO'#CzO,mOpO'#CxOOQ`'#EV'#EVO,rQbO'#EUO,yQQO'#ElOOQ`'#Dg'#DgO-OQbO'#DiO-OQbO'#EnOOQ`'#Dk'#DkO-sQRO'#DsOOQ`'#EU'#EUO.XQQO'#ETOOQ`'#ET'#ETOOQ`'#Du'#DuQYQbOOO.aQbO'#DUOOQa'#EY'#EYOOQ`'#De'#DeOOQ`'#Ek'#EkOOQ`'#D|'#D|O.kQbO,59cO/_QbO'#DPO/gQWO'#DQOOOO'#E]'#E]OOOO'#Dv'#DvO/{OSO,59iOOQa,59i,59iOOQ`'#Dx'#DxO0ZQbO'#DXO0cQQO,5;QOOQ`'#Dw'#DwO0hQbO,59|O0oQQO,59oOOQa,59|,59|O0zQbO,59|O1UQbO,5:`O-OQbO,59hO-OQbO,59hO-OQbO,59hO-OQbO,5:OO-OQbO,5:OO-OQbO,5:OO1fQRO,59fO1mQRO,59fO2OQRO,59fO1yQQO,59fO2ZQQO,59fO2cObO,59dO2nQbO'#D}O2yQbO,59bO3bQbO,5;WO3uQcO,5:TO4kQcO,5:TO4{QcO,5:TO5qQRO,5;YO5xQRO,5;YO1UQbO,5:_OOQ`,5:o,5:oOOQ`-E7s-E7sOOQ`,59p,59pOOQ`-E7z-E7zOOOO,59k,59kOOOO,59l,59lOOOO-E7t-E7tOOQa1G/T1G/TOOQ`-E7v-E7vO6TQbO1G0lOOQ`-E7u-E7uO6hQQO1G/ZOOQa1G/h1G/hO6sQbO1G/hOOQO'#Dz'#DzO6hQQO1G/ZOOQa1G/Z1G/ZOOQ`'#D{'#D{O6sQbO1G/hOOQ`1G/z1G/zOOQa1G/S1G/SO7lQcO1G/SO7vQcO1G/SO8QQcO1G/SOOQa1G/j1G/jO9pQcO1G/jO9wQcO1G/jO:OQcO1G/jOOQa1G/Q1G/QOOQa1G/O1G/OO!aQbO'#C{O:VQbO'#CwOOQ`,5:i,5:iOOQ`-E7{-E7{O:dQbO1G0rO:oQbO1G0sO;]QbO1G0tOOQ`1G/y1G/yO;pQbO7+&WO:oQbO7+&YO;{QQO7+$uOOQa7+$u7+$uO<WQbO7+%SOOQa7+%S7+%SOOQO-E7x-E7xOOQ`-E7y-E7yO<bQbO'#DZO<gQQO'#D^OOQ`7+&^7+&^O<lQbO7+&^O<qQbO7+&^OOQ`'#Dy'#DyO<yQQO'#DyO=OQbO'#EgOOQ`'#D]'#D]O=rQbO7+&_OOQ`'#Dm'#DmO=}QbO7+&`O>SQbO7+&aOOQ`<<Ir<<IrO>pQbO<<IrO>uQbO<<IrO>}QbO<<ItOOQa<<Ha<<HaOOQa<<Hn<<HnO?YQQO,59uO?_QbO,59xOOQ`<<Ix<<IxO?rQbO<<IxOOQ`,5:e,5:eOOQ`-E7w-E7wOOQ`<<Iy<<IyO?wQbO<<IyO?|QbO<<IyOOQ`<<Iz<<IzOOQ`'#Dn'#DnO@UQbO<<I{OOQ`AN?^AN?^O@aQbOAN?^OOQ`AN?`AN?`O@fQbOAN?`O@kQbOAN?`O@sQbO1G/aOAWQbO1G/dOOQ`1G/d1G/dOOQ`AN?dAN?dOOQ`AN?eAN?eOAnQbOAN?eO-OQbO'#DoOOQ`'#EO'#EOOAsQbOAN?gOBOQQO'#DqOOQ`AN?gAN?gOBTQbOAN?gOOQ`G24xG24xOOQ`G24zG24zOBYQbOG24zOB_QbO7+${OOQ`7+${7+${OOQ`7+%O7+%OOOQ`G25PG25POBxQRO,5:ZOCPQRO,5:ZOOQ`-E7|-E7|OOQ`G25RG25ROC[QbOG25ROCaQQO,5:]OOQ`LD*fLD*fOOQ`<<Hg<<HgOCfQQO1G/uOOQ`LD*mLD*mOAWQbO1G/wO>SQbO7+%aOOQ`7+%c7+%cOOQ`<<H{<<H{",
|
||||||
stateData: "CP~O!uOS!vOS~OdPOefOfWOg^OhROmWOuWOvWO!VWO![aO!^cO!`dO!{]O#OQO#VTO#WUO#XiO~OdmOfWOg^OhROmWOuWOvWOylO!TnO!VWO!{]O#OQO#VTO#WUO!YoX#XoX#doX#^oX!OoX!RoX!SoX~OP!|XQ!|XR!|XS!|XT!|XU!|XW!|XX!|XY!|XZ!|X[!|X]!|X^!|X~P!aOrtO#OwO#QrO#RsO~OdxO|{P~OdmOfWOg^OmWOuWOvWOylO!VWO!{]O#OQO#VTO#WUO#X{O~O#]!OO~P%XOdmOfWOg^OhROmWOuWOvWOylO!TnO!VWO!{]O#OQO#VTO#WUO~OP!}XQ!}XR!}XS!}XT!}XU!}XW!}XX!}XY!}XZ!}X[!}X]!}X^!}X#X!}X#d!}X#^!}X!O!}X!R!}X!S!}X~P&ZOP!|XQ!|XR!|XS!|XT!|XU!|XW!|XX!|XY!|XZ!|X[!|X]!|X^!|X~O#X!xX#d!xX!O!xX!R!xX!S!xX~P(hOP!ROQ!ROR!SOS!SOT!UOU!VOW!TOX!TOY!TOZ!TO[!TO]!TO^!QO~O#X!xX#d!xX!O!xX!R!xX!S!xX~OP!ROQ!ROR!SOS!SO~P*qOT!UOU!VO~P*qOdPOfWOg^OhROmWOuWOvWO!VWO!{]O#OQO#VTO#WUO~O!z!]O~O!Y!^O~P*qO|!`O~OdmOfWOg^OmWOuWOvWO!VWO!{]O#OQO#VTO#WUO~OV!gO_!fO`!fOa!fOb!fOc!fO~O#X!hO#d!hO~OhRO!T!jO~P,wO!Yka#Xka#dka#^ka!Oka!Rka!Ska~P&ZOd!lO!{]O~O#O!mO#Q!mO#R!mO#S!mO#T!mO#U!mO~OrtO#O!oO#QrO#RsO~OdxO|{X~O|!qO~O#]!tO~P%XOylO#X!vO#]!xO~O#X!yO#]!tO~P,wO#^#TO~P(hOP!ROQ!ROR!SOS!SO#^#TO~OT!UOU!VO#^#TO~O!Y!^O#^#TO~Od#UOm#UO!{]O~Od#VOg^O!{]O~O!Y!^O#Xja#dja#^ja!Oja!Rja!Sja~OefO![aO!^cO!`dO#X#[O~P+nO#X!]a#d!]a!O!]a!R!]a!S!]a~P)vO#X!]a#d!]a!O!]a!R!]a!S!]a~OP!ROQ!ROR!SOS!SO~P3hOT!UOU!VO~P3hOT!UOU!VOW!TOX!TOY!TOZ!TO[!TO]!TO~O|#]O~P4eOT!UOU!VO|#]O~OefO![aO!^cO!`dO~P+nOefO![aO!^cO!`dO#X#aO~P+nOylO#X!vO#]#cO~O#X!yO#]#eO~P,wO^!QORpiSpi#Xpi#dpi#^pi!Opi!Rpi!Spi~OPpiQpi~P6mOP!ROQ!RO~P6mOP!ROQ!RORpiSpi#Xpi#dpi#^pi!Opi!Rpi!Spi~OW!TOX!TOY!TOZ!TO[!TO]!TOT!Wi#X!Wi#d!Wi#^!Wi|!Wi!O!Wi!R!Wi!S!Wi~OU!VO~P8bOU!VO~P8tOU!Wi~P8bO!O#hO!R#iO!S#jO~OefO![aO!^cO!`dO#X#mO!O#ZP!R#ZP!S#ZP~P+nOefO![aO!^cO!`dO#X#tO~P+nO!O#hO!R#iO!S#uO~OylO#X!vO#]#yO~O#X!yO#]#zO~P,wOd#{O~O|#|O~O!S#}O~O!R#iO!S#}O~O#X$PO~OefO![aO!^cO!`dO#X#mO!O#ZX!R#ZX!S#ZX!d#ZX!f#ZX~P+nO!O#hO!R#iO!S$RO~O!S$UO~OefO![aO!^cO!`dO#X#mO!S#ZP!d#ZP!f#ZP~P+nO!S$XO~O!R#iO!S$XO~O!O#hO!R#iO!S$ZO~O|$^O~OefO![aO!^cO!`dO#X$_O~P+nO!S$aO~O!S$bO~O!R#iO!S$bO~O!S$hO!d$dO!f$gO~O!S$jO~O!S$kO~O!R#iO!S$kO~OefO![aO!^cO!`dO#X$mO~P+nOefO![aO!^cO!`dO#X#mO!S#ZP~P+nO!S$pO~O!S$tO!d$dO!f$gO~O|$vO~O!S$tO~O!S$wO~OefO![aO!^cO!`dO#X#mO!R#ZP!S#ZP~P+nO|$yO~P4eOT!UOU!VO|$yO~O!S$zO~O#X${O~O#X$|O~Omv~",
|
stateData: "Cn~O!uOS!vOS~OdPOegOfWOg_OhROmWOuWOvWO!VWO![bO!^dO!`eO!{^O#OQO#VTO#WUO#XjO~OdnOfWOg_OhROmWOuWOvWOymO!ToO!VWO!{^O#OQO#VTO#WUO!YoX#XoX#doX#^oX!OoX!RoX!SoX~OP!|XQ!|XR!|XS!|XT!|XU!|XW!|XX!|XY!|XZ!|X[!|X]!|X^!|X~P!aOruO#OxO#QsO#RtO~OdyO|{P~OdnOfWOg_OmWOuWOvWOymO!VWO!{^O#OQO#VTO#WUO#X|O~O#]!PO~P%XOP!}XQ!}XR!}XS!}XT!}XU!}XW!}XX!}XY!}XZ!}X[!}X]!}X^!}X#X!}X#d!}X!O!}X!R!}X!S!}X~OdnOfWOg_OhROmWOuWOvWOymO!ToO!VWO!{^O#OQO#VTO#WUO#^!}X~P&ZOV!RO~P&ZOP!|XQ!|XR!|XS!|XT!|XU!|XW!|XX!|XY!|XZ!|X[!|X]!|X^!|X~O#X!xX#d!xX!O!xX!R!xX!S!xX~P(oOP!TOQ!TOR!UOS!UOT!WOU!XOW!VOX!VOY!VOZ!VO[!VO]!VO^!SO~O#X!xX#d!xX!O!xX!R!xX!S!xX~OP!TOQ!TOR!UOS!UO~P*xOT!WOU!XO~P*xOdPOfWOg_OhROmWOuWOvWO!VWO!{^O#OQO#VTO#WUO~O!z!_O~O!Y!`O~P*xO|!bO~OdnOfWOg_OmWOuWOvWO!VWO!{^O#OQO#VTO#WUO~OV!RO_!hO`!hOa!hOb!hOc!hO~O#X!iO#d!iO~OhRO!T!kO~P-OOhROymO!ToO!Yka#Xka#dka#^ka!Oka!Rka!Ska~P-OOd!mO!{^O~O#O!nO#Q!nO#R!nO#S!nO#T!nO#U!nO~OruO#O!pO#QsO#RtO~OdyO|{X~O|!rO~O#]!uO~P%XOymO#X!wO#]!yO~O#X!zO#]!uO~P-OOegO![bO!^dO!`eO~P+uO#^#VO~P(oOP!TOQ!TOR!UOS!UO#^#VO~OT!WOU!XO#^#VO~O!Y!`O#^#VO~Od#WOm#WO!{^O~Od#XOg_O!{^O~O!Y!`O#Xja#dja#^ja!Oja!Rja!Sja~OegO![bO!^dO!`eO#X#^O~P+uO#X!]a#d!]a!O!]a!R!]a!S!]a~P)}O#X!]a#d!]a!O!]a!R!]a!S!]a~OP!TOQ!TOR!UOS!UO~P4YOT!WOU!XO~P4YOT!WOU!XOW!VOX!VOY!VOZ!VO[!VO]!VO~O|#_O~P5VOT!WOU!XO|#_O~OegO![bO!^dO!`eO#X#bO~P+uOymO#X!wO#]#dO~O#X!zO#]#fO~P-OO^!SORpiSpi#Xpi#dpi#^pi!Opi!Rpi!Spi~OPpiQpi~P6}OP!TOQ!TO~P6}OP!TOQ!TORpiSpi#Xpi#dpi#^pi!Opi!Rpi!Spi~OW!VOX!VOY!VOZ!VO[!VO]!VOT!Wi#X!Wi#d!Wi#^!Wi|!Wi!O!Wi!R!Wi!S!Wi~OU!XO~P8rOU!XO~P9UOU!Wi~P8rOhROymO!ToO~P-OO!O#iO!R#jO!S#kO~OegO![bO!^dO!`eO#X#nO!O#ZP!R#ZP!S#ZP~P+uOegO![bO!^dO!`eO#X#uO~P+uO!O#iO!R#jO!S#vO~OymO#X!wO#]#zO~O#X!zO#]#{O~P-OOd#|O~O|#}O~O!S$OO~O!R#jO!S$OO~O#X$QO~OegO![bO!^dO!`eO#X#nO!O#ZX!R#ZX!S#ZX!d#ZX!f#ZX~P+uO!O#iO!R#jO!S$SO~O!S$VO~OegO![bO!^dO!`eO#X#nO!S#ZP!d#ZP!f#ZP~P+uO!S$YO~O!R#jO!S$YO~O!O#iO!R#jO!S$[O~O|$_O~OegO![bO!^dO!`eO#X$`O~P+uO!S$bO~O!S$cO~O!R#jO!S$cO~O!S$iO!d$eO!f$hO~O!S$kO~O!S$lO~O!R#jO!S$lO~OegO![bO!^dO!`eO#X$nO~P+uOegO![bO!^dO!`eO#X#nO!S#ZP~P+uO!S$qO~O!S$uO!d$eO!f$hO~O|$wO~O!S$uO~O!S$xO~OegO![bO!^dO!`eO#X#nO!R#ZP!S#ZP~P+uO|$zO~P5VOT!WOU!XO|$zO~O!S${O~O#X$|O~O#X$}O~Omv~",
|
||||||
goto: "3n#dPPPPPPPPPPPPPPPPPPPPPPPPPP#e#{$bP%b#{&h'XP(S(SPP'X(WP(k)]P)`P)l)uPPP'XP*_+UP+]P+]P+]P+p+s+|P,QP+]+],W,^,d,j,p,|-W-b-k-rPPPP-x-|.qPP/[0sP1rPPPPPPPP1v2b1vPP2o2v2v3Z3ZrgOk!`!f!g!q#[#]#a#o#t#|$^$_$m${$|R!Z]w_O]k!^!`!f!g!q#[#]#a#o#t#|$^$_$m${$|tPO]k!`!f!g!q#[#]#a#o#t#|$^$_$m${$|zmPUVcdlq|!P!Q!R!S!T!U!V!u!z#V#W#d$dR#V!^tVO]k!`!f!g!q#[#]#a#o#t#|$^$_$m${$|zWPUVcdlq|!P!Q!R!S!T!U!V!u!z#V#W#d$dQ!lrQ#U!]R#W!^rZOk!`!f!g!q#[#]#a#o#t#|$^$_$m${$|Q!X]Q!bcQ!{!RR#O!S!qWOPUV]cdklq|!P!Q!R!S!T!U!V!`!f!g!q!u!z#V#W#[#]#a#d#o#t#|$^$_$d$m${$|TtQvYoPVq#V#WQ}UQ!s|X!v}!s!w#brgOk!`!f!g!q#[#]#a#o#t#|$^$_$m${$|YnPVq#V#WQ!Z]R!jlRzRQ#l#ZQ#w#`Q$T#qR$]#xQ#q#[Q$o$_R$x$mQ#k#ZQ#v#`Q$O#lQ$S#qQ$Y#wQ$[#xQ$c$TR$l$]r[Ok!`!f!g!q#[#]#a#o#t#|$^$_$m${$|Q!Y]Q!ccQ!edQ#P!VQ#R!UR$r$dZoPVq#V#WsgOk!`!f!g!q#[#]#a#o#t#|$^$_$m${$|R#s#]Q$W#tQ$}${R%O$|T$e$W$fQ$i$WR$u$fQkOR!ikQvQR!nvQ|UR!r|QyRR!py^#o#[#a#t$_$m${$|R$Q#oQ!w}Q#b!sT#f!w#bQ!z!PQ#d!uT#g!z#dWqPV#V#WR!kqS!_`![R#Y!_Q$f$WR$s$fTjOkShOkQ#Z!`Q#^!fQ#_!gQ#`!q`#n#[#a#o#t$_$m${$|Q#r#]Q$`#|R$n$^r`Ok!`!f!g!q#[#]#a#o#t#|$^$_$m${$|Q![]R#X!^tYO]k!`!f!g!q#[#]#a#o#t#|$^$_$m${$|YnPVq#V#WQ!PUQ!acQ!ddQ!jlQ!u|W!y!P!u!z#dQ!{!QQ!|!RQ!}!SQ#P!TQ#Q!UQ#S!VR$q$drXOk!`!f!g!q#[#]#a#o#t#|$^$_$m${$|zmPUVcdlq|!P!Q!R!S!T!U!V!u!z#V#W#d$dR!W]TuQv!RSOPV]klq!`!f!g!q#V#W#[#]#a#o#t#|$^$_$m${$|U#p#[$_$mQ#x#aV$V#t${$|ZpPVq#V#WsbOk!`!f!g!q#[#]#a#o#t#|$^$_$m${$|seOk!`!f!g!q#[#]#a#o#t#|$^$_$m${$|",
|
goto: "4k#dPPPPPPPPPPPPPPPPPPPPPPPPPP#e#{$bP%b#{&h'XP(S(SPP'X(WP(k)]P)`P)l)uPPP*_P+[,RP,YP,YP,YP,m,p,yP,}P,Y,Y-T-Z-a-g-m-y.T._.h.oPPPP.u.y/nPP0X1pP2oPPPPPPPP2s3_2sPP3l3s3s4W4WrhOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}R!]^w`O^l!R!`!b!h!r#^#_#b#p#u#}$_$`$n$|$}tPO^l!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}znPUVdemr}!Q!S!T!U!V!W!X!v!{#X#Y#e$eR#X!`tVO^l!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}zWPUVdemr}!Q!S!T!U!V!W!X!v!{#X#Y#e$eQ!msQ#W!_R#Y!`r[Ol!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}Q!Z^Q!ddQ!}!TR#Q!U!qWOPUV^delmr}!Q!R!S!T!U!V!W!X!b!h!r!v!{#X#Y#^#_#b#e#p#u#}$_$`$e$n$|$}TuQwYpPVr#X#YQ!OUQ!t}X!w!O!t!x#crhOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}YoPVr#X#YQ!]^R!kmR{RQ#m#]Q#x#aQ$U#rR$^#yQ#r#^Q$p$`R$y$nQ#l#]Q#w#aQ$P#mQ$T#rQ$Z#xQ$]#yQ$d$UR$m$^|WPUV^demr}!Q!S!T!U!V!W!X!v!{#X#Y#e$esXOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}r]Ol!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}Q![^Q!edQ!geQ#R!XQ#T!WR$s$eZpPVr#X#YshOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}R#t#_Q$X#uQ%O$|R%P$}T$f$X$gQ$j$XR$v$gQlOR!jlQwQR!owQ}UR!s}QzRR!qz^#p#^#b#u$`$n$|$}R$R#pQ!x!OQ#c!tT#g!x#cQ!{!QQ#e!vT#h!{#eWrPV#X#YR!lrS!aa!^R#[!aQ$g$XR$t$gTkOlSiOlQ!|!RQ#]!bQ#`!hQ#a!r`#o#^#b#p#u$`$n$|$}Q#s#_Q$a#}R$o$_raOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}Q!^^R#Z!`tZO^l!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}YoPVr#X#YQ!QUQ!cdQ!feQ!kmQ!v}W!z!Q!v!{#eQ!}!SQ#O!TQ#P!UQ#R!VQ#S!WQ#U!XR$r$erYOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}znPUVdemr}!Q!S!T!U!V!W!X!v!{#X#Y#e$eR!Y^TvQw!RSOPV^lmr!R!b!h!r#X#Y#^#_#b#p#u#}$_$`$n$|$}U#q#^$`$nQ#y#bV$W#u$|$}ZqPVr#X#YscOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}sfOl!R!b!h!r#^#_#b#p#u#}$_$`$n$|$}",
|
||||||
nodeNames: "⚠ Star Slash Plus Minus And Or Eq EqEq Neq Lt Lte Gt Gte Modulo PlusEq MinusEq StarEq SlashEq ModuloEq Identifier AssignableIdentifier Word IdentifierBeforeDot Do Program PipeExpr FunctionCall DotGet Number ParenExpr FunctionCallOrIdentifier BinOp String StringFragment Interpolation EscapeSeq Boolean Regex Dict NamedArg NamedArgPrefix FunctionDef Params colon CatchExpr keyword TryBlock FinallyExpr keyword keyword Underscore Array Null ConditionalOp PositionalArg operator TryExpr keyword Throw keyword IfExpr keyword SingleLineThenBlock ThenBlock ElseIfExpr keyword ElseExpr keyword CompoundAssign Assign",
|
nodeNames: "⚠ Star Slash Plus Minus And Or Eq EqEq Neq Lt Lte Gt Gte Modulo PlusEq MinusEq StarEq SlashEq ModuloEq Identifier AssignableIdentifier Word IdentifierBeforeDot Do Program PipeExpr FunctionCall DotGet Number ParenExpr FunctionCallOrIdentifier BinOp String StringFragment Interpolation EscapeSeq Boolean Regex Dict NamedArg NamedArgPrefix FunctionDef Params colon CatchExpr keyword TryBlock FinallyExpr keyword keyword Underscore Array Null ConditionalOp PositionalArg operator TryExpr keyword Throw keyword IfExpr keyword SingleLineThenBlock ThenBlock ElseIfExpr keyword ElseExpr keyword CompoundAssign Assign",
|
||||||
maxTerm: 112,
|
maxTerm: 112,
|
||||||
context: trackScope,
|
context: trackScope,
|
||||||
|
|
@ -23,5 +23,5 @@ export const parser = LRParser.deserialize({
|
||||||
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!z~~", 11)],
|
tokenizers: [operatorTokenizer, 1, 2, 3, tokenizer, new LocalTokenGroup("[~RP!O!PU~ZO!z~~", 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: 1562
|
tokenPrec: 1591
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -660,6 +660,62 @@ describe('Comments', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('Array destructuring', () => {
|
||||||
|
test('parses array pattern with two variables', () => {
|
||||||
|
expect('[ a b ] = [ 1 2 3 4]').toMatchTree(`
|
||||||
|
Assign
|
||||||
|
Array
|
||||||
|
Identifier a
|
||||||
|
Identifier b
|
||||||
|
Eq =
|
||||||
|
Array
|
||||||
|
Number 1
|
||||||
|
Number 2
|
||||||
|
Number 3
|
||||||
|
Number 4`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('parses array pattern with one variable', () => {
|
||||||
|
expect('[ x ] = [ 42 ]').toMatchTree(`
|
||||||
|
Assign
|
||||||
|
Array
|
||||||
|
Identifier x
|
||||||
|
Eq =
|
||||||
|
Array
|
||||||
|
Number 42`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('parses array pattern with emoji identifiers', () => {
|
||||||
|
expect('[ 🚀 💎 ] = [ 1 2 ]').toMatchTree(`
|
||||||
|
Assign
|
||||||
|
Array
|
||||||
|
Identifier 🚀
|
||||||
|
Identifier 💎
|
||||||
|
Eq =
|
||||||
|
Array
|
||||||
|
Number 1
|
||||||
|
Number 2`)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
test('works with dotget', () => {
|
||||||
|
expect('[ a ] = [ [1 2 3] ]; a.1').toMatchTree(`
|
||||||
|
Assign
|
||||||
|
Array
|
||||||
|
Identifier a
|
||||||
|
Eq =
|
||||||
|
Array
|
||||||
|
Array
|
||||||
|
Number 1
|
||||||
|
Number 2
|
||||||
|
Number 3
|
||||||
|
FunctionCallOrIdentifier
|
||||||
|
DotGet
|
||||||
|
IdentifierBeforeDot a
|
||||||
|
Number 1`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('Conditional ops', () => {
|
describe('Conditional ops', () => {
|
||||||
test('or can be chained', () => {
|
test('or can be chained', () => {
|
||||||
expect(`
|
expect(`
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user