Pegjs: Tambahkan kemampuan untuk melacak posisi simpul

Dibuat pada 13 Agu 2011  ·  15Komentar  ·  Sumber: pegjs/pegjs

Parser yang dihasilkan PEG.js saat ini tidak melacak posisi (baris dan kolom). Saya ingin menambahkan fitur ini karena akan sangat berguna.

Salah satu caranya adalah dengan menambahkan properti line dan column ke setiap objek yang dikembalikan sebagai hasil kecocokan:

start = "a" b:"b" { return [b.line, b.column]; } // Returns [1, 2] on the input "ab".

Cara lain adalah dengan membuat variabel khusus line dan column tersedia di dalam tindakan/predikat, mengacu pada posisi awal aturan saat ini:

start = "a" "b" { return [line, column]; } // Returns [1, 1] on the input "ab".

Cara pertama memang lebih fleksibel, tapi sebenarnya fleksibilitas ini mungkin tidak diperlukan. Saya belum yakin cara mana yang akan saya terapkan.

Kedua cara akan merusak kinerja. Untuk mencegah hal ini dalam kasus di mana pelacakan posisi tidak diperlukan, pelacakan harus diaktifkan hanya jika opsi trackPosition dengan nilai kebenaran diteruskan ke PEG.buildParser saat membuat parser.

feature

Komentar yang paling membantu

@tomitrescak fitur ini rupanya telah berubah beberapa kali di masa lalu. Lihat changelog untuk informasi lebih lanjut. tl; dr apakah Anda perlu menggunakan fungsi location() dalam tata bahasa Anda

Semua 15 komentar

Pilihan mana pun akan bagus. Untuk kebutuhan saya cukup baris, kolom akan baik-baik saja.

Saya juga mencari perbaikan untuk ini. Saat ini, saya telah meretas sesuatu dengan cepat berdasarkan computeErrorPosition(), tetapi memiliki beberapa kekusutan di dalamnya.

Di permukaan, pendekatan pertama tampaknya lebih intuitif daripada yang kedua.

saya suka pendekatan pertama lebih baik, juga.

Salah satu efisiensi yang mungkin adalah menjadikan name.position sebagai fungsi, sehingga dapat dihitung dengan malas. Ini kemudian dapat mengembalikan larik baris dan kolom 2 item. Sekedar ide bagi mereka yang tidak ingin menghitung posisi untuk setiap item.

Di belakang, tampaknya lebih baik untuk memberikan posisi karakter awal dan akhir, dan kemudian menyediakan fungsi pembantu di perpustakaan yang mengubah posisi menjadi baris/kolom. Karena dalam kasus umum, Anda tidak memerlukan baris/kolom kecuali jika ada kesalahan, dan setelah Anda mencapai kesalahan, Anda biasanya hanya membutuhkannya sekali.

Saat ini saya melakukan ini dengan cara retas dengan menyalahgunakan variabel startPos0 dan pos , yang terasa retas, tetapi berfungsi untuk saat ini.

Sampai ada perbaikan resmi, saya menyertakan fungsi ini (salinan kasar computeErrorPosition ) di bagian atas tata bahasa saya. Setidaknya itu akan memberi saya posisi _current_ (walaupun bukan posisi masing-masing node):

  function computeCurrentPos() {
    /*
     * The first idea was to use |String.split| to break the input up to the
     * error position along newlines and derive the line and column from
     * there. However IE's |split| implementation is so broken that it was
     * enough to prevent it.
     */

    var line = 1;
    var column = 1;
    var seenCR = false;

    for (var i = 0; i < pos; i++) {
      var ch = input.charAt(i);
      if (ch === '\n') {
        if (!seenCR) { line++; }
        column = 1;
        seenCR = false;
      } else if (ch === '\r' | ch === '\u2028' || ch === '\u2029') {
        line++;
        column = 1;
        seenCR = true;
      } else {
        column++;
        seenCR = false;
      }
    }

    return { line: line, column: column, pos: pos };
  }

Masalah ini telah diperbaiki dengan serangkaian komit .

Anda sekarang dapat meneruskan opsi trackLineAndColumn ke fungsi PEG.buildParser :

var parser = PEG.buildParser(myGrammar, { trackLineAndColumn: true});

Menyetel trackLineAndColumn ke true membuat dua variabel baru terlihat di tindakan dan predikat — line dan column . Untuk tindakan, variabel-variabel ini menunjukkan posisi awal dari ekspresi tindakan sementara dalam predikat mereka menunjukkan posisi saat ini. Perilaku yang sedikit berbeda dimotivasi oleh penggunaan yang diharapkan.

