Pegjs: Mendukung penguraian bahasa berbasis lekukan

Dibuat pada 16 Okt 2013  ·  34Komentar  ·  Sumber: pegjs/pegjs

Saya menggunakan banyak bahasa berbasis lekukan, seperti CoffeeScript, Jade, dan ingin membuat DSL sendiri.
Saya menemukan beberapa trik mempertahankan lekukan di pegjs dengan mencari, bertanya-tanya apakah ada solusi yang konsisten:
http://stackoverflow.com/questions/11659095/parse-indentation-level-with-peg-js
http://stackoverflow.com/questions/4205442/peg-for-python-style-indentation
https://Gist.github.com/jakubkulhan/3192844
https://groups.google.com/forum/#!searchin/pegjs/indent/pegjs/RkbAB4rPlfU/xxafrY5wGCEJ
Tapi apakah pegjs mendukung fitur ini?

feature

Komentar yang paling membantu

Sangat berbahaya untuk mengandalkan efek samping yang Anda tambahkan di penangan khusus untuk mengurai tata bahasa berbasis lekukan. Jangan lakukan itu. Pegjs harus menambahkan beberapa kemampuan untuk mendorong dan memunculkan status kondisional untuk membuat lekukan penguraian (dan tata bahasa sensitif konteks lainnya) aman.

Inilah yang saya lakukan untuk saat ini, dan saya sarankan Anda melakukan ini: Praproses file input dan masukkan token indent/outdent Anda sendiri. Saya menggunakan {{{{ dan }}}} masing-masing. Kemudian tata bahasa Anda bebas konteks dan dapat diuraikan secara normal. Ini mungkin mengacaukan nilai baris/kolom Anda, tetapi Anda dapat memperbaikinya di postprocessor.

Semua 34 komentar

Sangat berbahaya untuk mengandalkan efek samping yang Anda tambahkan di penangan khusus untuk mengurai tata bahasa berbasis lekukan. Jangan lakukan itu. Pegjs harus menambahkan beberapa kemampuan untuk mendorong dan memunculkan status kondisional untuk membuat lekukan penguraian (dan tata bahasa sensitif konteks lainnya) aman.

Inilah yang saya lakukan untuk saat ini, dan saya sarankan Anda melakukan ini: Praproses file input dan masukkan token indent/outdent Anda sendiri. Saya menggunakan {{{{ dan }}}} masing-masing. Kemudian tata bahasa Anda bebas konteks dan dapat diuraikan secara normal. Ini mungkin mengacaukan nilai baris/kolom Anda, tetapi Anda dapat memperbaikinya di postprocessor.

Jika Anda tidak perlu menargetkan javascript, Pegasus , klon pegjs saya untuk C#, memiliki dukungan untuk status push/popping. Berikut artikel wiki tentang cara melakukan apa yang Anda inginkan: https://github.com/otac0n/Pegasus/wiki/Significant-Whitespace-Parsing

Saya ingin mengusulkan agar pegjs menggunakan sintaks saya sebagai titik awal untuk penguraian berbasis negara.

Kemampuan untuk push dan pop state dengan aman itu bagus. Saya akan menggunakannya jika berbasis Javascript. Tidak layak untuk mengintegrasikan CLR hanya untuk penguraian.

Itulah yang saya pikirkan. Saya pikir, dalam hal ini, saya mungkin harus mencoba mem-back-port peningkatan saya ke pegjs.

Namun, saya tidak serta-merta ingin melakukannya tanpa berbincang dengan @dmajda.

@otac0n Itu bagus. Saya tidak menulis C# . JavaScript jauh lebih baik bagi saya.

Bahasa berbasis lekukan itu penting. Saya ingin melihat menyederhanakan parsing mereka setelah 1.0.0.

Saya pikir masalah ini paling baik diselesaikan dengan mengizinkan keadaan secara umum, seperti yang dilakukan Pegasus dan seperti yang disarankan di #285. Berikut adalah sebuah ide (berikut adalah tata bahasa spasi putih signifikan Pegasus yang diterjemahkan ke pegjs dan dengan ide sintaks saya ditambahkan):

{var indentation = 0}

program
  = s:statements eof { return s }

statements
  = line+

line
  = INDENTATION s:statement { return s }

