Jak napsat parser postavit JavaScript AST MemberExpression pro vyjádření.b[c.d][e].f[g[h[já.j]]]?

0

Otázka

Následující podél linií , Jak jasně představují.b[c.d][e].f[g[h[já.j]]] jako objekt strom?, jak by se vám napsat algoritmus pro generování, které JS AST z výrazu a.b[c.d][e].f[g[h[i.j]]]? Snažím se napsat parser generovat nějaký objekt struktury z tohoto vyjádření (v ideálním případě více intuitivní než JS AST MemberExpression jeden, proto, že další otázka). Chtěl bych vidět, jak algoritmus pracuje postavit JavaScript MemberExpression strom.

V současné době mám tento druh algoritmu pro generování nějakého stromu (ale to se zdá být nesprávné v současné době):

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]
}

Požadovaný výsledek je tento (nebo lepší, více intuitivní struktura dat, pokud jste tak nakloněn vytvořit):

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

Důvod, proč jsem bojovat (částečně) je, že jsem se to nelíbí MemberExpression stromovou strukturu, je to zpětně pocit, a ne příliš intuitivní. Takže pokud jste mohl postavit jednodušší, přímočařejší struktura dat, která by bylo ideální (to byla jiná otázka), ale pokud ne, pak jen algoritmus pro konstrukci to by se mi děje.

Osobně bych se spíše snažit vytvořit tuto strukturu, protože mi připadá více intuitivní:

{
  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'
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Ale buď jeden pracuje pro mě (nebo obojí).

Pokud půjdeme s druhým, můj další problém bude, jak to převést datové struktury do MemberExpression strom/struktura dat :) Ale budu se snažit a dělat, že jsem první. Takže je asi lepší postavit MemberExpression v této otázce, pak mohu pracovat.

1

Nejlepší odpověď

1
  1. Samostatný řetězec do skupiny objekt a vlastnosti na první úrovni, jako

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

    1. Vezměte poslední položky jako nemovitosti.
    2. Zkontrolujte, zda majetek začít s držákem, pak nastavte computed k true a pásy majetku z okolních závorkách.
    3. Vrátí objekt s
      • type: "MemberExpression" ,
      • object s objektem (2.),
      • property s výsledkem volání hlavní funkce 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

V jiných jazycích

Tato stránka je v jiných jazycích

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