如何将这个树结构转换成JS MemberExpression树结构呢?
How to convert this tree structure into a JS MemberExpression tree structure?
我找到了一种使用我自己的树格式表示表达式 a.b[c.d][e].f[g[h[i.j]]]
的方法。该表达式表示为一棵树,如下所示:
{
"form": "nest",
"link": [
{
"form": "site",
"name": "a"
},
{
"form": "site",
"name": "b"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "c"
},
{
"form": "site",
"name": "d"
}
]
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "e"
}
]
},
{
"form": "site",
"name": "f"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "g"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "h"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "i"
},
{
"form": "site",
"name": "j"
}
]
}
]
}
]
}
]
}
现在,同样的字符串表达式也由 MemberExpression
的 JS AST 树结构表示:
{
"type": "MemberExpression",
"object": {
"type": "MemberExpression",
"object": {
"type": "MemberExpression",
"object": {
"type": "MemberExpression",
"object": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "a"
},
"property": {
"type": "Identifier",
"name": "b"
},
"computed": false
},
"property": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "c"
},
"property": {
"type": "Identifier",
"name": "d"
},
"computed": false
},
"computed": true
},
"property": {
"type": "Identifier",
"name": "e"
},
"computed": true
},
"property": {
"type": "Identifier",
"name": "f"
},
"computed": false
},
"property": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "g"
},
"property": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "h"
},
"property": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "i"
},
"property": {
"type": "Identifier",
"name": "j"
},
"computed": false
},
"computed": true
},
"computed": true
},
"computed": true
}
所以这两个树结构表示相同的字符串表达式a.b[c.d][e].f[g[h[i.j]]]
。您会注意到在第一个“嵌套”结构上,有两种类型的对象、站点和嵌套。站点只是一个名称,而嵌套在 JS AST 术语中表示“计算的”属性。所以嵌套就像 parent[this_is_a_nest[and_another_nest]]
,而 parent.site1.site2
.
如何将第一个树结构转换为第二个树结构?
到目前为止,我还没有真正做到这一点,这很令人困惑。
console.log(JSON.stringify(transform(getNest()), null, 2))
function transform(nest) {
let i = 0
let stack = []
while (i < nest.link.length) {
let object = nest.link[i++]
let property = nest.link[i]
let member = {
type: 'MemberExpression'
}
stack.push(member)
if (object.form === 'nest') {
member.object = transform(object)
} else {
member.object = {
type: 'Identifier',
name: object.name
}
}
if (property) {
if (property.form === 'nest') {
member.property = transform(property)
member.computed = true
} else {
member.property = {
type: 'Identifier',
name: property.name
}
}
}
}
let object = stack.pop()
while (stack.length) {
let nextObject = stack.pop()
nextObject.object = object
object = nextObject
}
return object
}
function getNest() {
return {
"form": "nest",
"link": [
{
"form": "site",
"name": "a"
},
{
"form": "site",
"name": "b"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "c"
},
{
"form": "site",
"name": "d"
}
]
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "e"
}
]
},
{
"form": "site",
"name": "f"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "g"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "h"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "i"
},
{
"form": "site",
"name": "j"
}
]
}
]
}
]
}
]
}
}
还不知道如何简化问题以解决问题。
我不知道 this 是否有任何帮助(MemberExpression 的 acornjs 解析器)。
应该这样做:
function transform(treeNode) {
if (treeNode.form == "site") {
return {
"type": "Identifier",
"name": treeNode.name,
};
} else if (treeNode.form == "nest") {
const [base, ...props] = treeNode.link;
console.assert(base.form == "site");
return props.reduce((lhs, rhs) => {
if (rhs.form == "nest") {
return {
"type": "MemberExpression",
"object": lhs,
"property": transform(rhs), // returns MemberExpression or (if singleton) Identifier
"computed": true,
};
} else if (rhs.form == "site") {
return {
"type": "MemberExpression",
"object": lhs,
"property": transform(rhs), // returns Identifier
"computed": false,
};
}
}, transform(base));
}
}
你当然可以将reducer简化为
props.reduce((lhs, rhs) => ({
"type": "MemberExpression",
"object": lhs,
"property": transform(rhs),
"computed": rhs.form == "nest",
}), transform(base));
在看到@Bergi的回答后,我刚刚稍微解决了这个问题,太激动了!
function transform(nest) {
let i = 0
let stack = [{
type: 'Identifier',
name: nest.link[i++].name
}]
while (i < nest.link.length) {
const object = stack.shift()
const node = nest.link[i++]
if (node.form === 'nest') {
const property = transform(node)
stack.push({
object: object,
property,
computed: true
})
} else {
let property = {
type: 'Identifier',
name: node.name
}
stack.push({
object: object,
property: property,
computed: false
})
}
}
return stack.shift()
}
输出为:
{
"object": {
"object": {
"object": {
"object": {
"object": {
"type": "Identifier",
"name": "a"
},
"property": {
"type": "Identifier",
"name": "b"
},
"computed": false
},
"property": {
"object": {
"type": "Identifier",
"name": "c"
},
"property": {
"type": "Identifier",
"name": "d"
},
"computed": false
},
"computed": true
},
"property": {
"type": "Identifier",
"name": "e"
},
"computed": true
},
"property": {
"type": "Identifier",
"name": "f"
},
"computed": false
},
"property": {
"object": {
"type": "Identifier",
"name": "g"
},
"property": {
"object": {
"type": "Identifier",
"name": "h"
},
"property": {
"object": {
"type": "Identifier",
"name": "i"
},
"property": {
"type": "Identifier",
"name": "j"
},
"computed": false
},
"computed": true
},
"computed": true
},
"computed": true
}
更短的递归解决方案:
function mem_tree(objs){
var o = null;
for (var obj of objs){
if (obj.form === 'site'){
o = (o === null) ? {type:"Identifier", name:obj.name} : {type: "MemberExpression", object:o, property:{type:"Identifier", name:obj.name}, computed:false}
}
else{
var r = mem_tree(obj.link);
o = (o === null) ? {object:r} : {type: "MemberExpression", object:o, property:r, computed:true}
}
}
return o;
}
var d = {'form': 'nest', 'link': [{'form': 'site', 'name': 'a'}, {'form': 'site', 'name': 'b'}, {'form': 'nest', 'link': [{'form': 'site', 'name': 'c'}, {'form': 'site', 'name': 'd'}]}, {'form': 'nest', 'link': [{'form': 'site', 'name': 'e'}]}, {'form': 'site', 'name': 'f'}, {'form': 'nest', 'link': [{'form': 'site', 'name': 'g'}, {'form': 'nest', 'link': [{'form': 'site', 'name': 'h'}, {'form': 'nest', 'link': [{'form': 'site', 'name': 'i'}, {'form': 'site', 'name': 'j'}]}]}]}]}
var result = mem_tree(d.link)
我找到了一种使用我自己的树格式表示表达式 a.b[c.d][e].f[g[h[i.j]]]
的方法。该表达式表示为一棵树,如下所示:
{
"form": "nest",
"link": [
{
"form": "site",
"name": "a"
},
{
"form": "site",
"name": "b"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "c"
},
{
"form": "site",
"name": "d"
}
]
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "e"
}
]
},
{
"form": "site",
"name": "f"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "g"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "h"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "i"
},
{
"form": "site",
"name": "j"
}
]
}
]
}
]
}
]
}
现在,同样的字符串表达式也由 MemberExpression
的 JS AST 树结构表示:
{
"type": "MemberExpression",
"object": {
"type": "MemberExpression",
"object": {
"type": "MemberExpression",
"object": {
"type": "MemberExpression",
"object": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "a"
},
"property": {
"type": "Identifier",
"name": "b"
},
"computed": false
},
"property": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "c"
},
"property": {
"type": "Identifier",
"name": "d"
},
"computed": false
},
"computed": true
},
"property": {
"type": "Identifier",
"name": "e"
},
"computed": true
},
"property": {
"type": "Identifier",
"name": "f"
},
"computed": false
},
"property": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "g"
},
"property": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "h"
},
"property": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "i"
},
"property": {
"type": "Identifier",
"name": "j"
},
"computed": false
},
"computed": true
},
"computed": true
},
"computed": true
}
所以这两个树结构表示相同的字符串表达式a.b[c.d][e].f[g[h[i.j]]]
。您会注意到在第一个“嵌套”结构上,有两种类型的对象、站点和嵌套。站点只是一个名称,而嵌套在 JS AST 术语中表示“计算的”属性。所以嵌套就像 parent[this_is_a_nest[and_another_nest]]
,而 parent.site1.site2
.
如何将第一个树结构转换为第二个树结构?
到目前为止,我还没有真正做到这一点,这很令人困惑。
console.log(JSON.stringify(transform(getNest()), null, 2))
function transform(nest) {
let i = 0
let stack = []
while (i < nest.link.length) {
let object = nest.link[i++]
let property = nest.link[i]
let member = {
type: 'MemberExpression'
}
stack.push(member)
if (object.form === 'nest') {
member.object = transform(object)
} else {
member.object = {
type: 'Identifier',
name: object.name
}
}
if (property) {
if (property.form === 'nest') {
member.property = transform(property)
member.computed = true
} else {
member.property = {
type: 'Identifier',
name: property.name
}
}
}
}
let object = stack.pop()
while (stack.length) {
let nextObject = stack.pop()
nextObject.object = object
object = nextObject
}
return object
}
function getNest() {
return {
"form": "nest",
"link": [
{
"form": "site",
"name": "a"
},
{
"form": "site",
"name": "b"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "c"
},
{
"form": "site",
"name": "d"
}
]
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "e"
}
]
},
{
"form": "site",
"name": "f"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "g"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "h"
},
{
"form": "nest",
"link": [
{
"form": "site",
"name": "i"
},
{
"form": "site",
"name": "j"
}
]
}
]
}
]
}
]
}
}
还不知道如何简化问题以解决问题。
我不知道 this 是否有任何帮助(MemberExpression 的 acornjs 解析器)。
应该这样做:
function transform(treeNode) {
if (treeNode.form == "site") {
return {
"type": "Identifier",
"name": treeNode.name,
};
} else if (treeNode.form == "nest") {
const [base, ...props] = treeNode.link;
console.assert(base.form == "site");
return props.reduce((lhs, rhs) => {
if (rhs.form == "nest") {
return {
"type": "MemberExpression",
"object": lhs,
"property": transform(rhs), // returns MemberExpression or (if singleton) Identifier
"computed": true,
};
} else if (rhs.form == "site") {
return {
"type": "MemberExpression",
"object": lhs,
"property": transform(rhs), // returns Identifier
"computed": false,
};
}
}, transform(base));
}
}
你当然可以将reducer简化为
props.reduce((lhs, rhs) => ({
"type": "MemberExpression",
"object": lhs,
"property": transform(rhs),
"computed": rhs.form == "nest",
}), transform(base));
在看到@Bergi的回答后,我刚刚稍微解决了这个问题,太激动了!
function transform(nest) {
let i = 0
let stack = [{
type: 'Identifier',
name: nest.link[i++].name
}]
while (i < nest.link.length) {
const object = stack.shift()
const node = nest.link[i++]
if (node.form === 'nest') {
const property = transform(node)
stack.push({
object: object,
property,
computed: true
})
} else {
let property = {
type: 'Identifier',
name: node.name
}
stack.push({
object: object,
property: property,
computed: false
})
}
}
return stack.shift()
}
输出为:
{
"object": {
"object": {
"object": {
"object": {
"object": {
"type": "Identifier",
"name": "a"
},
"property": {
"type": "Identifier",
"name": "b"
},
"computed": false
},
"property": {
"object": {
"type": "Identifier",
"name": "c"
},
"property": {
"type": "Identifier",
"name": "d"
},
"computed": false
},
"computed": true
},
"property": {
"type": "Identifier",
"name": "e"
},
"computed": true
},
"property": {
"type": "Identifier",
"name": "f"
},
"computed": false
},
"property": {
"object": {
"type": "Identifier",
"name": "g"
},
"property": {
"object": {
"type": "Identifier",
"name": "h"
},
"property": {
"object": {
"type": "Identifier",
"name": "i"
},
"property": {
"type": "Identifier",
"name": "j"
},
"computed": false
},
"computed": true
},
"computed": true
},
"computed": true
}
更短的递归解决方案:
function mem_tree(objs){
var o = null;
for (var obj of objs){
if (obj.form === 'site'){
o = (o === null) ? {type:"Identifier", name:obj.name} : {type: "MemberExpression", object:o, property:{type:"Identifier", name:obj.name}, computed:false}
}
else{
var r = mem_tree(obj.link);
o = (o === null) ? {object:r} : {type: "MemberExpression", object:o, property:r, computed:true}
}
}
return o;
}
var d = {'form': 'nest', 'link': [{'form': 'site', 'name': 'a'}, {'form': 'site', 'name': 'b'}, {'form': 'nest', 'link': [{'form': 'site', 'name': 'c'}, {'form': 'site', 'name': 'd'}]}, {'form': 'nest', 'link': [{'form': 'site', 'name': 'e'}]}, {'form': 'site', 'name': 'f'}, {'form': 'nest', 'link': [{'form': 'site', 'name': 'g'}, {'form': 'nest', 'link': [{'form': 'site', 'name': 'h'}, {'form': 'nest', 'link': [{'form': 'site', 'name': 'i'}, {'form': 'site', 'name': 'j'}]}]}]}]}
var result = mem_tree(d.link)