statement
  = s:simpleStatement eol { return s }
  / "if" _ n:name _? ":" eol INDENT !"bar " s:statements UNDENT {
      return { condition: n, statements: s }
    }
  / "def" _ n:name _? ":" eol INDENT s:statements UNDENT {
      return { name: n, statements: s }
    }

simpleStatement
  = a:name _? "=" _? b:name { return { lValue: a, expression: b } }

name
  = [a-zA-Z] [a-zA-Z0-9]* { return text() }

_ = [ \t]+

eol = _? comment? ("\r\n" / "\n\r" / "\r" / "\n" / eof)

comment = "//" [^\r\n]*

eof = !.

INDENTATION
  = spaces:" "* &{ return spaces.length == indentation }

INDENT
  = #STATE{indentation}{ indentation += 4 }

UNDENT
  = #STATE{indentation}{ indentation -= 4 }

Perhatikan blok #STATE{indentation} dekat bagian bawah (jelas terinspirasi oleh Pegasus). Saya menyebut blok negara bagian itu. Idenya adalah untuk mengizinkan blok status sebelum tindakan. Berikut adalah blok status yang lebih rumit:

#STATE{a, b, arr: {arr.slice()}, obj: {shallowCopy(obj)}, c}

Ini adalah singkatan untuk:

#STATE{a: {a}, b: {b}, arr: {arr.slice()}, obj: {shallowCopy(obj)}, c: {c}}

Dengan kata lain, setelah ekspansi singkatan diterapkan, isi dari blok status adalah daftar identifier ":" "{" code "}" . Menambahkan blok status sebelum tindakan memberi tahu pegjs bahwa tindakan ini akan mengubah pengidentifikasi yang terdaftar, dan jika aturan dilacak mundur, pengidentifikasi tersebut harus disetel ulang ke kode di antara kurung kurawal.

Berikut adalah fungsi yang dikompilasi untuk INDENT dan UNDENT dari tata bahasa di atas, dengan pengaturan ulang variabel indentation ditambahkan:

    function peg$parseINDENT() {
      var s0, s1, t0;

      s0 = peg$currPos;
      t0 = indentation;
      s1 = [];
      if (s1 !== peg$FAILED) {
        peg$reportedPos = s0;
        s1 = peg$c41();
      } else {
        indentation = t0;
      }
      s0 = s1;

      return s0;
    }

    function peg$parseUNDENT() {
      var s0, s1, t0;

      s0 = peg$currPos;
      t0 = indentation;
      s1 = [];
      if (s1 !== peg$FAILED) {
        peg$reportedPos = s0;
        s1 = peg$c42();
      } else {
        indentation = t0;
      }
      s0 = s1;

      return s0;
    }

Dan inilah sedikit bagaimana "blok keadaan rumit" dari atas dapat dikompilasi:

s0 = peg$currPos;
t0 = a;
t1 = b;
t2 = arr.slice();
t3 = shallowCopy(obj);
t4 = c;
// ...
if (s1 !== peg$FAILED) {
  // ...
} else {
  peg$currPos = s0;
  a = t0;
  b = t1;
  arr = t2;
  obj = t3;
  c = t4;
}

Apa pendapat Anda tentang gagasan untuk dapat:

  • Beri tahu pegjs tentang variabel stateful mana yang akan dimodifikasi oleh suatu tindakan.
  • Berikan kode yang diperlukan untuk menyimpan variabel tersebut jika perlu diatur ulang. (Termasuk sintaks singkatan untuk kasus sederhana di mana variabel adalah nilai primitif.)

Dan apa pendapat Anda tentang sintaks?

Sunting: Inilah tata bahasa sintaks yang diusulkan (hanya untuk bersenang-senang):

diff --git a/src/parser.pegjs b/src/parser.pegjs
index 08f6c4f..09e079f 100644
--- a/src/parser.pegjs
+++ b/src/parser.pegjs
@@ -116,12 +116,31 @@ ChoiceExpression
     }

 ActionExpression
