// https://ericsmekens.github.io/jsep
import {parse} from '@/utils/expression-eval'
class Ast {
static transToAstArray(ast) {
const tags = []
let layer = ast
console.log('layer', layer)
while(layer) {
switch(layer.type) {
case 'MemberExpression': {
const operator = layer.computed ? '[]' : '.'
const right = Ast.transToAstArray(layer.property)
tags.push({operator: operator, left: '', right, type: layer.type })
layer = layer.object
break
}
case 'CallExpression': {
// tags.push(this.ViewModel.find(layer.arguments[0].value).name)
let operator = '.'
let right = ''
const calleeType = layer.callee.type
if (calleeType === 'CallExpression') {
operator = ''
right = Ast.transToAstArray(layer.callee)
} else if (calleeType === 'MemberExpression') {
operator = layer.callee?.computed ? '[]' : '.'
right = Ast.transToAstArray(layer.callee.property)
} else { // FIXME, 未测试,还不确定其他情况, 暂时用MemberExpression的值
right = Ast.transToAstArray(layer.callee.property)
}
tags.push({ operator, left: '', right, args: layer.arguments.map(arg => Ast.transToAstArray(arg)), type: layer.type })
layer = layer.callee.object
break
}
case 'Identifier':
tags.push({ operator: '', left: '', right: layer.name, type: layer.type })
layer = layer.object
break
case 'BinaryExpression':
case 'LogicalExpression':
tags.push({ operator: layer.operator, left: Ast.transToAstArray(layer.left), right: Ast.transToAstArray(layer.right), type: layer.type })
layer = layer.object
break
// !a, a++, ++a, a--, --a
case 'UnaryExpression':
tags.push({
operator: layer.operator,
left: '',
right: layer.argument ? Ast.transToAstArray(layer.argument) : '',
type: layer.type
})
layer = layer.object
break
case 'Literal':
tags.push({
operator: '',
left: '',
right: typeof layer.value === 'string' ? `'${ layer.value }'` : layer.value,
type: layer.type
})
layer = layer.object
break
default:
layer = null
}
}
return tags.reverse()
}
static transToExpression(astArray, isEntry = true) {
let expression = ''
for(const cLayer of astArray) {
switch (cLayer.type) {
// + - * /
case 'BinaryExpression':
// a[0]
case 'LogicalExpression': {
const leftExpression = this.transToExpression(cLayer.left, false)
const rightExpression = this.transToExpression(cLayer.right, false)
expression = cLayer.operator === '[]' ? `${leftExpression}[${rightExpression}]` : `${leftExpression}${cLayer.operator}${rightExpression}`
if (!isEntry) {
expression = `(${expression})`
}
break
}
// ! ++ --
case 'UnaryExpression': {
let leftExpression = this.transToExpression(cLayer.left, false)
let rightExpression = this.transToExpression(cLayer.right, false)
expression = cLayer.operator === '[]' ? `${leftExpression}[${rightExpression}]` : `${leftExpression}${cLayer.operator}${rightExpression}`
break
}
case 'MemberExpression': {
const rightExpression = this.transToExpression(cLayer.right, false)
expression = cLayer.operator === '[]' ? `${expression}${cLayer.left}[${rightExpression}]` : `${expression}${cLayer.left}${cLayer.operator}${rightExpression}`
break
}
// 函数
case 'CallExpression':
// 函数参数
const rightExpression = this.transToExpression(cLayer.right, false)
const args = cLayer.args.map(argument => this.transToExpression(argument, true))
expression = cLayer.operator === '[]' ? `${expression}${cLayer.left}[${rightExpression}](${args.join(',')})` : `${expression}${cLayer.left}${cLayer.operator}${rightExpression}(${args.join(',')})`
break
default:
expression = cLayer.operator === '[]' ? `${expression}${cLayer.left}[${cLayer.right}]` : `${expression}${cLayer.left}${cLayer.operator}${cLayer.right}`
}
}
return expression
}
constructor() {
// 最后一次正确的解析表达式
this.expression = ''
// 当前表达式
this._expression = ''
this._error = null
}
get ast() {
return this._ast
}
set ast(val) {
this._ast = val
this._astArray = Ast.transToAstArray(val)
this._astExpression = Ast.transToExpression(this._astArray)
}
update(expression) {
try {
// parse expression
const ast = parse(expression)
this.expression = expression
this.ast = ast
this._expression = expression
this._error = null
} catch (err) {
console.error('expression parse error:', err)
this._expression = expression
this._error = err
}
return this
}
}
export default Ast