feat: add molang package
1. upgrade bukkit chat 2. fix config update error Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
21
packages/molang/src/parser/parselets/andOperator.ts
Normal file
21
packages/molang/src/parser/parselets/andOperator.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IExpression } from '../expression'
|
||||
import { GenericOperatorExpression } from '../expressions/genericOperator'
|
||||
import { IInfixParselet } from './infix'
|
||||
|
||||
export class AndOperator implements IInfixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, leftExpression: IExpression, token: Token) {
|
||||
if (parser.match('AND'))
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
parser.parseExpression(this.precedence),
|
||||
'&&',
|
||||
(leftExpression: IExpression, rightExpression: IExpression) =>
|
||||
leftExpression.eval() && rightExpression.eval()
|
||||
)
|
||||
else throw new Error(`"&" not followed by another "&"`)
|
||||
}
|
||||
}
|
||||
22
packages/molang/src/parser/parselets/arrayAccess.ts
Normal file
22
packages/molang/src/parser/parselets/arrayAccess.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { Parser } from '../parse'
|
||||
import { IInfixParselet } from './infix'
|
||||
import { IExpression } from '../expression'
|
||||
import { ArrayAccessExpression } from '../expressions/arrayAccess'
|
||||
|
||||
export class ArrayAccessParselet implements IInfixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, left: IExpression, token: Token) {
|
||||
const expr = parser.parseExpression(this.precedence - 1)
|
||||
|
||||
if (!left.setPointer) throw new Error(`"${left.type}" is not an array`)
|
||||
|
||||
if (!parser.match('ARRAY_RIGHT'))
|
||||
throw new Error(
|
||||
`No closing bracket for opening bracket "[${expr.eval()}"`
|
||||
)
|
||||
|
||||
return new ArrayAccessExpression(left, expr)
|
||||
}
|
||||
}
|
||||
134
packages/molang/src/parser/parselets/binaryOperator.ts
Normal file
134
packages/molang/src/parser/parselets/binaryOperator.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import { IInfixParselet } from './infix'
|
||||
import { Parser } from '../parse'
|
||||
import { IExpression } from '../expression'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { GenericOperatorExpression } from '../expressions/genericOperator'
|
||||
|
||||
const plusHelper = (
|
||||
leftExpression: IExpression,
|
||||
rightExpression: IExpression
|
||||
) => {
|
||||
const leftValue = leftExpression.eval()
|
||||
const rightValue = rightExpression.eval()
|
||||
if (
|
||||
!(typeof leftValue === 'number' || typeof leftValue === 'boolean') ||
|
||||
!(typeof rightValue === 'number' || typeof rightValue === 'boolean')
|
||||
)
|
||||
throw new Error(
|
||||
`Cannot use numeric operators for expression "${leftValue} + ${rightValue}"`
|
||||
)
|
||||
//@ts-ignore
|
||||
return leftValue + rightValue
|
||||
}
|
||||
const minusHelper = (
|
||||
leftExpression: IExpression,
|
||||
rightExpression: IExpression
|
||||
) => {
|
||||
const leftValue = leftExpression.eval()
|
||||
const rightValue = rightExpression.eval()
|
||||
if (
|
||||
!(typeof leftValue === 'number' || typeof leftValue === 'boolean') ||
|
||||
!(typeof rightValue === 'number' || typeof rightValue === 'boolean')
|
||||
)
|
||||
throw new Error(
|
||||
`Cannot use numeric operators for expression "${leftValue} - ${rightValue}"`
|
||||
)
|
||||
//@ts-ignore
|
||||
return leftValue - rightValue
|
||||
}
|
||||
const divideHelper = (
|
||||
leftExpression: IExpression,
|
||||
rightExpression: IExpression
|
||||
) => {
|
||||
const leftValue = leftExpression.eval()
|
||||
const rightValue = rightExpression.eval()
|
||||
if (
|
||||
!(typeof leftValue === 'number' || typeof leftValue === 'boolean') ||
|
||||
!(typeof rightValue === 'number' || typeof rightValue === 'boolean')
|
||||
)
|
||||
throw new Error(
|
||||
`Cannot use numeric operators for expression "${leftValue} / ${rightValue}"`
|
||||
)
|
||||
//@ts-ignore
|
||||
return leftValue / rightValue
|
||||
}
|
||||
const multiplyHelper = (
|
||||
leftExpression: IExpression,
|
||||
rightExpression: IExpression
|
||||
) => {
|
||||
const leftValue = leftExpression.eval()
|
||||
const rightValue = rightExpression.eval()
|
||||
if (
|
||||
!(typeof leftValue === 'number' || typeof leftValue === 'boolean') ||
|
||||
!(typeof rightValue === 'number' || typeof rightValue === 'boolean')
|
||||
)
|
||||
throw new Error(
|
||||
`Cannot use numeric operators for expression "${leftValue} * ${rightValue}"`
|
||||
)
|
||||
//@ts-ignore
|
||||
return leftValue * rightValue
|
||||
}
|
||||
const assignHelper = (
|
||||
leftExpression: IExpression,
|
||||
rightExpression: IExpression
|
||||
) => {
|
||||
if (leftExpression.setPointer) {
|
||||
leftExpression.setPointer(rightExpression.eval())
|
||||
return 0
|
||||
} else {
|
||||
throw Error(`Cannot assign to ${leftExpression.type}`)
|
||||
}
|
||||
}
|
||||
|
||||
export class BinaryOperator implements IInfixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, leftExpression: IExpression, token: Token) {
|
||||
const rightExpression = parser.parseExpression(this.precedence)
|
||||
// return new AdditionExpression(leftExpression, rightExpression)
|
||||
|
||||
const tokenText = token.getText()
|
||||
|
||||
switch (tokenText) {
|
||||
case '+':
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
rightExpression,
|
||||
tokenText,
|
||||
plusHelper
|
||||
)
|
||||
case '-':
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
rightExpression,
|
||||
tokenText,
|
||||
minusHelper
|
||||
)
|
||||
case '*':
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
rightExpression,
|
||||
tokenText,
|
||||
multiplyHelper
|
||||
)
|
||||
case '/':
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
rightExpression,
|
||||
tokenText,
|
||||
divideHelper
|
||||
)
|
||||
case '=': {
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
rightExpression,
|
||||
'=',
|
||||
assignHelper
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Operator not implemented`)
|
||||
}
|
||||
}
|
||||
}
|
||||
12
packages/molang/src/parser/parselets/boolean.ts
Normal file
12
packages/molang/src/parser/parselets/boolean.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { IPrefixParselet } from './prefix'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { Parser } from '../parse'
|
||||
import { BooleanExpression } from '../expressions/boolean'
|
||||
|
||||
export class BooleanParselet implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
return new BooleanExpression(token.getText() === 'true')
|
||||
}
|
||||
}
|
||||
12
packages/molang/src/parser/parselets/break.ts
Normal file
12
packages/molang/src/parser/parselets/break.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IPrefixParselet } from './prefix'
|
||||
import { BreakExpression } from '../expressions/break'
|
||||
|
||||
export class BreakParselet implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
return new BreakExpression()
|
||||
}
|
||||
}
|
||||
12
packages/molang/src/parser/parselets/continue.ts
Normal file
12
packages/molang/src/parser/parselets/continue.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IPrefixParselet } from './prefix'
|
||||
import { ContinueExpression } from '../expressions/continue'
|
||||
|
||||
export class ContinueParselet implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
return new ContinueExpression()
|
||||
}
|
||||
}
|
||||
19
packages/molang/src/parser/parselets/equals.ts
Normal file
19
packages/molang/src/parser/parselets/equals.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Parser } from '../../parser/parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IExpression } from '../expression'
|
||||
import { GenericOperatorExpression } from '../expressions/genericOperator'
|
||||
import { IInfixParselet } from './infix'
|
||||
|
||||
export class EqualsOperator implements IInfixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, leftExpression: IExpression, token: Token) {
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
parser.parseExpression(this.precedence),
|
||||
'==',
|
||||
(leftExpression: IExpression, rightExpression: IExpression) =>
|
||||
leftExpression.eval() === rightExpression.eval()
|
||||
)
|
||||
}
|
||||
}
|
||||
29
packages/molang/src/parser/parselets/forEach.ts
Normal file
29
packages/molang/src/parser/parselets/forEach.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IPrefixParselet } from './prefix'
|
||||
import { IExpression } from '../expression'
|
||||
import { ForEachExpression } from '../expressions/forEach'
|
||||
|
||||
export class ForEachParselet implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
parser.consume('LEFT_PARENT')
|
||||
const args: IExpression[] = []
|
||||
|
||||
if (parser.match('RIGHT_PARENT'))
|
||||
throw new Error(`for_each() called without arguments`)
|
||||
|
||||
do {
|
||||
args.push(parser.parseExpression())
|
||||
} while (parser.match('COMMA'))
|
||||
parser.consume('RIGHT_PARENT')
|
||||
|
||||
if (args.length !== 3)
|
||||
throw new Error(
|
||||
`There must be exactly three for_each() arguments; found ${args.length}`
|
||||
)
|
||||
|
||||
return new ForEachExpression(args[0], args[1], args[2])
|
||||
}
|
||||
}
|
||||
26
packages/molang/src/parser/parselets/function.ts
Normal file
26
packages/molang/src/parser/parselets/function.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { Parser } from '../parse'
|
||||
import { IInfixParselet } from './infix'
|
||||
import { IExpression } from '../expression'
|
||||
import { FunctionExpression } from '../expressions/function'
|
||||
|
||||
export class FunctionParselet implements IInfixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, left: IExpression, token: Token) {
|
||||
const args: IExpression[] = []
|
||||
|
||||
if (!left.setFunctionCall)
|
||||
throw new Error(`${left.type} is not callable!`)
|
||||
left.setFunctionCall(true)
|
||||
|
||||
if (!parser.match('RIGHT_PARENT')) {
|
||||
do {
|
||||
args.push(parser.parseExpression())
|
||||
} while (parser.match('COMMA'))
|
||||
parser.consume('RIGHT_PARENT')
|
||||
}
|
||||
|
||||
return new FunctionExpression(left, args)
|
||||
}
|
||||
}
|
||||
31
packages/molang/src/parser/parselets/greaterOperator.ts
Normal file
31
packages/molang/src/parser/parselets/greaterOperator.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IExpression } from '../expression'
|
||||
import { GenericOperatorExpression } from '../expressions/genericOperator'
|
||||
import { IInfixParselet } from './infix'
|
||||
|
||||
export class GreaterOperator implements IInfixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, leftExpression: IExpression, token: Token) {
|
||||
if (parser.match('EQUALS'))
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
parser.parseExpression(this.precedence),
|
||||
'>=',
|
||||
(leftExpression: IExpression, rightExpression: IExpression) =>
|
||||
// @ts-ignore
|
||||
leftExpression.eval() >= rightExpression.eval()
|
||||
)
|
||||
else {
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
parser.parseExpression(this.precedence),
|
||||
'>',
|
||||
(leftExpression: IExpression, rightExpression: IExpression) =>
|
||||
// @ts-ignore
|
||||
leftExpression.eval() > rightExpression.eval()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
18
packages/molang/src/parser/parselets/groupParselet.ts
Normal file
18
packages/molang/src/parser/parselets/groupParselet.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { IPrefixParselet } from './prefix'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { Parser } from '../parse'
|
||||
import { GroupExpression } from '../expressions/group'
|
||||
|
||||
export class GroupParselet implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
const expression = parser.parseExpression(this.precedence)
|
||||
parser.consume('RIGHT_PARENT')
|
||||
|
||||
if (parser.config.keepGroups)
|
||||
return new GroupExpression(expression, '()')
|
||||
|
||||
return expression
|
||||
}
|
||||
}
|
||||
8
packages/molang/src/parser/parselets/infix.ts
Normal file
8
packages/molang/src/parser/parselets/infix.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Parser } from '../parse'
|
||||
import { IExpression } from '../expression'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
|
||||
export interface IInfixParselet {
|
||||
readonly precedence: number
|
||||
parse: (parser: Parser, left: IExpression, token: Token) => IExpression
|
||||
}
|
||||
29
packages/molang/src/parser/parselets/loop.ts
Normal file
29
packages/molang/src/parser/parselets/loop.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IPrefixParselet } from './prefix'
|
||||
import { IExpression } from '../expression'
|
||||
import { LoopExpression } from '../expressions/loop'
|
||||
|
||||
export class LoopParselet implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
parser.consume('LEFT_PARENT')
|
||||
const args: IExpression[] = []
|
||||
|
||||
if (parser.match('RIGHT_PARENT'))
|
||||
throw new Error(`loop() called without arguments`)
|
||||
|
||||
do {
|
||||
args.push(parser.parseExpression())
|
||||
} while (parser.match('COMMA'))
|
||||
parser.consume('RIGHT_PARENT')
|
||||
|
||||
if (args.length !== 2)
|
||||
throw new Error(
|
||||
`There must be exactly two loop() arguments; found ${args.length}`
|
||||
)
|
||||
|
||||
return new LoopExpression(args[0], args[1])
|
||||
}
|
||||
}
|
||||
43
packages/molang/src/parser/parselets/name.ts
Normal file
43
packages/molang/src/parser/parselets/name.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { IPrefixParselet } from './prefix'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { Parser } from '../parse'
|
||||
import { NameExpression } from '../expressions/name'
|
||||
import { ContextSwitchExpression } from '../expressions/contextSwitch'
|
||||
|
||||
export class NameParselet implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
const nameExpr = new NameExpression(
|
||||
parser.executionEnv,
|
||||
token.getText()
|
||||
)
|
||||
const nextTokens = <const>[parser.lookAhead(0), parser.lookAhead(1)]
|
||||
|
||||
// Context switching operator "->"
|
||||
if (
|
||||
nextTokens[0].getType() === 'MINUS' &&
|
||||
nextTokens[1].getType() === 'GREATER'
|
||||
) {
|
||||
parser.consume('MINUS')
|
||||
parser.consume('GREATER')
|
||||
|
||||
const nameToken = parser.lookAhead(0)
|
||||
if (nameToken.getType() !== 'NAME')
|
||||
throw new Error(
|
||||
`Cannot use context switch operator "->" on ${parser.lookAhead(
|
||||
0
|
||||
)}`
|
||||
)
|
||||
|
||||
parser.consume('NAME')
|
||||
|
||||
return new ContextSwitchExpression(
|
||||
nameExpr,
|
||||
new NameExpression(parser.executionEnv, nameToken.getText())
|
||||
)
|
||||
}
|
||||
|
||||
return nameExpr
|
||||
}
|
||||
}
|
||||
23
packages/molang/src/parser/parselets/notEquals.ts
Normal file
23
packages/molang/src/parser/parselets/notEquals.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IExpression } from '../expression'
|
||||
import { GenericOperatorExpression } from '../expressions/genericOperator'
|
||||
import { IInfixParselet } from './infix'
|
||||
|
||||
export class NotEqualsOperator implements IInfixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, leftExpression: IExpression, token: Token) {
|
||||
if (parser.match('EQUALS')) {
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
parser.parseExpression(this.precedence),
|
||||
'!=',
|
||||
(leftExpression: IExpression, rightExpression: IExpression) =>
|
||||
leftExpression.eval() !== rightExpression.eval()
|
||||
)
|
||||
} else {
|
||||
throw new Error(`! was used as a binary operator`)
|
||||
}
|
||||
}
|
||||
}
|
||||
12
packages/molang/src/parser/parselets/number.ts
Normal file
12
packages/molang/src/parser/parselets/number.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { IPrefixParselet } from './prefix'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { Parser } from '../parse'
|
||||
import { NumberExpression } from '../expressions/number'
|
||||
|
||||
export class NumberParselet implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
return new NumberExpression(Number(token.getText()))
|
||||
}
|
||||
}
|
||||
21
packages/molang/src/parser/parselets/orOperator.ts
Normal file
21
packages/molang/src/parser/parselets/orOperator.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IExpression } from '../expression'
|
||||
import { GenericOperatorExpression } from '../expressions/genericOperator'
|
||||
import { IInfixParselet } from './infix'
|
||||
|
||||
export class OrOperator implements IInfixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, leftExpression: IExpression, token: Token) {
|
||||
if (parser.match('OR'))
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
parser.parseExpression(this.precedence),
|
||||
'||',
|
||||
(leftExpression: IExpression, rightExpression: IExpression) =>
|
||||
leftExpression.eval() || rightExpression.eval()
|
||||
)
|
||||
else throw new Error(`"|" not followed by another "|"`)
|
||||
}
|
||||
}
|
||||
3
packages/molang/src/parser/parselets/postfix.ts
Normal file
3
packages/molang/src/parser/parselets/postfix.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { IInfixParselet } from './infix'
|
||||
|
||||
export interface IPostfixParselet extends IInfixParselet {}
|
||||
20
packages/molang/src/parser/parselets/prefix.ts
Normal file
20
packages/molang/src/parser/parselets/prefix.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Parser } from '../parse'
|
||||
import { IExpression } from '../expression'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { PrefixExpression } from '../expressions/prefix'
|
||||
|
||||
export interface IPrefixParselet {
|
||||
readonly precedence: number
|
||||
parse: (parser: Parser, token: Token) => IExpression
|
||||
}
|
||||
|
||||
export class PrefixOperator implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
return new PrefixExpression(
|
||||
token.getType(),
|
||||
parser.parseExpression(this.precedence)
|
||||
)
|
||||
}
|
||||
}
|
||||
26
packages/molang/src/parser/parselets/questionOperator.ts
Normal file
26
packages/molang/src/parser/parselets/questionOperator.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IExpression } from '../expression'
|
||||
import { GenericOperatorExpression } from '../expressions/genericOperator'
|
||||
import { IInfixParselet } from './infix'
|
||||
import { TernaryParselet } from './ternary'
|
||||
import { EPrecedence } from '../precedence'
|
||||
|
||||
const ternaryParselet = new TernaryParselet(EPrecedence.CONDITIONAL)
|
||||
export class QuestionOperator implements IInfixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, leftExpression: IExpression, token: Token) {
|
||||
if (parser.match('QUESTION')) {
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
parser.parseExpression(this.precedence),
|
||||
'??',
|
||||
(leftExpression: IExpression, rightExpression: IExpression) =>
|
||||
leftExpression.eval() ?? rightExpression.eval()
|
||||
)
|
||||
} else {
|
||||
return ternaryParselet.parse(parser, leftExpression, token)
|
||||
}
|
||||
}
|
||||
}
|
||||
18
packages/molang/src/parser/parselets/return.ts
Normal file
18
packages/molang/src/parser/parselets/return.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IPrefixParselet } from './prefix'
|
||||
import { NumberExpression } from '../expressions/number'
|
||||
import { ReturnExpression } from '../expressions/return'
|
||||
import { EPrecedence } from '../precedence'
|
||||
|
||||
export class ReturnParselet implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
const expr = parser.parseExpression(EPrecedence.STATEMENT + 1)
|
||||
|
||||
return new ReturnExpression(
|
||||
parser.match('SEMICOLON', false) ? expr : new NumberExpression(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
22
packages/molang/src/parser/parselets/scope.ts
Normal file
22
packages/molang/src/parser/parselets/scope.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IPrefixParselet } from './prefix'
|
||||
import { GroupExpression } from '../expressions/group'
|
||||
|
||||
export class ScopeParselet implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
let expr = parser.parseExpression(this.precedence)
|
||||
|
||||
if (
|
||||
parser.config.useOptimizer &&
|
||||
parser.config.earlyReturnsSkipTokenization &&
|
||||
expr.isReturn
|
||||
)
|
||||
parser.match('CURLY_RIGHT')
|
||||
else parser.consume('CURLY_RIGHT')
|
||||
|
||||
return parser.config.keepGroups ? new GroupExpression(expr, '{}') : expr
|
||||
}
|
||||
}
|
||||
31
packages/molang/src/parser/parselets/smallerOperator.ts
Normal file
31
packages/molang/src/parser/parselets/smallerOperator.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { Parser } from '../parse'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IExpression } from '../expression'
|
||||
import { GenericOperatorExpression } from '../expressions/genericOperator'
|
||||
import { IInfixParselet } from './infix'
|
||||
|
||||
export class SmallerOperator implements IInfixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, leftExpression: IExpression, token: Token) {
|
||||
if (parser.match('EQUALS'))
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
parser.parseExpression(this.precedence),
|
||||
'<=',
|
||||
(leftExpression: IExpression, rightExpression: IExpression) =>
|
||||
// @ts-ignore
|
||||
leftExpression.eval() <= rightExpression.eval()
|
||||
)
|
||||
else {
|
||||
return new GenericOperatorExpression(
|
||||
leftExpression,
|
||||
parser.parseExpression(this.precedence),
|
||||
'<',
|
||||
(leftExpression: IExpression, rightExpression: IExpression) =>
|
||||
// @ts-ignore
|
||||
leftExpression.eval() < rightExpression.eval()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
84
packages/molang/src/parser/parselets/statement.ts
Normal file
84
packages/molang/src/parser/parselets/statement.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { Parser } from '../parse'
|
||||
import { IExpression } from '../expression'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { IInfixParselet } from './infix'
|
||||
import { StatementExpression } from '../expressions/statement'
|
||||
import { StaticExpression } from '../expressions/static'
|
||||
|
||||
export class StatementParselet implements IInfixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
findReEntryPoint(parser: Parser) {
|
||||
let bracketCount = 1
|
||||
let tokenType = parser.lookAhead(0).getType()
|
||||
while (tokenType !== 'EOF') {
|
||||
if (tokenType == 'CURLY_RIGHT') bracketCount--
|
||||
else if (tokenType === 'CURLY_LEFT') bracketCount++
|
||||
if (bracketCount === 0) break
|
||||
|
||||
parser.consume()
|
||||
tokenType = parser.lookAhead(0).getType()
|
||||
}
|
||||
}
|
||||
|
||||
parse(parser: Parser, left: IExpression, token: Token) {
|
||||
if (parser.config.useOptimizer) {
|
||||
if (left.isStatic())
|
||||
left = new StaticExpression(left.eval(), left.isReturn)
|
||||
|
||||
if (parser.config.earlyReturnsSkipParsing && left.isReturn) {
|
||||
if (!parser.config.earlyReturnsSkipTokenization)
|
||||
this.findReEntryPoint(parser)
|
||||
|
||||
return new StatementExpression([left])
|
||||
}
|
||||
}
|
||||
|
||||
const expressions: IExpression[] = [left]
|
||||
|
||||
if (!parser.match('CURLY_RIGHT', false)) {
|
||||
do {
|
||||
let expr = parser.parseExpression(this.precedence)
|
||||
if (parser.config.useOptimizer) {
|
||||
if (expr.isStatic()) {
|
||||
if (
|
||||
parser.config.useAgressiveStaticOptimizer &&
|
||||
!expr.isReturn
|
||||
)
|
||||
continue
|
||||
expr = new StaticExpression(expr.eval(), expr.isReturn)
|
||||
}
|
||||
|
||||
if (
|
||||
parser.config.earlyReturnsSkipParsing &&
|
||||
(expr.isBreak || expr.isContinue || expr.isReturn)
|
||||
) {
|
||||
expressions.push(expr)
|
||||
|
||||
if (!parser.config.earlyReturnsSkipTokenization)
|
||||
this.findReEntryPoint(parser)
|
||||
|
||||
return new StatementExpression(expressions)
|
||||
}
|
||||
}
|
||||
|
||||
expressions.push(expr)
|
||||
} while (
|
||||
parser.match('SEMICOLON') &&
|
||||
!parser.match('EOF') &&
|
||||
!parser.match('CURLY_RIGHT', false)
|
||||
)
|
||||
}
|
||||
|
||||
parser.match('SEMICOLON')
|
||||
|
||||
const statementExpr = new StatementExpression(expressions)
|
||||
// if (parser.config.useOptimizer && statementExpr.isStatic()) {
|
||||
// return new StaticExpression(
|
||||
// statementExpr.eval(),
|
||||
// statementExpr.isReturn
|
||||
// )
|
||||
// }
|
||||
return statementExpr
|
||||
}
|
||||
}
|
||||
12
packages/molang/src/parser/parselets/string.ts
Normal file
12
packages/molang/src/parser/parselets/string.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { IPrefixParselet } from './prefix'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { Parser } from '../parse'
|
||||
import { StringExpression } from '../expressions/string'
|
||||
|
||||
export class StringParselet implements IPrefixParselet {
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, token: Token) {
|
||||
return new StringExpression(token.getText())
|
||||
}
|
||||
}
|
||||
28
packages/molang/src/parser/parselets/ternary.ts
Normal file
28
packages/molang/src/parser/parselets/ternary.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { IInfixParselet } from './infix'
|
||||
import { Parser } from '../parse'
|
||||
import { IExpression } from '../expression'
|
||||
import { Token } from '../../tokenizer/token'
|
||||
import { TernaryExpression } from '../expressions/ternary'
|
||||
import { VoidExpression } from '../expressions/void'
|
||||
|
||||
export class TernaryParselet implements IInfixParselet {
|
||||
exprName = 'Ternary'
|
||||
constructor(public precedence = 0) {}
|
||||
|
||||
parse(parser: Parser, leftExpression: IExpression, token: Token) {
|
||||
let thenExpr = parser.parseExpression(this.precedence - 1)
|
||||
let elseExpr: IExpression
|
||||
|
||||
if (parser.match('COLON')) {
|
||||
elseExpr = parser.parseExpression(this.precedence - 1)
|
||||
} else {
|
||||
elseExpr = new VoidExpression()
|
||||
}
|
||||
|
||||
if (parser.config.useOptimizer && leftExpression.isStatic()) {
|
||||
return leftExpression.eval() ? thenExpr : elseExpr
|
||||
}
|
||||
|
||||
return new TernaryExpression(leftExpression, thenExpr, elseExpr)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user