-  = expression:SequenceExpression code:(__ CodeBlock)? {
+  = expression:SequenceExpression code:((__ StateBlock)? __ CodeBlock)? {
       return code !== null
-        ? { type: "action", expression: expression, code: code[1] }
+        ? {
+            type:       "action",
+            expression: expression,
+            code:       code[2],
+            stateVars:  (code[0] !== null ? code[0][1] : [])
+          }
         : expression;
     }

+StateBlock "state block"
+  = "#STATE{" __ first:StateBlockItem rest:(__ "," __ StateBlockItem)* __ "}" {
+      return buildList(first, rest, 3);
+    }
+
+StateBlockItem
+  = varName:Identifier expression:(__ ":" __ CodeBlock)? {
+      return {
+        type:       "stateVar",
+        name:       varName,
+        expression: expression !== null ? expression[3] : varName
+      };
+    }
+
 SequenceExpression
   = first:LabeledExpression rest:(__ LabeledExpression)* {
       return rest.length > 0

Halo kawan-kawan,
Hanya untuk memperjelas, apakah saya benar bahwa lebih baik tidak menggunakan PEG.js (dengan solusi dari atas masalah ini) dengan bahasa berbasis lekukan sampai masalah ini ditutup?
Terima kasih.

@hoho Saya tidak mengerti maksud Anda .. Tapi saya kemudian menemukan solusi lain untuk mengurai lekukan dengan kombinator parser seperti solusi dan berhasil. Dan saya pikir lekukan asli saya untuk mengurai lekukan dengan PEG.js hilang.

Maksud saya ada solusi untuk mengurai lekukan, tetapi komentar mengatakan bahwa solusi ini akan gagal dalam beberapa kasus tertentu.

Biarkan saya mengklarifikasi situasinya: Mengurai bahasa berbasis lekukan di PEG.js dimungkinkan. Ada berbagai solusi yang disebutkan di atas dan saya baru saja membuat yang lain ketika saya mencoba untuk mendapatkan "rasa" untuk ini (ini adalah tata bahasa bahasa sederhana dengan dua pernyataan, salah satunya dapat berisi sub-pernyataan berindentasi - mirip dengan misalnya if dengan Python).

Satu hal yang umum untuk semua solusi adalah mereka perlu melacak status indentasi secara manual (karena PEG.js tidak dapat melakukannya). Ini berarti ada dua batasan:

  1. Anda tidak dapat mengkompilasi tata bahasa dengan caching dengan aman (karena parser dapat menggunakan hasil yang di-cache alih-alih mengeksekusi kode yang memanipulasi keadaan).
  2. Anda tidak dapat melakukan backtrack di seluruh level indentasi (karena saat ini tidak ada cara untuk membuka gulungan status saat melakukan backtracking). Dengan kata lain, Anda tidak dapat mengurai bahasa di mana ada dua konstruksi valid yang dapat disamarkan hanya setelah baris baru dan tingkat lekukan berubah.

Batasan 1 dapat menyebabkan masalah kinerja dalam beberapa kasus, tetapi saya tidak berpikir ada banyak bahasa yang batasan 2 akan menjadi masalah.

Saya setuju dengan keadaan ini hingga 1.0.0 dan saya berencana untuk kembali ke topik ini beberapa saat setelahnya. Tingkat peningkatan pertama dapat menghilangkan batasan 2 menggunakan pelacakan status yang lebih eksplisit (seperti yang disarankan di atas) atau dengan menyediakan kait lacak balik (sehingga seseorang dapat membuka gulungan status dengan benar). Tingkat kedua dapat menghilangkan kebutuhan untuk melacak status indentasi secara manual dengan menyediakan beberapa cara deklaratif untuk melakukannya. Ini bisa membantu dengan batasan 1.

H, saya menulis tambalan (kecil, retas) untuk PEG.js yang mendukung pelacakan balik yang tepat, seperti yang saya jelaskan di sini: https://github.com/pegjs/pegjs/issues/45

maaf atas benturannya

Saya baru saja ingin membuat parser CSON dan YAML untuk bahasa yang saya rancang, dan sambil mencari cara untuk membuat parser berbasis indentasi dengan PEG.js, saya menemukan metode sederhana yang:

1) tidak bergantung pada status push/pop
2) menegaskan level indentasi melalui kode dalam tindakan

Terpikir oleh saya bahwa salah satu dari 2 solusi di atas sebenarnya menambah masalah kinerja ke parser yang dihasilkan. Selain itu menurut saya:

