A.b[c.d][e] ifadesi için JavaScript AST MemberExpression oluşturmak üzere bir ayrıştırıcı nasıl yazılır.f [g [h [i. j]]]?

0

Soru

A.b[c.d][e] ' yi açıkça nasıl temsil edeceğimizin çizgilerini takip etmek.nesne ağacı olarak f [g [h [i. j]]]?, ifadeden bu JS ast'yi oluşturmak için nasıl bir algoritma yazarsınız a.b[c.d][e].f[g[h[i.j]]]? Bu ifadeden bir tür nesne yapısı oluşturmak için bir ayrıştırıcı yazmaya çalışıyorum (ideal olarak JS ast'den daha sezgisel MemberExpression bir, dolayısıyla başka bir soru). JavaScript'i oluşturmak için algoritmanın nasıl çalıştığını görmek istiyorum MemberExpression ağaç.

Şu anda bir çeşit ağaç oluşturmak için bu tür bir algoritmam var (ancak şu anda yanlış görünüyor):

const patterns = [
  [/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*/, 'name'],
  [/^\[/, 'open'],
  [/^\]/, 'close'],
  [/^\./, 'stem']
]

console.log(parsePath('a.b[c.d][e].f[g[h[i.j]]]'))

function parsePath(str) {
  let node
  let nest = []
  let result = nest
  let stack = [nest]
  while (str.length) {
    nest = stack[stack.length - 1]
    p:
    for (let pattern of patterns) {
      let match = str.match(pattern[0])
      if (match) {
        if (pattern[1] === 'name') {
          node = {
            form: `term`,
            name: match[0],
            link: []
          }
          nest.push(node)
        } else if (pattern[1] === 'stem') {
          stack.push(node.link)
        } else if (pattern[1] === 'open') {
          node = {
            form: 'read',
            link: []
          }
          nest.push(node)
          stack.push(node.link)
        } else if (pattern[1] === 'close') {
          stack.pop()
        }

        str = str.substr(match[0].length)
        break p
      }
    }
  }
  return result[0]
}

İstenen sonuç şudur (ya da bir tane oluşturmaya eğilimliyseniz daha iyi, daha sezgisel bir veri yapısı):

{
  "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
}

Mücadele etmemin nedeni (kısmen) bundan hoşlanmıyorum MemberExpression ağaç yapısı, geriye dönük bir his ve çok sezgisel değil. Öyleyse, ideal olacak daha basit ve daha basit bir veri yapısı inşa edebilseydiniz (bu başka bir soruydu), ama eğer değilse, bunu inşa etmek için sadece bir algoritma beni harekete geçirirdi.

Şahsen, daha sezgisel bulduğum için bu yapıyı oluşturmaya çalışmayı tercih ederim:

{
  type: 'site',
  site: [
    {
      type: 'term',
      term: 'a'
    },
    {
      type: 'term',
      term: 'b'
    },
    {
      type: 'sink',
      sink: [
        {
          type: 'term',
          term: 'c'
        },
        {
          type: 'term',
          term: 'd'
        }
      ]
    },
    {
      type: 'sink',
      sink: [
        {
          type: 'term',
          term: 'e'
        }
      ]
    },
    {
      type: 'term',
      term: 'f'
    },
    {
      type: 'sink',
      sink: [
        {
          type: 'term',
          term: 'g'
        },
        {
          type: 'sink',
          sink: [
            {
              type: 'term',
              term: 'h'
            },
            {
              type: 'sink',
              sink: [
                {
                  type: 'term',
                  term: 'i'
                },
                {
                  type: 'term',
                  term: 'j'
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Ama ya biri benim için çalışıyor (ya da her ikisi).

İkincisi ile gidersek, bir sonraki sorunum bu veri yapısını nasıl dönüştüreceğimizdir. MemberExpression ağaç / veri yapısı:) Ama önce bunu kendim yapmaya çalışacağım. Bu nedenle, bu soruda MemberExpression oluşturmak muhtemelen daha iyidir, o zaman bunu halledebilirim.

1

En iyi cevabı

1
  1. Dizeyi, aşağıdaki gibi birinci düzey nesne ve özellik gruplarına ayırın

    [
        "a",
        "b",
        "[c.d]",
        "[e]",
        "f",
        "[g[h[i.j]]]"
    ]
    
  2. Nesneyi al

    1. Son öğeyi özellik olarak alın.
    2. Özelliğin parantez ile başlayıp başlamadığını kontrol edin ve ardından ayarlayın computed -e doğru true ve özelliği çevreleyen parantezlerden çıkarın.
    3. Bir nesneyi şununla döndürün:
      • type: "MemberExpression" ,
      • object nesne ile (2.),
      • property ana işlevi çağırmanın sonucu ile getAST (1.),
      • computed.

function getAST(string) {

    function getObject(parts) {
        if (parts.length === 1) return { type: "Identifier", name: parts[0] };

        let property = parts.pop(),
            computed = false;

        if (property.startsWith('[')) {
            computed = true;
            property = property.slice(1, -1);
        }

        return {
            type: "MemberExpression",
            object: getObject(parts),
            property: getAST(property),
            computed
        };
    }

    let i = 0,
        dot,
        bracket,
        parts = [];

    while (i < string.length) {
        dot = string.indexOf('.', i);
        bracket = string.indexOf('[', i);

        if (dot !== -1 && (bracket === -1 || dot < bracket)) {
            const temp = string.slice(i, dot);
            if (temp) parts.push(temp);
            i = dot + 1;
            continue;
        }

        if (bracket !== -1 && (dot === -1 || bracket < dot)) {
            const temp = string.slice(i, bracket);
            if (temp) parts.push(temp);
            i = bracket;

            let open = 1,
                j = i;

            while (++j < string.length) {
                if (string[j] === '[') open++;
                if (string[j] === ']') open--;
                if (!open) break;
            }

            j++;
            parts.push(string.slice(i, j));

            i = j;
            continue;
        }
        parts.push(string.slice(i));
        break;
    }

    return getObject(parts);
}

console.log(getAST('a.b[c.d][e].f[g[h[i.j]]]'));
.as-console-wrapper { max-height: 100% !important; top: 0; }

2021-11-24 07:30:42

Diğer dillerde

Bu sayfa diğer dillerde

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