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:
129
packages/molang/src/MoLang.ts
Normal file
129
packages/molang/src/MoLang.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { ExecutionEnvironment } from './env/env'
|
||||
import { IExpression, IParserConfig } from './main'
|
||||
import { StaticExpression } from './parser/expressions/static'
|
||||
import { StringExpression } from './parser/expressions/string'
|
||||
import { MoLangParser } from './parser/molang'
|
||||
|
||||
export class MoLang {
|
||||
protected expressionCache: Record<string, IExpression> = {}
|
||||
protected totalCacheEntries = 0
|
||||
protected executionEnvironment!: ExecutionEnvironment
|
||||
|
||||
protected parser: MoLangParser
|
||||
|
||||
constructor(
|
||||
env: Record<string, unknown> = {},
|
||||
protected config: Partial<IParserConfig> = {}
|
||||
) {
|
||||
if (config.useOptimizer === undefined) this.config.useOptimizer = true
|
||||
if (config.useCache === undefined) this.config.useCache = true
|
||||
if (config.earlyReturnsSkipParsing === undefined)
|
||||
this.config.earlyReturnsSkipParsing = true
|
||||
if (config.earlyReturnsSkipTokenization === undefined)
|
||||
this.config.earlyReturnsSkipTokenization = true
|
||||
if (config.convertUndefined === undefined)
|
||||
this.config.convertUndefined = false
|
||||
|
||||
this.parser = new MoLangParser({
|
||||
...this.config,
|
||||
tokenizer: undefined,
|
||||
})
|
||||
|
||||
this.updateExecutionEnv(env)
|
||||
}
|
||||
|
||||
updateConfig(newConfig: Partial<IParserConfig>) {
|
||||
newConfig = Object.assign(this.config, newConfig)
|
||||
|
||||
if (newConfig.tokenizer) this.parser.setTokenizer(newConfig.tokenizer)
|
||||
this.parser.updateConfig({ ...this.config, tokenizer: undefined })
|
||||
this.executionEnvironment.updateConfig(newConfig)
|
||||
}
|
||||
updateExecutionEnv(env: Record<string, unknown>, isFlat = false) {
|
||||
this.executionEnvironment = new ExecutionEnvironment(env, {
|
||||
useRadians: this.config.useRadians,
|
||||
convertUndefined: this.config.convertUndefined,
|
||||
isFlat,
|
||||
variableHandler: this.config.variableHandler,
|
||||
})
|
||||
this.parser.setExecutionEnvironment(this.executionEnvironment)
|
||||
}
|
||||
/**
|
||||
* Clears the MoLang expression cache
|
||||
*/
|
||||
clearCache() {
|
||||
this.expressionCache = {}
|
||||
this.totalCacheEntries = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given MoLang string `expression`
|
||||
* @param expression The MoLang string to execute
|
||||
*
|
||||
* @returns The value the MoLang expression corresponds to
|
||||
*/
|
||||
execute(expression: string) {
|
||||
this.parser.setExecutionEnvironment(this.executionEnvironment)
|
||||
const abstractSyntaxTree = this.parse(expression)
|
||||
|
||||
const result = abstractSyntaxTree.eval()
|
||||
if (result === undefined) return 0
|
||||
if (typeof result === 'boolean') return Number(result)
|
||||
return result
|
||||
}
|
||||
/**
|
||||
* Execute the given MoLang string `expression`
|
||||
* In case of errors, return 0
|
||||
* @param expression The MoLang string to execute
|
||||
*
|
||||
* @returns The value the MoLang expression corresponds to and 0 if the statement is invalid
|
||||
*/
|
||||
executeAndCatch(expression: string) {
|
||||
try {
|
||||
return this.execute(expression)
|
||||
} catch {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given MoLang string `expression`
|
||||
* @param expression The MoLang string to parse
|
||||
*
|
||||
* @returns An AST that corresponds to the MoLang expression
|
||||
*/
|
||||
parse(expression: string): IExpression {
|
||||
if (this.config.useCache ?? true) {
|
||||
const abstractSyntaxTree = this.expressionCache[expression]
|
||||
if (abstractSyntaxTree) return abstractSyntaxTree
|
||||
}
|
||||
|
||||
this.parser.init(expression)
|
||||
let abstractSyntaxTree = this.parser.parseExpression()
|
||||
if ((this.config.useOptimizer ?? true) && abstractSyntaxTree.isStatic())
|
||||
abstractSyntaxTree = new StaticExpression(abstractSyntaxTree.eval())
|
||||
// console.log(JSON.stringify(abstractSyntaxTree, null, ' '))
|
||||
|
||||
if (this.config.useCache ?? true) {
|
||||
if (this.totalCacheEntries > (this.config.maxCacheSize || 256))
|
||||
this.clearCache()
|
||||
|
||||
this.expressionCache[expression] = abstractSyntaxTree
|
||||
this.totalCacheEntries++
|
||||
}
|
||||
|
||||
return abstractSyntaxTree
|
||||
}
|
||||
|
||||
resolveStatic(ast: IExpression) {
|
||||
ast.walk((expr) => {
|
||||
if (expr instanceof StringExpression) return
|
||||
|
||||
if (expr.isStatic()) return new StaticExpression(expr.eval())
|
||||
})
|
||||
}
|
||||
|
||||
getParser() {
|
||||
return this.parser
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user