1) mengandalkan status tidak hanya menambahkan sintaks PEG.js yang jelek tetapi juga dapat memengaruhi jenis parser apa yang dapat dihasilkan karena mereka perlu mendukung penyerahan status berbasis tindakan.
2) terkadang menambahkan beberapa kode dalam tindakan menghasilkan aturan yang bergantung pada bahasa, dan untuk beberapa pengembang itu berarti mereka tidak dapat menggunakan plugin untuk menghasilkan parser untuk bahasa lain seperti C atau PHP tanpa menggunakan lebih banyak plugin untuk menangani tindakan pada aturan, yang hanya berarti sistem build yang lebih besar hanya untuk mendukung 1 atau 2 perubahan.

Setelah beberapa saat saya mulai membuat varian saya sendiri dari parser PEG.js dan berpikir: mengapa tidak menggunakan operator awalan increment (“++”) dan decrement (“--”) (__++ ekspresi__ dan __-- ekspresi__ ) untuk menangani hasil ekspresi kecocokan (__ekspresi *__ atau __ekspresi +__).

Berikut ini adalah contoh tata bahasa berdasarkan @dmajda 's Simple bahasa berbasis intentation , ditulis ulang untuk menggunakan baru __ ++ expression__ dan __-- expression__ bukan __ & {predikat} __:

Start
  = Statements

Statements
  = Statement*

Statement
  = Indent* statement:(S / I) { return statement; }

S
  = "S" EOS {
      return "S";
    }

I
  = "I" EOL ++Indent statements:Statements --Indent { return statements; }
  / "I" EOS { return []; }

Indent "indent"
  = "\t"
 / !__ "  "

__ "white space"
 = " \t"
 / " "

EOS
  = EOL
  / EOF

EOL
  = "\n"

EOF
  = !.

Jauh lebih enak dipandang, bukan? Lebih mudah dipahami juga, baik untuk manusia maupun perangkat lunak.

Bagaimana cara kerjanya? sederhana:

1) Indent* memberi tahu parser bahwa kita menginginkan 0 atau lebih dari apa yang dikembalikan Indent
2) ++Indent memberitahu parser untuk meningkatkan jumlah minimum kecocokan yang diperlukan untuk Indent
3) Sekarang setiap kali parser akan mengembalikan kecocokan untuk Indent , parser pertama-tama mengharapkannya menjadi __1 lebih__ cocok dari sebelumnya, jika tidak _peg$SyntaxError_ akan dilempar.
4) --Indent memberitahu parser untuk mengurangi jumlah minimum kecocokan yang diperlukan untuk Indent
5) Sekarang setiap kali parser mencari Indent dan mengembalikan kecocokan yang diharapkan __1 less__ cocok dengan sebelumnya, jika tidak _peg$SyntaxError_ akan dilempar.

Solusi ini adalah cara terbaik untuk menambahkan dukungan untuk 'Significant Whitespace Parsing' tanpa menambahkan sintaks yang jelek ke tata bahasa PEG.js atau memblokir generator pihak ke-3.

Inilah aturan yang diubah untuk menambahkan dukungan untuk parsing ini di _src/parser.pegjs_:

{
  const OPS_TO_PREFIXED_TYPES = {
    "$": "text",
    "&": "simple_and",
    "!": "simple_not",
    "++": "increment_match",
    "--": "decrement_match"
  };
}

PrefixedOperator
  = "$"
  / "&"
  / "!"
  / "++"
  / "--"

SuffixedOperator
  = "?"
  / "*"
  / "+" !"+"

Apakah saya benar untuk berasumsi bahwa untuk mendukungnya sisi kompiler/generator kita harus:

1) tambahkan pass kompiler yang memastikan __++ expression__ atau __-- expression__ hanya digunakan pada __expression *__ atau __expression +__, di mana __expression__ harus bertipe: choice, sequence, atau rule_ref
2) tambahkan pemeriksaan berbasis cache di parser yang dihasilkan untuk __expression *__ atau __expression +__ yang menegaskan kecocokan minimum yang diperlukan terpenuhi sebelum mengembalikan kecocokan
3) secara opsional tambahkan metode pembantu untuk pengurai yang dihasilkan untuk diterapkan yang mengembalikan jumlah kecocokan yang diperlukan untuk aturan yang diberikan, mis. nMatches( name: String ): Number

