วิธีที่จะแปลงนี้ต้นไม้ของโครงสร้างให้เป็น JS MemberExpression ต้นไม้ของโครงสร้าง?

0

คำถาม

ฉันต้องคิดหาทางที่จะเป็นตัวแทนของการแสดง 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"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

ตอนนี้เหมือนกันข้อความแสดงออยังถูกแทนที่ด้วยนี่ JS AST ต้นไม้ของโครงสร้างที่ MemberExpression:

{
  "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 terminology. ดังนั้นครังเหมือน 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"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

ไม่รู้ว่าจะ simplify ปัญหาลงไปในทางที่จะแก้ปัญหามันเลย

ฉันไม่รู้ว่า นี้ เป็นของช่วย(acornjs ตัวกระจายคำสำหรับ MemberExpression).

3

คำตอบที่ดีที่สุด

1

นี่ควรจะทำมัน:

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));
  }
}

คุณสามารถแน่นอน simplify ที่ reducer จะแค่

props.reduce((lhs, rhs) => ({
  "type": "MemberExpression",
  "object": lhs,
  "property": transform(rhs),
  "computed": rhs.form == "nest",
}), transform(base));
2021-11-23 13:35:06

ไม่มีทาง! คุณประยุกต์@item text character set งนั่นลงให้มันโล่งสำคัญ! อันที่จริงฉันคิดว่าฉันเพิ่งได้รับมันเหมือนกันฉันจะตั้งคำตอบของฉันเช่นกัน D
Lance Pollard

ดังนั้นอะไรคือเทคนิคของคุณได้ยังไงคุณหาทางออกดังนั้น elegantly? ฉันคงต้องบอกว่านี่คือเรื่องยุ่งยากมาก เป็นยังไงฉันเรียนรู้ที่จะเป็นมากกว่าเหมือนสิ่งที่คุณทำ:)
Lance Pollard

@LancePollard ลังคิดพออยู่แล้ว grokking recursion ช่วยได้ มันชัดเจนสำหรับผมว่ามันต้องเป็นผู้บริสุทธิ์ฟังก์ชันไม่ใช่การใช้งานแล้ว(ถึงแม้อันที่จริงฉันไม่ได้เต็มอ่านรหัสของคุณความพยายาม). และมีสองทางของ traversal:หนึ่งเป็นพื้นที่ล่ามโซ่อีกคนในครอบการแสดง. ให้เจ๋งสุดยอดแฟลตต่างหาคือเส้นนั่นคงจะเป็นเรียบง่ายหรือจะเรียกว่าอดีตจนท.ที่ตารางคู่ลำดับที่จะสร้างครอบการ MemberExpression เชื่อมโยงรายชื่อสำหรับการซ้อนในที่ recursion นจะมีความจำเป็นอย่างมาก งั้นมันก็แค่คำถามของว่าลดทิ้งหรือถูกต้องและวิธีพิเศษ-คดีเริ่มต้น
Bergi
1

ก็เหลือน้อยลง recursive ทางออก:

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)
2021-11-24 05:25:09
0

ฉันเรื่องนี้เล็กน้อยหลังจาก@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
}
2021-11-23 13:45:28

ในภาษาอื่นๆ

หน้านี้อยู่ในภาษาอื่นๆ

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................

ดังอยู่ในนี้หมวดหมู่

ดังคำถามอยู่ในนี้หมวดหมู่