ok, cool
This commit is contained in:
parent
e0fafc0088
commit
a28bdf74c9
|
|
@ -16,7 +16,7 @@ Shrimp is a shell-like scripting language that combines the simplicity of comman
|
||||||
## Current Status & Goals
|
## Current Status & Goals
|
||||||
|
|
||||||
### Today's Implementation Goals
|
### Today's Implementation Goals
|
||||||
1. **Interpreter Setup** - Rename evaluator to interpreter for clarity
|
1. ✅ **Interpreter Setup** - Renamed evaluator to interpreter for clarity
|
||||||
2. **Command Execution** - Support calling external commands and built-in functions
|
2. **Command Execution** - Support calling external commands and built-in functions
|
||||||
3. **Variable Assignment** - Implement assignment with validation using Lezer context tracking
|
3. **Variable Assignment** - Implement assignment with validation using Lezer context tracking
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#! /usr/bin/env bun
|
#! /usr/bin/env bun
|
||||||
|
|
||||||
import { parser } from '../parser/shrimp.js'
|
import { parser } from '../parser/shrimp.js'
|
||||||
import { evaluate } from '../evaluator/evaluator.js'
|
import { evaluate } from '../interpreter/evaluator.js'
|
||||||
|
|
||||||
const log = (...args: any[]) => console.log(...args)
|
const log = (...args: any[]) => console.log(...args)
|
||||||
log.error = (...args: any[]) => console.error(...args)
|
log.error = (...args: any[]) => console.error(...args)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { outputSignal } from '#editor/editor'
|
import { outputSignal } from '#editor/editor'
|
||||||
import { evaluate } from '#evaluator/evaluator'
|
import { evaluate } from '#interpreter/evaluator'
|
||||||
import { parser } from '#parser/shrimp'
|
import { parser } from '#parser/shrimp'
|
||||||
import { errorMessage, log } from '#utils/utils'
|
import { errorMessage, log } from '#utils/utils'
|
||||||
import { keymap } from '@codemirror/view'
|
import { keymap } from '@codemirror/view'
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Tree, type SyntaxNode } from '@lezer/common'
|
import { Tree, type SyntaxNode } from '@lezer/common'
|
||||||
import * as terms from '../parser/shrimp.terms.ts'
|
import * as terms from '../parser/shrimp.terms.ts'
|
||||||
import { RuntimeError } from '#evaluator/runtimeError.ts'
|
import { RuntimeError } from '#interpreter/runtimeError.ts'
|
||||||
import { assert } from 'console'
|
import { assert } from 'console'
|
||||||
import { assertNever } from '#utils/utils.tsx'
|
import { assertNever } from '#utils/utils.tsx'
|
||||||
import { matchingCommands, type CommandShape } from '#editor/commands.ts'
|
import { matchingCommands, type CommandShape } from '#editor/commands.ts'
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
@external propSource highlighting from "./highlight.js"
|
@external propSource highlighting from "./highlight.js"
|
||||||
@top Program { (Expression newline)* }
|
|
||||||
|
@skip { space }
|
||||||
|
|
||||||
|
@top Program { (line newline)* }
|
||||||
|
|
||||||
@tokens {
|
@tokens {
|
||||||
|
@precedence { Number "-" }
|
||||||
|
|
||||||
|
NamedArgPrefix { $[a-z]+ "=" }
|
||||||
Number { "-"? $[0-9]+ ('.' $[0-9]+)? }
|
Number { "-"? $[0-9]+ ('.' $[0-9]+)? }
|
||||||
Boolean { "true" | "false" }
|
Boolean { "true" | "false" }
|
||||||
String { '\'' !["]* '\'' }
|
String { '\'' !["]* '\'' }
|
||||||
|
|
@ -9,6 +15,11 @@
|
||||||
space { " " }
|
space { " " }
|
||||||
leftParen { "(" }
|
leftParen { "(" }
|
||||||
rightParen { ")" }
|
rightParen { ")" }
|
||||||
|
":"
|
||||||
|
"fn"
|
||||||
|
"do"
|
||||||
|
"end"
|
||||||
|
"="
|
||||||
"+"[@name=operator]
|
"+"[@name=operator]
|
||||||
"-"[@name=operator]
|
"-"[@name=operator]
|
||||||
"*"[@name=operator]
|
"*"[@name=operator]
|
||||||
|
|
@ -16,20 +27,28 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@external tokens tokenizer from "./tokenizers" { Identifier, Word }
|
@external tokens tokenizer from "./tokenizers" { Identifier, Word }
|
||||||
|
|
||||||
@precedence {
|
@precedence {
|
||||||
multiplicative @left,
|
multiplicative @left,
|
||||||
additive @left
|
additive @left
|
||||||
|
call
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression {
|
line {
|
||||||
FunctionCall |
|
FunctionCall |
|
||||||
FunctionCallOrIdentifier |
|
FunctionCallOrIdentifier |
|
||||||
|
FunctionDef |
|
||||||
|
Assignment |
|
||||||
|
expressionWithoutIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
expression {
|
||||||
|
expressionWithoutIdentifier | Identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
expressionWithoutIdentifier {
|
||||||
BinOp |
|
BinOp |
|
||||||
ParenExpr |
|
valueWithoutIdentifier
|
||||||
Word |
|
|
||||||
String |
|
|
||||||
Number |
|
|
||||||
Boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -38,11 +57,11 @@ FunctionCallOrIdentifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionCall {
|
FunctionCall {
|
||||||
Identifier (~ambig space arg)+
|
Identifier arg+
|
||||||
}
|
}
|
||||||
|
|
||||||
arg {
|
arg {
|
||||||
PositionalArg | NamedArg | IncompleteNamedArg
|
PositionalArg | NamedArg
|
||||||
}
|
}
|
||||||
|
|
||||||
PositionalArg {
|
PositionalArg {
|
||||||
|
|
@ -50,29 +69,36 @@ PositionalArg {
|
||||||
}
|
}
|
||||||
|
|
||||||
NamedArg {
|
NamedArg {
|
||||||
Identifier "=" value
|
NamedArgPrefix value
|
||||||
}
|
}
|
||||||
|
|
||||||
IncompleteNamedArg {
|
FunctionDef {
|
||||||
Identifier "="
|
"fn" Params ":" "do" expression "end"
|
||||||
|
}
|
||||||
|
|
||||||
|
Params {
|
||||||
|
Identifier*
|
||||||
|
}
|
||||||
|
|
||||||
|
Assignment {
|
||||||
|
Identifier "=" line
|
||||||
}
|
}
|
||||||
|
|
||||||
BinOp {
|
BinOp {
|
||||||
operand ~ambig space !multiplicative "*" space operand |
|
expression !multiplicative "*" expression |
|
||||||
operand ~ambig space !multiplicative "/" space operand |
|
expression !multiplicative "/" expression |
|
||||||
operand ~ambig space !additive "+" space operand |
|
expression !additive "+" expression |
|
||||||
operand ~ambig space !additive "-" space operand
|
expression !additive "-" expression
|
||||||
}
|
}
|
||||||
|
|
||||||
operand {
|
|
||||||
value | BinOp
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ParenExpr {
|
ParenExpr {
|
||||||
leftParen Expression rightParen
|
leftParen (expressionWithoutIdentifier | FunctionCall | FunctionCallOrIdentifier) rightParen
|
||||||
}
|
}
|
||||||
|
|
||||||
value {
|
value {
|
||||||
ParenExpr | Identifier | Word | String | Number | Boolean
|
valueWithoutIdentifier | Identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
valueWithoutIdentifier {
|
||||||
|
ParenExpr | Word | String | Number | Boolean
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,16 @@ export const
|
||||||
Identifier = 1,
|
Identifier = 1,
|
||||||
Word = 2,
|
Word = 2,
|
||||||
Program = 3,
|
Program = 3,
|
||||||
Expression = 4,
|
FunctionCall = 4,
|
||||||
FunctionCall = 5,
|
PositionalArg = 5,
|
||||||
PositionalArg = 6,
|
ParenExpr = 6,
|
||||||
ParenExpr = 7,
|
BinOp = 7,
|
||||||
String = 8,
|
FunctionCallOrIdentifier = 12,
|
||||||
Number = 9,
|
String = 13,
|
||||||
Boolean = 10,
|
Number = 14,
|
||||||
NamedArg = 11,
|
Boolean = 15,
|
||||||
IncompleteNamedArg = 12,
|
NamedArg = 16,
|
||||||
FunctionCallOrIdentifier = 13,
|
NamedArgPrefix = 17,
|
||||||
BinOp = 14
|
FunctionDef = 18,
|
||||||
|
Params = 20,
|
||||||
|
Assignment = 24
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ describe('calling functions', () => {
|
||||||
|
|
||||||
test('call with no args', () => {
|
test('call with no args', () => {
|
||||||
expect('tail').toMatchTree(`
|
expect('tail').toMatchTree(`
|
||||||
Expression
|
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier tail
|
Identifier tail
|
||||||
`)
|
`)
|
||||||
|
|
@ -29,7 +28,6 @@ describe('calling functions', () => {
|
||||||
|
|
||||||
test('call with arg', () => {
|
test('call with arg', () => {
|
||||||
expect('tail path').toMatchTree(`
|
expect('tail path').toMatchTree(`
|
||||||
Expression
|
|
||||||
FunctionCall
|
FunctionCall
|
||||||
Identifier tail
|
Identifier tail
|
||||||
PositionalArg
|
PositionalArg
|
||||||
|
|
@ -39,20 +37,18 @@ describe('calling functions', () => {
|
||||||
|
|
||||||
test('call with arg and named arg', () => {
|
test('call with arg and named arg', () => {
|
||||||
expect('tail path lines=30').toMatchTree(`
|
expect('tail path lines=30').toMatchTree(`
|
||||||
Expression
|
|
||||||
FunctionCall
|
FunctionCall
|
||||||
Identifier tail
|
Identifier tail
|
||||||
PositionalArg
|
PositionalArg
|
||||||
Identifier path
|
Identifier path
|
||||||
NamedArg
|
NamedArg
|
||||||
Identifier lines
|
NamedArgPrefix lines=
|
||||||
Number 30
|
Number 30
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('command with arg that is also a command', () => {
|
test('command with arg that is also a command', () => {
|
||||||
expect('tail tail').toMatchTree(`
|
expect('tail tail').toMatchTree(`
|
||||||
Expression
|
|
||||||
FunctionCall
|
FunctionCall
|
||||||
Identifier tail
|
Identifier tail
|
||||||
PositionalArg
|
PositionalArg
|
||||||
|
|
@ -60,7 +56,6 @@ describe('calling functions', () => {
|
||||||
`)
|
`)
|
||||||
|
|
||||||
expect('tai').toMatchTree(`
|
expect('tai').toMatchTree(`
|
||||||
Expression
|
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier tai
|
Identifier tai
|
||||||
`)
|
`)
|
||||||
|
|
@ -74,27 +69,18 @@ describe('calling functions', () => {
|
||||||
|
|
||||||
test('Incomplete namedArg', () => {
|
test('Incomplete namedArg', () => {
|
||||||
expect('tail lines=').toMatchTree(`
|
expect('tail lines=').toMatchTree(`
|
||||||
Expression
|
|
||||||
FunctionCall
|
FunctionCall
|
||||||
Identifier tail
|
Identifier tail
|
||||||
IncompleteNamedArg
|
NamedArg
|
||||||
Identifier lines
|
NamedArgPrefix lines=
|
||||||
`)
|
⚠
|
||||||
|
⚠ `)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Identifier', () => {
|
describe('Identifier', () => {
|
||||||
test('fails on underscores and capital letters', () => {
|
|
||||||
expect('myVar').toFailParse()
|
|
||||||
expect('underscore_var').toFailParse()
|
|
||||||
expect('_leadingUnderscore').toFailParse()
|
|
||||||
expect('trailingUnderscore_').toFailParse()
|
|
||||||
expect('mixed-123_var').toFailParse()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('parses identifiers with emojis and dashes', () => {
|
test('parses identifiers with emojis and dashes', () => {
|
||||||
expect('moo-😊-34').toMatchTree(`
|
expect('moo-😊-34').toMatchTree(`
|
||||||
Expression
|
|
||||||
FunctionCallOrIdentifier
|
FunctionCallOrIdentifier
|
||||||
Identifier moo-😊-34`)
|
Identifier moo-😊-34`)
|
||||||
})
|
})
|
||||||
|
|
@ -103,9 +89,7 @@ describe('Identifier', () => {
|
||||||
describe('Parentheses', () => {
|
describe('Parentheses', () => {
|
||||||
test('parses expressions with parentheses correctly', () => {
|
test('parses expressions with parentheses correctly', () => {
|
||||||
expect('(2 + 3)').toMatchTree(`
|
expect('(2 + 3)').toMatchTree(`
|
||||||
Expression
|
|
||||||
ParenExpr
|
ParenExpr
|
||||||
Expression
|
|
||||||
BinOp
|
BinOp
|
||||||
Number 2
|
Number 2
|
||||||
operator +
|
operator +
|
||||||
|
|
@ -114,23 +98,45 @@ describe('Parentheses', () => {
|
||||||
|
|
||||||
test('allows parens in function calls', () => {
|
test('allows parens in function calls', () => {
|
||||||
expect('echo (3 + 3)').toMatchTree(`
|
expect('echo (3 + 3)').toMatchTree(`
|
||||||
Expression
|
|
||||||
FunctionCall
|
FunctionCall
|
||||||
Identifier echo
|
Identifier echo
|
||||||
PositionalArg
|
PositionalArg
|
||||||
ParenExpr
|
ParenExpr
|
||||||
Expression
|
|
||||||
BinOp
|
BinOp
|
||||||
Number 3
|
Number 3
|
||||||
operator +
|
operator +
|
||||||
Number 3`)
|
Number 3`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('nested parentheses', () => {
|
||||||
|
expect('(2 + (1 * 4))').toMatchTree(`
|
||||||
|
ParenExpr
|
||||||
|
BinOp
|
||||||
|
Number 2
|
||||||
|
operator +
|
||||||
|
ParenExpr
|
||||||
|
BinOp
|
||||||
|
Number 1
|
||||||
|
operator *
|
||||||
|
Number 4`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('Function in parentheses', () => {
|
||||||
|
expect('4 + (echo 3)').toMatchTree(`
|
||||||
|
BinOp
|
||||||
|
Number 4
|
||||||
|
operator +
|
||||||
|
ParenExpr
|
||||||
|
FunctionCall
|
||||||
|
Identifier echo
|
||||||
|
PositionalArg
|
||||||
|
Number 3`)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('BinOp', () => {
|
describe('BinOp', () => {
|
||||||
test('addition tests', () => {
|
test('addition tests', () => {
|
||||||
expect('2 + 3').toMatchTree(`
|
expect('2 + 3').toMatchTree(`
|
||||||
Expression
|
|
||||||
BinOp
|
BinOp
|
||||||
Number 2
|
Number 2
|
||||||
operator +
|
operator +
|
||||||
|
|
@ -140,7 +146,6 @@ describe('BinOp', () => {
|
||||||
|
|
||||||
test('subtraction tests', () => {
|
test('subtraction tests', () => {
|
||||||
expect('5 - 2').toMatchTree(`
|
expect('5 - 2').toMatchTree(`
|
||||||
Expression
|
|
||||||
BinOp
|
BinOp
|
||||||
Number 5
|
Number 5
|
||||||
operator -
|
operator -
|
||||||
|
|
@ -150,7 +155,6 @@ describe('BinOp', () => {
|
||||||
|
|
||||||
test('multiplication tests', () => {
|
test('multiplication tests', () => {
|
||||||
expect('4 * 3').toMatchTree(`
|
expect('4 * 3').toMatchTree(`
|
||||||
Expression
|
|
||||||
BinOp
|
BinOp
|
||||||
Number 4
|
Number 4
|
||||||
operator *
|
operator *
|
||||||
|
|
@ -160,7 +164,6 @@ describe('BinOp', () => {
|
||||||
|
|
||||||
test('division tests', () => {
|
test('division tests', () => {
|
||||||
expect('8 / 2').toMatchTree(`
|
expect('8 / 2').toMatchTree(`
|
||||||
Expression
|
|
||||||
BinOp
|
BinOp
|
||||||
Number 8
|
Number 8
|
||||||
operator /
|
operator /
|
||||||
|
|
@ -170,7 +173,6 @@ describe('BinOp', () => {
|
||||||
|
|
||||||
test('mixed operations with precedence', () => {
|
test('mixed operations with precedence', () => {
|
||||||
expect('2 + 3 * 4 - 5 / 1').toMatchTree(`
|
expect('2 + 3 * 4 - 5 / 1').toMatchTree(`
|
||||||
Expression
|
|
||||||
BinOp
|
BinOp
|
||||||
BinOp
|
BinOp
|
||||||
Number 2
|
Number 2
|
||||||
|
|
@ -188,86 +190,78 @@ describe('BinOp', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// describe('Fn', () => {
|
describe('Fn', () => {
|
||||||
// test('parses function with single parameter', () => {
|
test('parses function no parameters', () => {
|
||||||
// expect('fn x: x + 1').toMatchTree(`
|
expect('fn: do 1 end').toMatchTree(`
|
||||||
// Function
|
FunctionDef
|
||||||
// keyword fn
|
fn fn
|
||||||
// Params
|
Params
|
||||||
// Identifier x
|
: :
|
||||||
// colon :
|
do do
|
||||||
// BinOp
|
Number 1
|
||||||
// Identifier x
|
end end`)
|
||||||
// operator +
|
})
|
||||||
// Number 1`)
|
|
||||||
// })
|
|
||||||
|
|
||||||
// test('parses function with multiple parameters', () => {
|
test('parses function with single parameter', () => {
|
||||||
// expect('fn x y: x * y').toMatchTree(`
|
expect('fn x: do x + 1 end').toMatchTree(`
|
||||||
// Function
|
FunctionDef
|
||||||
// keyword fn
|
fn fn
|
||||||
// Params
|
Params
|
||||||
// Identifier x
|
Identifier x
|
||||||
// Identifier y
|
: :
|
||||||
// colon :
|
do do
|
||||||
// BinOp
|
BinOp
|
||||||
// Identifier x
|
Identifier x
|
||||||
// operator *
|
operator +
|
||||||
// Identifier y`)
|
Number 1
|
||||||
// })
|
end end`)
|
||||||
|
})
|
||||||
|
|
||||||
// test('parses nested functions', () => {
|
test('parses function with multiple parameters', () => {
|
||||||
// expect('fn x: fn y: x + y').toMatchTree(`
|
expect('fn x y: do x * y end').toMatchTree(`
|
||||||
// Function
|
FunctionDef
|
||||||
// keyword fn
|
fn fn
|
||||||
// Params
|
Params
|
||||||
// Identifier x
|
Identifier x
|
||||||
// colon :
|
Identifier y
|
||||||
// Function
|
: :
|
||||||
// keyword fn
|
do do
|
||||||
// Params
|
BinOp
|
||||||
// Identifier y
|
Identifier x
|
||||||
// colon :
|
operator *
|
||||||
// BinOp
|
Identifier y
|
||||||
// Identifier x
|
end end`)
|
||||||
// operator +
|
})
|
||||||
// Identifier y`)
|
})
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
||||||
// describe('Identifier', () => {
|
describe('Assignment', () => {
|
||||||
// test('parses hyphenated identifiers correctly', () => {
|
test('parses assignment with addition', () => {
|
||||||
// expect('my-var').toMatchTree(`Identifier my-var`)
|
expect('x = 5 + 3').toMatchTree(`
|
||||||
// expect('double--trouble').toMatchTree(`Identifier double--trouble`)
|
Assignment
|
||||||
// })
|
Identifier x
|
||||||
// })
|
= =
|
||||||
|
BinOp
|
||||||
|
Number 5
|
||||||
|
operator +
|
||||||
|
Number 3`)
|
||||||
|
})
|
||||||
|
|
||||||
// describe('Assignment', () => {
|
test('parses assignment with functions', () => {
|
||||||
// test('parses assignment with addition', () => {
|
expect('add = fn a b: do a + b end').toMatchTree(`
|
||||||
// expect('x = 5 + 3').toMatchTree(`
|
Assignment
|
||||||
// Assignment
|
Identifier add
|
||||||
// Identifier x
|
= =
|
||||||
// operator =
|
FunctionDef
|
||||||
// BinOp
|
fn fn
|
||||||
// Number 5
|
Params
|
||||||
// operator +
|
Identifier a
|
||||||
// Number 3`)
|
Identifier b
|
||||||
// })
|
: :
|
||||||
|
do do
|
||||||
// test('parses assignment with functions', () => {
|
BinOp
|
||||||
// expect('add = fn a b: a + b').toMatchTree(`
|
Identifier a
|
||||||
// Assignment
|
operator +
|
||||||
// Identifier add
|
Identifier b
|
||||||
// operator =
|
end end`)
|
||||||
// Function
|
})
|
||||||
// keyword fn
|
})
|
||||||
// Params
|
|
||||||
// Identifier a
|
|
||||||
// Identifier b
|
|
||||||
// colon :
|
|
||||||
// BinOp
|
|
||||||
// Identifier a
|
|
||||||
// operator +
|
|
||||||
// Identifier b`)
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@ import {tokenizer} from "./tokenizers"
|
||||||
import {highlighting} from "./highlight.js"
|
import {highlighting} from "./highlight.js"
|
||||||
export const parser = LRParser.deserialize({
|
export const parser = LRParser.deserialize({
|
||||||
version: 14,
|
version: 14,
|
||||||
states: "$nQQOTOOOQOTO'#CcOfOPO'#CtOqOPO'#CtOOOO'#Cx'#CxO!POPO'#CxO![OPOOOOOO'#C`'#C`O!aOPO'#CoQQOTOOO!fOPO,58}O!|OTO'#CpO#TOPO,58{O#`OQO,59UOOOS,59Z,59ZOOOS-E6m-E6mOOOO1G.i1G.iOOOO'#Ct'#CtO#nOPO'#CtOOOO'#Cb'#CbOOOO'#Cs'#CsOOOO,59[,59[OOOO-E6n-E6nO#|OPO1G.pO$ROTO,59SO$cOTO7+$[OOOO1G.m1G.mOOOO<<Gv<<Gv",
|
states: "&YQVQTOOOnQPO'#DSO!tQUO'#DSO#OQPOOOOQO'#DR'#DRO#oQTO'#CbOOQS'#DP'#DPO#vQTO'#CnOOQO'#C|'#C|O$OQPO'#CvQVQTOOOOQS'#DO'#DOOOQS'#Ca'#CaO$TQTO'#ClOOQS'#C}'#C}OOQS'#Cw'#CwO$[QUO,58zOVQTO,59`O$lQTO,58}O$lQTO,58}O$sQPO,58|O%UQUO'#DSO%]QPO,58|OOQS'#Cx'#CxO%bQTO'#CpO%jQPO,59YOOQS,59b,59bOOQS-E6t-E6tOOQS,59W,59WOOQS-E6u-E6uOOQO1G.z1G.zOOQO'#DS'#DSOOQO1G.i1G.iO%oQPO1G.iOOQS1G.h1G.hOOQS-E6v-E6vO&WQPO1G.tO$lQTO7+$`O&]QPO<<GzOOQOAN=fAN=f",
|
||||||
stateData: "$j~OPROQQOWQOXQOYQOiPO~OfhXmSXjSX~OfZOfhXm]Xj]X~OflXmSXjSX~Of]O~Om^O~Oj`O~OQaOWaOXaOYaOiPO~OPbO~P!kOfZOmTajTa~O_gO`gOagObgO~OkhOfhXmhXjhX~OfiO~OPaOf[am[aj[a~P!kOPaO~P!kO",
|
stateData: "&q~OoOS~OPQOQUO]UO^UO_UOcVOtTO~OWvXXvXYvXZvXxpX~OPZOQUO]UO^UO_UOa]OtTOWvXXvXYvXZvX~OiaOx[X~P!POWbOXbOYcOZcO~OQUO]UO^UO_UOtTO~OPeO~P#^OPgOedP~OxjO~OPZO~P#^OPZOa]OxSawSa~P#^OPoO~P#^OwrOWvXXvXYvXZvX~Ow[X~P!POwrO~OPgOedX~OetO~OWbOXbOYViZVixViwVigVi~OfuO~OWbOXbOYcOZcOgwO~O^Z~",
|
||||||
goto: "#UmPPPPnuz}PPPzzu!XPPPP!a!gPP!m!pPPP!|SWOXRYPVVOPXRdZUQOPXVaZhiQSiVTOPXQXOR_XQ[RRf[ReZWSOPXiQcZRjhUUOPXRki",
|
goto: "$kwPPPPx!Q!V!dPPPPxPPP!QP!mP!rPPP!mP!u!{#SPPP#Y#a#f#nP#}$[UWOYaRfTV^Q`egUOQTY]`abceu_SOTYabcuVWOYaRiVQYORkYS`QeRm`QhVRshSXOYRnaV_Q`eU[Q`eRl]^SOTYabcuXZQ]`eUPOYaQdTVobcuWROTYaQpbQqcRvu",
|
||||||
nodeNames: "⚠ Identifier Word Program Expression FunctionCall PositionalArg ParenExpr String Number Boolean NamedArg IncompleteNamedArg FunctionCallOrIdentifier BinOp operator operator operator operator",
|
nodeNames: "⚠ Identifier Word Program FunctionCall PositionalArg ParenExpr BinOp operator operator operator operator FunctionCallOrIdentifier String Number Boolean NamedArg NamedArgPrefix FunctionDef fn Params : do end Assignment =",
|
||||||
maxTerm: 29,
|
maxTerm: 40,
|
||||||
propSources: [highlighting],
|
propSources: [highlighting],
|
||||||
skippedNodes: [0],
|
skippedNodes: [0],
|
||||||
repeatNodeCount: 2,
|
repeatNodeCount: 3,
|
||||||
tokenData: "%i~R^YZ}pq!Swx!Xxy#]yz#bz{#g{|#l}!O#q!P!Q$d!Q![#y!_!`$i#Y#Z$n#h#i%]~~}~!SOm~~!XOf~~![UOr!Xsw!Xwx!nx;'S!X;'S;=`#V<%lO!X~!sUW~Or!Xsw!Xwx!nx;'S!X;'S;=`#V<%lO!X~#YP;=`<%l!X~#bOi~~#gOj~~#lO_~~#qOa~R#vPbQ!Q![#yP$OQXP!O!P$U!Q![#yP$XP!Q![$[P$aPXP!Q![$[~$iO`~~$nOk~~$qP#T#U$t~$wP#`#a$z~$}P#g#h%Q~%TP#X#Y%W~%]OY~~%`P#f#g%c~%fP#i#j%Q",
|
tokenData: ")c~RdYZ!apq!fwx!kxy#oyz#tz{#y{|$O}!O$T!P!Q$v!Q![$]![!]${!_!`%Q#T#W%V#W#X%e#X#Y&P#Y#Z&z#Z#h%V#h#i(s#i#o%V~~!a~!fOx~~!kOo~~!nUOr!ksw!kwx#Qx;'S!k;'S;=`#i<%lO!k~#VU]~Or!ksw!kwx#Qx;'S!k;'S;=`#i<%lO!k~#lP;=`<%l!k~#tOt~~#yOw~~$OOW~~$TOY~~$YPZ~!Q![$]~$bQ^~!O!P$h!Q![$]~$kP!Q![$n~$sP^~!Q![$n~${OX~~%QOe~~%VOi~Q%YQ!_!`%`#T#o%VQ%eOaQR%hS!_!`%`#T#c%V#c#d%t#d#o%VR%yQfP!_!`%`#T#o%VR&SS!_!`%`#T#b%V#b#c&`#c#o%VR&cS!_!`%`#T#W%V#W#X&o#X#o%VR&tQgP!_!`%`#T#o%V~&}T!_!`%`#T#U'^#U#b%V#b#c(h#c#o%V~'aS!_!`%`#T#`%V#`#a'm#a#o%V~'pS!_!`%`#T#g%V#g#h'|#h#o%V~(PS!_!`%`#T#X%V#X#Y(]#Y#o%V~(bQ_~!_!`%`#T#o%VR(mQcP!_!`%`#T#o%V~(vS!_!`%`#T#f%V#f#g)S#g#o%V~)VS!_!`%`#T#i%V#i#j'|#j#o%V",
|
||||||
tokenizers: [0, 1, tokenizer],
|
tokenizers: [0, 1, tokenizer],
|
||||||
topRules: {"Program":[0,3]},
|
topRules: {"Program":[0,3]},
|
||||||
tokenPrec: 0
|
tokenPrec: 260
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { ExternalTokenizer, InputStream, Stack } from '@lezer/lr'
|
import { ExternalTokenizer, InputStream, Stack } from '@lezer/lr'
|
||||||
import { Identifier, Word, NamedArg } from './shrimp.terms'
|
import { Identifier, Word } from './shrimp.terms'
|
||||||
|
|
||||||
export const tokenizer = new ExternalTokenizer((input: InputStream, stack: Stack) => {
|
export const tokenizer = new ExternalTokenizer((input: InputStream, stack: Stack) => {
|
||||||
let ch = getFullCodePoint(input, 0)
|
let ch = getFullCodePoint(input, 0)
|
||||||
|
|
@ -7,18 +7,15 @@ export const tokenizer = new ExternalTokenizer((input: InputStream, stack: Stack
|
||||||
|
|
||||||
let pos = getCharSize(ch)
|
let pos = getCharSize(ch)
|
||||||
let isValidIdentifier = isLowercaseLetter(ch) || isEmoji(ch)
|
let isValidIdentifier = isLowercaseLetter(ch) || isEmoji(ch)
|
||||||
|
const canBeWord = stack.canShift(Word)
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ch = getFullCodePoint(input, pos)
|
ch = getFullCodePoint(input, pos)
|
||||||
if (isWhitespace(ch) || ch === -1) break
|
if (isWhitespace(ch) || ch === -1) break
|
||||||
|
|
||||||
// Only stop at = if we could parse a NamedArg here
|
|
||||||
if (ch === 61 /* = */ && isValidIdentifier) {
|
|
||||||
break // Stop, let grammar handle identifier = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Track identifier validity
|
// Track identifier validity
|
||||||
if (!isLowercaseLetter(ch) && !isDigit(ch) && ch !== 45 && !isEmoji(ch)) {
|
if (!isLowercaseLetter(ch) && !isDigit(ch) && ch !== 45 && !isEmoji(ch)) {
|
||||||
|
if (!canBeWord) break
|
||||||
isValidIdentifier = false
|
isValidIdentifier = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { Tree, TreeCursor } from '@lezer/common'
|
||||||
import { parser } from '#parser/shrimp'
|
import { parser } from '#parser/shrimp'
|
||||||
import { $ } from 'bun'
|
import { $ } from 'bun'
|
||||||
import { assert } from '#utils/utils'
|
import { assert } from '#utils/utils'
|
||||||
import { evaluate } from '#evaluator/evaluator'
|
import { evaluate } from '#interpreter/evaluator'
|
||||||
|
|
||||||
const regenerateParser = async () => {
|
const regenerateParser = async () => {
|
||||||
let generate = true
|
let generate = true
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user