@futagoza , ini bersih dan pintar. Saya suka itu. Saya sedang mengerjakan parser yang menangani status, tetapi satu-satunya status yang benar-benar kita butuhkan adalah level indentasi. Saya dapat menggunakan ide ini dan memberi Anda kredit untuk itu. Melacak level indentasi masih secara efektif membutuhkan status push/popping sehingga mungkin masih mencegah beberapa pengoptimalan tetapi semantiknya sangat bagus.

Jika Anda menambahkan operator ke tata bahasa, saya sarankan untuk menambahkan operator awalan @ juga. Tujuannya adalah untuk mengekstrak hasil aturan tunggal dari urutan. Dengan menggunakan itu, tata bahasa sampel menjadi lebih bersih. Tidak ada lagi tindakan sepele { return x }.

Start
  = Statements

Statements
  = Statement*

Statement
  = Indent* @(S / I)

S
  = "S" EOS {
      return "S";
    }

I
  = "I" EOL ++Indent <strong i="8">@Statements</strong> --Indent
  / "I" EOS { return []; }

Indent "indent"
  = "\t"
 / !__ "  "

__ "white space"
 = " \t"
 / " "

EOS
  = EOL
  / EOF

EOL
  = "\n"

EOF
  = !.

@kodyjking apa pendapat Anda tentang ini?

@futagoza Apakah Anda memiliki garpu/cabang dengan tambalan lekukan diaktifkan dan tata bahasa sampel kecil?

Saya sedang mengerjakan lekukan garpu/cabang ini

@krinye "Saya sarankan menambahkan operator awalan @ juga. Tujuannya adalah untuk mengekstrak satu hasil aturan dari urutan"

Bisakah salah satu dari kalian melihat dan membuat dan membuat komentar atau PR dengan perbaikannya. Terima kasih :)

Readme: perubahan garpu

Saya men-debug... increment_match-not-found

Ah, tidak memperhatikan peringatannya:

Apakah saya benar untuk berasumsi bahwa untuk mendukungnya sisi kompiler/generator kita harus:

  • tambahkan pass kompiler yang memastikan ekspresi ++ atau -- ekspresi hanya digunakan pada ekspresi * atau ekspresi +, di mana ekspresi harus bertipe: choice, sequence, atau rule_ref
  • tambahkan pemeriksaan berbasis cache di parser yang dihasilkan untuk ekspresi * atau ekspresi + yang menegaskan kecocokan minimum yang diperlukan terpenuhi sebelum mengembalikan kecocokan
  • opsional tambahkan metode pembantu untuk parser yang dihasilkan untuk diterapkan yang mengembalikan jumlah kecocokan yang diperlukan untuk aturan tertentu, mis. nCocok (nama: String): Nomor

Hanya untuk iseng, saya mencoba menambahkan ini di visitor.js

      increment_match: visitExpression,
      decrement_match: visitExpression,

Sekarang saya mendapatkan Invalid opcode: undefined.

@kristianmandrup mengenai operator @ untuk mengekstrak nilai tunggal dari urutan, saya memiliki garpu hanya dengan fitur yang ditambahkan ke PegJS yang tersedia di sini:

https://github.com/krisnye/pegjs

Ini adalah tambahan yang cukup sederhana.

@krisnye +1 untuk implementasi berbasis tata bahasa, bagus dan sederhana. Jika Anda tidak keberatan, saya akan menambahkan ini ke varian PEG.js saya

@kristianmandrup melihat Anda berkomitmen untuk saran saya

@futagoza Tolong lakukan.

Saya sedang mendiskusikan logika indentasi dengan rekan kerja dan kami menyarankan elemen sintaksis berikut:

// menambah variabel status bernama
pengenal++
// mengurangi variabel status bernama
pengenal--

// ulangi jumlah konstan atau variabel status (dengan default nol jika variabel belum bertambah)
aturan{bilangan bulat | pengenal}
// ulangi min/max menggunakan konstanta atau variabel status
aturan{bilangan bulat | pengenal, bilangan bulat | pengenal}

Parser yang sedang kami kerjakan dapat menangani keadaan arbitrer, tetapi jujur, hal di atas adalah semua yang diperlukan untuk penguraian lekukan.