Pelacakan garis dan kolom bersifat opsional karena mengganggu kinerja (membuat parser sekitar 3-4× lebih lambat). Saya mungkin dapat mengoptimalkan ini di masa mendatang (saya mencoba membuatnya berfungsi terlebih dahulu).

Pada deskripsi masalah, saya menyebutkan pendekatan yang berbeda untuk masalah ini: menambahkan properti line dan column ke setiap hasil kecocokan. Meskipun solusi ini lebih bersih dan disukai oleh pengguna, saya menyadari bahwa seseorang tidak dapat mengatur properti pada nilai primitif seperti string, angka, atau boolean (yang sering ditampilkan sebagai hasil kecocokan). Mengembalikan contoh objek pembungkus (misalnya String , Number atau Boolean ) akan menjadi solusi yang mungkin, tetapi mungkin akan menyebabkan bug halus di parser yang dibuat oleh pengguna, karena pembungkus ini berperilaku sedikit berbeda dari primitif. Jadi saya memutuskan untuk menerapkan proposal alternatif.

Apakah halaman pengujian online akan diperbarui untuk mendukung fitur ini?

@paulftw Editor online selalu menggunakan versi stabil terbaru dari PEG.js (saat ini 0.6.2). Saya akan memperbaruinya setelah saya merilis PEG.js 0.7.0 (yang akan menyertakan fitur ini). Kecuali sesuatu yang tidak terduga muncul, ini akan terjadi pada paruh kedua April.

Perhatikan bahwa kode sumber situs web tersedia di GitHub , jadi jika Anda tidak sabar, Anda dapat menjalankan dan memodifikasinya sendiri.

Baru menyadari bahwa semua baris dan kolom berbasis 1, sedangkan array JS serta hampir semua bahasa dan pustaka modern menggunakan pengindeksan berbasis 0.

Adakah kesempatan untuk mengembalikan keputusan desain itu?

@paulftw Bisakah Anda memberikan contoh generator parser yang melaporkan baris dan kolom sebagai berbasis 0?

Gagasan di balik keputusan saya adalah bahwa angka-angka ini kemungkinan besar akan ditampilkan kepada pengguna (dalam pesan kesalahan, sebagai posisi simpul, dll.), jadi pengindeksan berbasis 1 lebih masuk akal daripada berbasis 0. Untuk pemrosesan mesin, variabel offset mungkin paling sering digunakan, yang berbasis 0.

Adakah kesempatan untuk mengembalikan keputusan desain itu?

Ya, jika saya menjadi yakin :-)

Saya menggunakan peg.js untuk menyorot teks di editor Ace. Cukup alami nomor baris Ace berbasis 0.
Namun, tampaknya di lokasi Bison berbasis 1.
http://git.savannah.gnu.org/cgit/bison.git/tree/src/location.c#n73

Jika ini memang masalahnya, maka saya harus berhenti berdebat.

Tidak yakin contoh seperti apa yang ingin Anda lihat.
Saat ini saya menggunakan kode berikut untuk menemukan nama simbol:

penahan
= "" { kembalikan Posisi baru(baris - 1, kolom - 1); }

simbol
= start:captor name:IDENT end:captor S* { kembalikan Simbol baru(nama, Rentang baru(mulai, akhir)); }

@paulftw Saya telah membagi masalah ini menjadi issue yang terpisah . Saya akan menunggu pengguna untuk mengadopsi 0.7.0 dan melihat apa yang akan diputuskan oleh penggunaan umum.

Saya tahu ini sudah lama ditutup, tetapi bagaimana saya bisa membuatnya bekerja? Saya cukup noob dalam hal ini. Saya mengkompilasi tata bahasa saya dengan flag "trackLineAndColumn': true", tetapi node masih tidak berisi baris dan kolom. Apa lagi yang dibutuhkan?

Anda menyebutkan yang berikut, saya hanya tidak tahu bagaimana menggunakannya, apakah itu didokumentasikan di suatu tempat?

Menyetel trackLineAndColumn ke true membuat dua variabel baru terlihat dalam tindakan dan predikat — baris dan kolom. Untuk tindakan, variabel-variabel ini menunjukkan posisi awal dari ekspresi tindakan sementara dalam predikat mereka menunjukkan posisi saat ini. Perilaku yang sedikit berbeda dimotivasi oleh penggunaan yang diharapkan.

@tomitrescak fitur ini rupanya telah berubah beberapa kali di masa lalu. Lihat changelog untuk informasi lebih lanjut. tl; dr apakah Anda perlu menggunakan fungsi location() dalam tata bahasa Anda

Apakah halaman ini membantu?
0 / 5 - 0 peringkat