Terima kasih banyak! Jika ini sangat mudah dilakukan, mengapa tidak membuat garpu "khusus" di mana hal-hal yang Anda sebutkan "berfungsi" ;)
Bersulang!

@krisnye

  1. Menggunakan __identifier++__ dapat dengan mudah menyebabkan kesalahan berantakan jika pengembang bermaksud __identifier+__, itu sebabnya saya memilih untuk menggunakan __++identifier__ dan, untuk konsistensi, __--identifier__
  2. Seperti disebutkan dalam masalah berbeda tentang rentang, rule{ STATE_REPEAT / RANGE } dapat dikacaukan dengan rule{ ACTION } , terutama jika Anda membuat penyorot sintaks untuk PEG.js, jadi pendekatan ini telah ditolak oleh @dmajda

@kristianmandrup _(OFF TOPIC)_ Saya pandai merancang fitur, dan terkadang membuat implementasi, tetapi buruk dalam menguji dan membandingkannya, jadi biasanya saya membuat varian yang berfungsi (tanpa tes atau tolok ukur) di direktori non-repo pribadi di pc saya , lalu lupakan mereka . Untuk varian PEG.js saya saat ini (bernama ePEG.js , penulisan ulang diperpanjang dari PEG.js) saya menambahkan hal-hal yang disebutkan di sini, serta fitur lainnya (rentang, impor, template, dll), jadi saya menambahkan tes dan tolok ukur, tetapi saat ini saya juga sedang mengerjakan proyek C++ yang memakan waktu saya, jadi tidak ada ETA untuk itu.

@futagoza Terima kasih sobat :) Melihat ekstensi fitur, tetapi tidak menyebutkan dukungan indentasi. Apakah itu termasuk tetapi tidak berdokumen atau sedang berjalan?

Orang lain dari daftar ini mengarahkan saya ke solusi pembuat/generator parser lain yang mungkin saya lihat juga. Selalu kabari saya! Bersulang!

@kristianmandrup Sejauh yang saya tahu itu tidak termasuk, tetapi @dmajda mengatakan 3 tahun yang lalu bahwa dia akan memeriksanya setelah merilis PEG.js v1, tetapi dari apa yang saya tahu itu tidak akan terjadi selama 2 tahun, kecuali dia berencana untuk rilis lebih banyak versi minor PEG.js v0 (_0.12_, _0.13_, _etc_)

Maksud saya jika Anda sudah memasukkan dukungan indentasi di ePEG atau di peta jalan?

@kristianmandrup oh , ada di peta jalan. Saya belum memperbarui repo ePEG.js untuk sementara waktu, dan baru-baru ini memutuskan untuk mengubahnya menjadi penulisan ulang lengkap PEG.js alih-alih sebuah plugin.

@futagoza menyetujui ++/-- sebagai pra operasi, dan saya lupa tentang sintaks tindakan, kami mengubahnya menjadi [min, maks]

Jadi

++identifier
--identifier
rule[integer | identifier]
rule[integer | identifier, integer | identifier]

@krisnye [ ... ] digunakan untuk kelas karakter, lihat https://github.com/pegjs/pegjs#characters

Apa yang saya lakukan di ePEG.js adalah menambahkan rentang (juga di peta jalan) untuk mencapai apa yang saya pikir Anda gambarkan:

space = [ \t]*
rule = range|expression
  • __expression__ dapat berupa salah satu dari ini: __++space__, __--space__ atau __space__
  • __range__ bisa __ min.. __, __ min..max __, __ ..max __ atau __ exact __
  • __min__, __max__ atau __exact__ hanya dapat berupa __unsigned integer__
  • menggunakan __range__ dengan __expression__ (misalnya 2|expression) dapat memungkinkan kita untuk mengatur jumlah total __expression__ yang diperlukan agar __rule__ berhasil diurai.
  • menggunakan rentang __exact__ dengan __++expression__ atau __--expression__ (misalnya 3|++expression) dapat memungkinkan kita untuk mengatur jumlah __integer__ untuk __++__ atau __--__, yang secara default adalah __1__
  • menggunakan rentang __min__ atau __max__ dengan __++expression__ atau __--expression__ memunculkan kesalahan sintaks.

Saya tidak menggunakan variabel status karena itu hanya akan membingungkan dengan pengidentifikasi aturan.

Menggunakan kombinasi __range__, __++__, __--__ atau __ @__ Saya berharap dapat membuat file tata bahasa PEG yang tidak terlalu bergantung pada aturan __action__ untuk hasilnya, yang seharusnya meningkatkan waktu pengembangan spasi putih (mis. -berbasis, seni ASCII, dll) sebagai perancang dan/atau pelaksana bahasa tidak perlu khawatir mencoba mengonfirmasi apakah jumlah spasi yang benar telah diuraikan.
Ini juga harus memungkinkan pengembang plugin untuk membuat generator parser yang dapat mengoptimalkan dengan _tanpa rasa takut_ tentang bahasa __action__ kami (secara default JavaScript, tetapi dengan plugin dapat mengubahnya ke CoffeeScript, PHP, dll).

Jadi sepertinya hari ini masih tidak mungkin untuk mengurai Python dengan PEG.js di luar kotak, benar?

Jika tidak, apakah ini sesuatu yang akan segera hadir? Apakah ada serangkaian tugas yang diperlukan untuk membuat pekerjaan ini yang dapat disumbangkan orang?

Saya memiliki proyek di mana saya ingin mendapatkan AST Python di JS, memodifikasinya dan kemudian mengubahnya kembali ke kode sumber dengan format yang sama, jadi saya akan tertarik untuk mewujudkannya jika ada yang jelas peta jalan.

@mindjuice Belum, direncanakan untuk posting 1.0.

Jika Anda tidak bisa menunggu, keponakan saya dan saya membuat parser yang ditulis dalam TypeScript yang menggunakan sintaks yang sama dan menangani lekukan. Ini belum didokumentasikan, tetapi cukup sederhana. Masih ada pekerjaan yang sedang berlangsung karena kami menggunakannya sebagai pengurai untuk desain bahasa baru.

https://github.com/krisnye/pegs

Anda juga dapat mencoba generator parser lain dengan dukungan seperti chevrotain

Contoh lekukan python

Saya percaya sangat mungkin untuk mengurai lekukan seperti python dengan PEGjs.
Contoh di bawah ini hanya menggunakan lekukan berbasis empat spasi, tetapi dapat diperluas untuk mencakup tab dengan spasi arbitrer dan karakter spasi putih lainnya.
Faktanya, bahasa yang saya kerjakan memiliki cerita lekukan yang sedikit lebih rumit daripada yang dimiliki Python dan tata bahasa ini berfungsi dengan baik untuk itu.

{
    let prevIndentCount = 0;
    function print(...s) { console.log(...s); }
}

Indent 'indent'
    = i:("    "+) { 
        let currentIndentCount = i.toString().replace(/,/g, "").length;
        if (currentIndentCount === prevIndentCount + 4) { 
            // DEBUG //
            print("=== Indent ===");
            print("    current:"+currentIndentCount); 
            print("    previous:"+prevIndentCount);
            print("    lineNumber:"+location().start.line); 
            // DEBUG //
            prevIndentCount += 4;
            return "[indent]";
        }
        error("error: expected a 4-space indentation here!")
    } // 4 spaces 

Samedent 'samedent'
    = s:("    "+ / "") &{
        let currentIndentCount = s.toString().replace(/,/g, "").length;
        if (currentIndentCount === prevIndentCount) {
            print("=== Samedent ===");
            return true;
        }
        return false;
    }

Dedent 'dedent'
    = d:("    "+ / "") {
        let currentIndentCount = d.toString().replace(/,/g, "").length;
        if (currentIndentCount < prevIndentCount) {
            // DEBUG //
            print("=== Dedent ===");
            print("    current:"+currentIndentCount); 
            print("    previous:"+prevIndentCount);
            print("    lineNumber:"+location().start.line); 
            // DEBUG //
            prevIndentCount -= 4;
            return "[dedent]";
        }
        error("error: expected a 4-space dedentation here!");
    }

Dengan tata bahasa di atas, Anda dapat membuat aturan blok indentasi seperti ini:

FunctionDeclaration 
    = 'function' _ Identifier _ FunctionParameterSection _ ":" _ FunctionBody

FunctionBody
    = Newline Indent FunctionSourceCode (Newline Samedent FunctionSourceCode)* Dedent 
Apakah halaman ini membantu?
0 / 5 - 0 peringkat