Struktur Lexical Syntax yang Aneh
(justine.lol)- Saat menangani 42 bahasa untuk membuat syntax highlighter baru bagi llamafile, terungkap bahwa bahkan leksing sederhana pun dipenuhi pengecualian per bahasa dan sintaks lama yang tersembunyi rapat
- Implementasinya menggunakan C++ dan GNU gperf untuk mempercepat pencarian keyword, sementara pemrosesan yang berfokus pada string, komentar, dan keyword diselesaikan dengan finite state machine berbasis loop
fordanswitch - Trigraph C, terminator baris
u2028danu2029JavaScript, heredoc di Shell/Perl/Ruby, serta interpolasi string di Kotlin/Scala/TypeScript/Swift berulang kali muncul sebagai kasus yang sulit ditangani hanya dengan leksing - Dari sisi jumlah baris kode, FORTH hanya 125 baris sementara Ruby mencapai 1042 baris; pada Ruby, operator
<<, heredoc, dan backquote saling berbenturan sehingga highlighting tanpa parsing menjadi sangat sulit - Highlighter baru llamafile didemokan di Windows 10 dengan Meta LLaMA 3.2 3B Instruct dan juga bisa berjalan di macOS, Linux, FreeBSD, serta NetBSD, sehingga membedakannya dari ollama yang tidak memiliki syntax highlighting
Alasan membuat highlighter llamafile
- Selama satu bulan mempelajari 42 bahasa pemrograman untuk membuat syntax highlighter baru bagi llamafile
- Target dukungannya adalah Ada, Assembly, BASIC, C, C#, C++, COBOL, CSS, D, FORTH, FORTRAN, Go, Haskell, HTML, Java, JavaScript, Julia, JSON, Kotlin, ld, LISP, Lua, m4, Make, Markdown, MATLAB, Pascal, Perl, PHP, Python, R, Ruby, Rust, Scala, Shell, SQL, Swift, Tcl, TeX, TXT, TypeScript, dan Zig
- Daftar ini mencakup sebagian besar TIOBE Index, tetapi Scratch dikecualikan dari target highlighting karena menggunakan blok, bukan teks
Cara implementasi: gperf dan finite state machine
- Bottleneck terbesar pada syntax highlighter dasar adalah titik ketika perbandingan string berulang bertambah saat menentukan apakah token adalah keyword
- Menggunakan C++ dan GNU gperf untuk menghasilkan perfect hash table
- Contoh input
gperfmendefinisikan konstanta Java sepertitrue,false, dannullsebagai keyword - File C yang dihasilkan
gperfdapat membuat fungsi hash yang hanya mempertimbangkan satu karakter untuk lookup tanpa collision
- Contoh input
- Highlighting C dapat diproses pada kecepatan 35 MB/s berkat gperf meskipun mendefinisikan sekitar 4.000 keyword
- Sebagian besar pemrosesan lainnya cukup ditangani dengan finite state machine
- Highlighter dasar bisa dibuat hanya dengan loop
fordanswitch, tanpaflex,bison, atauragel - Jika berfokus pada string, komentar, dan keyword, umumnya bisa ditangani pada level leksing
- Untuk menyorot elemen seperti nama fungsi C, parsing sungguhan mungkin diperlukan
- Highlighter dasar bisa dibuat hanya dengan loop
- highlight_ada.cpp digunakan sebagai contoh implementasi
Demo llamafile dan lingkungan penggunaan
- Highlighter baru dan antarmuka chatbot meningkatkan kegunaan llamafile, dan syntax highlighting yang tidak ada di ollama menjadi pembeda
- Demo dijalankan di Windows 10 dengan model Meta LLaMA 3.2 3B Instruct
- llamafile tersebut juga dapat berjalan di macOS, Linux, FreeBSD, dan NetBSD
- Seiring meningkatnya kualitas model open-weight seperti gemma 27b it, dorongan untuk menggunakan Claude menjadi berkurang
C: pengecualian leksing yang berbeda dari kesan sebagai bahasa sederhana
- Berbeda dari kesan bahwa C itu sederhana, elemen leksikalnya tergolong sangat unik
- Trigraph dapat mengganti karakter seperti
#,[,\,^,{,|,},~dengan??=,??(,??/,??),??',??<,??!,??>,??-- Sudah dihapus dari standar C23, tetapi karena software legacy, compiler tampaknya akan terus mendukungnya
- Syntax highlighter yang baik juga harus menangani sintaks ini
- Universal character pada C dapat merepresentasikan identifier Unicode di dalam source code ASCII, seperti
int \uFEB2 = 1;- GCC mengeluarkan error jika bukan plane Unicode tertentu yang diizinkan komite standar
- Komentar satu baris C dapat membentang ke beberapa baris jika menggunakan backslash di akhir baris
- Bahasa yang mengizinkan escape backslash di source code seperti Perl, Ruby, dan Shell pun tidak mendukung perilaku ala C ini
- Tcl dan GNU Make dipahami mendukung perilaku ini
- Emacs dan Pygments kadang menanganinya dengan salah, sedangkan Vim tampaknya selalu menangani backslash dengan benar
- C juga memiliki null preprocessor directive
- File
.cdari source code v6 awal sering diawali dengan satu baris# - Ini masih merupakan kode yang valid, dan dapat digunakan agar preprocessor menghapus komentar tertentu meskipun pelestarian komentar diminta dengan
cc -C -E
- File
Sintaks komentar: Haskell dan D
- Di C, komentar multi-baris tidak dapat menyarang komentar multi-baris lain di dalamnya
- Haskell mendukung komentar bersarang dalam bentuk
{- ... {- ... -} ... -} - D mengadopsi komentar
//dan/* ... */dari C apa adanya, serta memperkenalkan sintaks komentar rekursif terpisah dalam bentuk/+ ... +/ - Dokumen lexical grammar D formal dan terperinci sehingga menyediakan informasi yang diperlukan untuk implementasi
- Dokumen lexical syntax D membahas detail seperti hex string dan heredoc string
- D memiliki beragam bentuk string seperti
"...", string backtick,r"...",q"...",x"...", dan lainnya
Tcl dan JavaScript: tanda kutip dan terminator baris yang tak terlihat
- Di Tcl, tanda kutip dapat masuk ke dalam identifier
puts a"bmencetaka"b- Nama variabel juga dapat memuat tanda kutip, tetapi saat direferensikan harus menggunakan notasi
${a"b}, bukan$a"b
- JavaScript memiliki lexical grammar bawaan untuk regular expression
- Seperti
/[/]/g,/di dalam tanda kurung character set tidak perlu di-escape - Cara yang hanya memindai slash penutup dapat keliru pada kode yang sudah diminify
- Seperti
- ECMAScript mendefinisikan
u2028LINE SEPARATOR danu2029PARAGRAPH SEPARATOR sebagai terminator baris- Karakter ini pada dasarnya berperilaku seperti
\n - Karena merupakan karakter Trojan Source, Emacs dikonfigurasi agar menampilkannya masing-masing sebagai
↵dan¶ - Banyak software tidak mengenali karakter ini sehingga kadang merendernya sebagai tanda tanya
- Disebutkan bahwa selain D, tidak diketahui ada bahasa lain yang melakukan pemrosesan seperti ini
- Karakter ini pada dasarnya berperilaku seperti
- Dengan memanfaatkan karakteristik ini, sebuah polyglot C dan JavaScript dapat dibuat di SectorLISP
- lisp.js berjalan di browser dan juga dapat dikompilasi dengan GCC untuk dijalankan secara lokal
- llamafile menyorot kode seperti ini dengan benar, tetapi pemrosesan yang sama tidak ditemukan pada highlighter lain
Kasus sudut heredoc di Shell
- Heredoc Shell menulis string multi-baris dalam bentuk
cat <<EOF ... EOF - Sintaks quoted heredoc
cat <<'END'menonaktifkan substitusi variabel - Jika marker heredoc dibuat sebagai string kosong, heredoc berakhir pada baris kosong berikutnya
- Program contoh mencetak
hellodanworlddalam dua baris
- Program contoh mencetak
- Dalam bahasa yang mendukung heredoc seperti Shell, Ruby, dan Perl, beberapa heredoc dapat diletakkan pada baris yang sama
- Di Shell, seperti Tcl,
#tidak selalu memulai komentar- Dalam
${x#hi-},#digunakan untuk menghapus prefix, dan contohnya mencetakthere
- Dalam
Interpolasi string: bahasa yang membutuhkan stack status
- String Kotlin dapat masuk ke status lain pada
{karena interpolasi string, meskipun dimulai dengan" - TypeScript, Swift, Kotlin, dan Scala sangat mendukung interpolasi string ke arah memasukkan kode sungguhan ke dalam string
- Untuk menyorot Kotlin, Scala, dan TypeScript, perlu menghitung kurung kurawal dan mempertahankan stack status parser
- TypeScript relatif sederhana sehingga cukup menambahkan beberapa status pada finite state machine
- Kotlin dan Scala mendukung interpolasi baik pada sintaks double quote maupun triple quote, sehingga untuk leksing string saja diperlukan sekitar 13 status independen
- Swift mendukung sintaks interpolasi
"\(var)"dan triple quote, tetapi implementasinya membutuhkan 10 status
Swift, C#, FORTH: perbedaan cara membungkus string
- Swift mendukung sintaks yang membungkus string
"...","""...""", dan/regex/dengan jumlah#arbitrer- Jumlah
#di kedua sisi harus cocok - Cara ini menyelesaikan masalah memasukkan tanda kutip atau batas regular expression ke dalam string
- Jumlah
- C# mirip dengan string multi-baris triple quote Python, tetapi dapat menggunakan jumlah tanda kutip yang lebih banyak pada awal dan akhir dengan jumlah yang sama
- Jumlah tanda kutip di sisi kiri menjadi syarat penutup di sisi kanan
- Dengan mengizinkan jumlah tanda kutip arbitrer, aturan validitas berkurang dibandingkan triple quote klasik Python sehingga dianggap lebih mudah didekode dengan finite state machine
- FORTH mentokenisasi semuanya berdasarkan batas spasi
- Sintaks awal string
c"juga merupakan satu token c" hello world"memiliki arti yang sama dengan"hello world"di bahasa lain
- Sintaks awal string
FORTRAN dan COBOL: aturan kolom tetap
- llamafile disajikan sebagai use case yang dapat membantu pemeliharaan sistem perbankan bahkan setelah programmer FORTRAN dan COBOL pensiun
- Disebutkan bahwa di lingkungan air-gapped, kita dapat meminta kode COBOL dan FORTRAN kepada AI yang terkendali seperti Gemma 27b
- Aturan kolom tetap FORTRAN adalah sebagai berikut
- Jika
*,c, atauCdiletakkan di kolom 1, baris tersebut menjadi komentar - Jika karakter non-spasi diletakkan di kolom 6, baris yang melebihi 80 karakter dapat dilanjutkan
- Jika angka diletakkan di kolom 1–5, itu menjadi label
- Jika
- Aturan COBOL adalah sebagai berikut
- Jika
*diletakkan di kolom 7, itu menjadi komentar - Jika
-diletakkan di kolom 7, baris yang melebihi 80 karakter dapat dilanjutkan - Kolom 1–6 berisi nomor baris
- Jika
Zig dan Lua: solusi berbeda untuk string multi-baris
- Zig memiliki sintaks string multi-baris yang dimulai dengan dua backslash
- Sintaks ini menghilangkan kebutuhan memanggil
textwrap.dedent()pada string triple quote Python - Kekurangannya, semicolon dianggap kurang enak dilihat
- Diusulkan sebagai sintaks string yang layak dipertimbangkan oleh bahasa yang tidak membutuhkan semicolon seperti Go, Scala, dan Python
- Sintaks ini menghilangkan kebutuhan memanggil
- String multi-baris Lua berbasis
[[...]], dan dapat memasukkan jumlah=arbitrer di antara tanda kurung siku- Jumlah
=pada awal dan akhir dicocokkan seperti[==[ ... ]==] - Cara yang sama dapat digunakan untuk komentar
- Bentuk
--[[ ... ]]dan--[==[ ... ]==]sama-sama memungkinkan
- Jumlah
Assembly: gabungan dialek dan preprocessor
- Assembly adalah salah satu bahasa yang sulit di-highlight karena terpecah menjadi banyak dialek
- llamafile bertujuan menangani beberapa sintaks seperti AT&T dan nasm secara masuk akal
- Jika keyword diperlakukan sebagai identifier pertama pada baris dan bukan item yang muncul setelah colon, sebagian besar kode assembly dapat terlihat cukup baik
- Sintaks komentar juga tidak sederhana
- Komentar UNIX awalnya hanya membutuhkan satu
/ - GNU as masih mendukung komentar ini hanya di posisi awal baris
- Clang disebut tidak mendukung fixed comment sehingga sulit digunakan secara praktis di kode open-source
- Komentar UNIX awalnya hanya membutuhkan satu
- Assembler UNIX awalnya tidak menggunakan tanda kutip penutup pada literal karakter
'xmerepresentasikan nilai karakterx, yaitu0x78- GNU as terus mendukungnya, tetapi LLVM tidak
- Karena sintaks ini ada di kode lama, highlighter yang baik harus mendukungnya
- GNU assembler mengizinkan identifier yang dikutip sehingga hampir semua karakter dapat dimasukkan ke dalam simbol
- Assembly sering digunakan bersama preprocessor C atau m4
- Baris yang dimulai dengan
dnl,m4_dnl, atauCjuga harus diperlakukan sebagai komentar
- Baris yang dimulai dengan
Ada dan BASIC: kasus sintaks kecil yang mengguncang leksing
- Ada cukup sederhana untuk dileksing, tetapi penggunaan tanda kutip tunggalnya unik
- Seperti C, ia dapat memiliki literal karakter
'x' - Tanda kutip tunggal juga digunakan saat merujuk atribut seperti
Foo'Size Character'(')')'Imagemendeklarasikan karakter dan mengubahnya menjadi representasi string melalui fungsiImage
- Seperti C, ia dapat memiliki literal karakter
- Contoh Commodore BASIC meruntuhkan banyak asumsi syntax highlighting
- String dapat menghilangkan tanda kutip penutup di akhir baris
- Nama variabel diberi sigil seperti
$ - Keyword seperti
gotosecara aktif dileksing bahkan di dalam identifier
- Visual BASIC memiliki sintaks literal tanggal seperti
#1/1/2024# - Visual BASIC juga memiliki preprocessor directive seperti
#If DEBUG Then,#Else, dan#End If, sehingga leksing menjadi rumit
Perl: kompleksitas di antara Shell dan bahasa pemrograman
- Perl berada di antara Shell dan bahasa pemrograman, sehingga mewarisi kompleksitas keduanya
- Perl menjadikan regular expression sebagai elemen first-class dalam bahasa, dan pengaruhnya berlanjut ke bahasa lain seperti Python
- Sintaks substitusi Perl mirip sed, seperti
s/hello/Perl/i- Karakter tanda baca arbitrer dapat digunakan sebagai delimiter sebagai pengganti
/ - Ini nyaman ketika slash masuk ke dalam regular expression, seperti
s!hello!Perl!i - Jika menggunakan karakter berpasangan seperti
s{hello}{Perl}i, karakter tambahan diperlukan
- Karakter tanda baca arbitrer dapat digunakan sebagai delimiter sebagai pengganti
- Perl memiliki banyak prefiks ajaib yang harus di-highlight seperti string
m,s,y,qr,qw,qq,qx, dan lainnya digunakan bersama berbagai delimiter
- Agar tidak salah menilai
y/x/y/sebagai pembagian, konteks harus dilihat- Variabel Perl memiliki sigil seperti skalar
$, array@, dan hash%, sehingga membantu membedakan tanpa harus mem-parse seluruh grammar
- Variabel Perl memiliki sigil seperti skalar
- Perl memiliki kebiasaan memasukkan dokumen POD untuk man page di dalam source code
=worddi awal baris memulai dokumen POD dan=cutmengakhirinya
Ruby: target leksing tersulit
- Ruby terlihat seperti gabungan dari bahasa-bahasa sebelumnya, dan sintaksnya dinilai tidak terdokumentasi cukup formal
- Dokumen syntax pada manual Ruby dinilai ringan dalam detail
- Ruby mendukung sintaks backquote sekaligus dapat menggunakan backquote seperti nama metode, sehingga highlighter sulit menentukan apakah itu string atau bukan
- Ruby memiliki operator
<<dan heredoc sekaligus- Bentuk seperti
options[:includes] <<arg; trueada di kode nyata - Kode ini dapat terlihat seperti heredoc, dan Emacs pun menanganinya dengan salah
- Bentuk seperti
- Kode yang memasukkan heredoc ke dalam interpolasi string seperti
puts "This is #{<<HERE.strip} evil"juga valid - Dari 42 bahasa, Ruby disebut sebagai kejutan terbesar; Ruby mungkin tidak dapat dileksing tanpa parsing, dan bahkan dengan parsing pun sulit memastikan apakah ia dapat diinterpretasikan
Kompleksitas dilihat dari jumlah baris kode implementasi
- Jika berdasarkan jumlah baris kode implementasi highlighter tiap bahasa, FORTH adalah yang paling sederhana dan Ruby paling kompleks
- Implementasi terpendek adalah highlight_forth.cpp dengan 125 baris
- Implementasi yang relatif pendek mencakup m4 132 baris, Ada 149 baris, LISP 160 baris, MATLAB 166 baris, COBOL 186 baris, BASIC 199 baris, FORTRAN 200 baris, dan lainnya
- Implementasi skala menengah mencakup JavaScript 337 baris, TypeScript 371 baris, Kotlin 387 baris, Scala 387 baris, Assembly 447 baris, C 449 baris, Swift 455 baris, dan D 521 baris
- Implementasi terpanjang adalah Shell 570 baris, Perl 583 baris, dan highlight_ruby.cpp 1042 baris
1 komentar
Komentar Hacker News
Dari semua trigraph C, yang paling saya suka adalah bentuk seperti
do_action() ??!??! handle_error()Sekilas terlihat seperti sintaks penanganan error khusus, tetapi ternyata
??!??!diubah menjadi OR logis||, dan dengan aturan short-circuit evaluation, strukturnya menjalankanhandle_error()saatdo_action()mengembalikan nilai non-nol, jadi terasa memuaskan??!dikonversi menjadi|, sehingga??!??!menjadi||, yaitu “or”||karena alasan estetika?Bacaan yang menarik, tetapi justru membuat saya lebih bersimpati pada sudut pandang Lisp
Sejauh yang saya pahami, posisinya adalah bahwa sintaks bukan bagian yang terlalu penting dari sebuah bahasa, dan karena cenderung lebih menjadi hambatan daripada bantuan, sintaks sebaiknya dibuat sesederhana dan seseragam mungkin agar kita bisa fokus pada hal lain
Namun, belajar structural editing di Lisp sejauh ini lebih terasa seperti hambatan daripada bantuan, dan saya berharap suatu saat ada imbalannya
Jika dibuat sesederhana Lisp, perdebatan sintaks hanya terdorong menjadi masalah semantik, jadi lapisannya saja yang berubah
Menurut saya sintaks yang kompleks jauh lebih mudah dibaca dan ditulis daripada sintaks sederhana dengan semantik yang kompleks. Error sintaks mendapat umpan balik cepat, sedangkan error semantik bisa tersembunyi sampai runtime
Contohnya ada https://pyret.org/. Dalam praktiknya, sulit mengatakan Lisp itu sederhana atau pasti seragam
parinferdan ketahui key binding untuk tiga perintahslurp,barf, danraiseDengan empat hal ini saja, Anda bisa mendapatkan sekitar 95% manfaat paredit tanpa kompleksitasnya, dan trik lainnya bisa dipelajari setelah terbiasa
Ada bagian yang mengatakan “saya tidak tahu siapa yang ingin melakukan syntax highlighting C pada 35MB per detik, tetapi sekarang itu mungkin”; memang cepat, tetapi
tccbahkan di komputer yang sangat tua dapat mengompilasi 29MB C per detik menjadi kode biner: https://bellard.org/tcc/#speedMungkin bisa dibuat lebih cepat lagi, tetapi tampaknya tidak terlalu perlu
Ada beberapa hal yang terlewat oleh penulis
Bukan hanya TypeScript, Swift, Kotlin, dan Scala yang sampai pada ekstrem memasukkan kode sungguhan ke dalam interpolasi string; C#, Python, JavaScript, Ruby, Shell, dan Make juga mendukung hal serupa
Di Tcl, kode dan data sulit dibedakan sehingga
{ }pada dasarnya adalah delimiter string yang unik, dan padaxyzzy {#hello world}, apakah#hello worlditu komentar atau string tidak dapat diketahui sebelum waktu evaluasiPostgreSQL memiliki string ber-quote dolar yang praktis, sehingga seperti di https://www.postgresql.org/docs/current/sql-syntax-lexical.h...,
'Dianne''s horse',$$Dianne's horse$$, dan$SomeTag$Dianne's horse$SomeTag$memiliki makna yang samaString seperti
"I have $foo $bar's: @{[$bar x $foo]}"dapat mencetakI have 5 x's: xxxxxSintaks
@{[...]}memanfaatkan karakteristik Perl yang memungkinkan interpolasi array selain skalar;[...]di dalam membuat referensi array, lalu@{...}di luar melakukan dereference terhadapnya. Interpreter Perl mengizinkan kode arbitrer dalam ekspresi bagian dalam ituDengan begitu, ia bisa dinesting seperti
"foo { toUpper("bar { x + y } bar") } foo", dan jika+adalah penggabungan string, pada dasarnya sama dengan"foo " + toUpper("bar " + (x + y) + " bar") + " foo"Saya tidak tahu apakah ada bahasa yang benar-benar bekerja seperti ini
Saya suka Ruby, tetapi Ruby valid seperti
puts "This is #{<yang mencampur interpolasi string dan heredoc sulit dibelaSelain itu, di Ruby spasi juga bisa menjadi karakter quote. Dalam konteks tanpa operand kiri,
%memulai string ber-quote dan karakter berikutnya menunjukkan jenis quote, sehingga% hellomenjadi string yang berisihello.%(this is a string)atau%{this is a string}bagus, tetapi saya belum pernah melihat penggunaan spasi di alam liar, danirbjuga tidak menanganinya dengan benar, jadi rasanya boleh saja dihapusJika menulis
val s"${a} + ${b}" = "1 + 2", makaamenjadi1danbmenjadi2Dulu, dalam hot loop, kode seperti
log.trace($"Entering iteration {i} for customer {c.ID} [{c.ShortName}]");memanggilstring.Concatsetiap kali bahkan sebelum logger keluar, sehingga banyak logger mengimplementasikan interpolasi sendiriDi C#, Anda dapat mendeklarasikan overload yang menerima
DefaultInterpolatedStringHandleratau pola handler kustom, dan overload ini diprioritaskan sehingga dapat memeriksa apakah log benar-benar diperlukan sebelum menunda pembuatan stringAda satu lagi keanehan sintaksis yang tidak disebutkan di sini, yang merusak sebagian besar syntax highlighter
Di Java, Unicode escape bisa muncul di mana saja, bukan hanya di dalam string
Misalnya
class Foo\u007b}adalah kelas yang valid, dan\u000Adi dalam komentar//bisa diproses sebagai newline sungguhan, sehingga contohassertjuga berperilaku tidak seperti yang diperkirakanKarena komentar blok bisa diakhiri dengan Unicode escape, untuk menyembunyikan kode berbahaya di dalam komentar pada file sumber Java, cukup buat alasan yang masuk akal mengapa ada blok Unicode escape di dalam komentar
Developer yang tidak tahu sifat ini kemungkinan besar akan melihatnya sebagai kode yang dikomentari dan melewatkannya begitu saja
Ada bagian yang mengatakan “Ruby adalah bahasa yang menghindari semua upaya memahami sintaksnya”, tetapi dari sudut pandang TeX yang punya lexer yang bisa diprogram ulang secara arbitrer, itu masih tergolong imut
Katanya “semua programmer C tahu bahwa komentar multi-baris tidak bisa dimasukkan ke dalam komentar multi-baris”, tetapi bagi programmer Standard ML, itu bisa terasa seperti batasan yang mengejutkan
Komentar bersarang seperti
(* (* Nested (**) *) comment *)valid, danval _ = print "hello, world\n"setelahnya juga berjalan normalMengingat saat C muncul ia dianggap sebagai bahasa yang ekspresif, menarik bahwa komentar bersarang tidak dimasukkan ke dalam bahasa tersebut
ML tidak punya komentar satu baris, jadi itu juga batasan yang sama mengejutkannya; dan ini pertama kalinya saya mendengar C disebut “ekspresif”, meski pada 1972 dibandingkan assembly mungkin memang begitu
Selain itu, saya tidak tahu apa hubungan sintaks komentar dengan ekspresivitas bahasa, dan menurut definisi saya rasa tidak ada sama sekali
Secara tradisional, analisis leksikal dianggap sebagai ranah yang hanya memakai finite-state automaton seperti regex, sehingga fitur seperti itu terlihat berada di luar cakupan lexing
#if 0Bisa dibungkus seperti
#if 0 ... #if 0 ... #endif ... #endifSaya ingin melihat implementasi syntax highlighting joe dalam bentuk yang bisa digunakan ulang
Format di https://joe-editor.sf.net/ cukup kuat untuk menyorot Python f-string dengan benar
Dokumentasi dan contoh terkait ada di https://github.com/cmur2/joe-syntax/blob/joe-4.4/misc/HowItW..., https://gist.github.com/irdc/6188f11b1e699d615ce2520f03f1d0d...
Sintaks state dan transisinya jauh lebih mudah dipahami dibandingkan tool standar
Kekurangannya adalah kumpulan aturan menjadi bertele-tele dan agak sulit disusun secara ideal, tetapi menurut saya justru menjadi kelebihan karena semua aturan produksi lebih mudah disimpulkan dari kode
Sepertinya penulis belum pernah mencoba syntax highlighting untuk TeX
Itu mungkin baik untuk kesehatan mental, karena di TeX biasanya syntax highlighting yang lengkap mustahil dilakukan tanpa interpretasi
Parsing saja bahkan tidak cukup, karena peran tiap karakter bisa didefinisikan ulang, sehingga hal seperti “mulai sekarang K adalah
{dan C adalah}” pun bisa dilakukanDalam kenyataannya, ada juga paper arXiv yang memakai fitur terkutuk ini
.texyang saya temukan di hard drive, highlighting-nya cukup bagus tanpa rusakTargetnya adalah mencakup 99,9% penggunaan dunia nyata. Dengan begitu, kemungkinan besar keluaran LLM pun sebagian besar tercakup
Sintaks yang sulit dipahami biasanya juga bukan masalah besar selama string atau komentar tidak berlanjut sampai akhir file dan menutupi sisa source code
\makeatletterbukan berarti “membuat sesuatu menjadi karakter at”, melainkan berarti memperlakukan karakter@sebagai huruf saat parsingMenurut saya, menulis engine pewarnaan sintaks yang bagus seperti Vim itu tidak mudah
Pewarnaan sintaks membutuhkan pemrosesan konteks, yaitu menerapkan aturan yang berbeda pada konten yang bertumpuk dengan cara tertentu
Penyorot sintaks Vim memungkinkan kita mendeklarasikan dua jenis item,
matchdanregion;matchadalah aturan leksikal sederhana, sedangkanregionmemiliki ekspresi yang masing-masing mencocokkan awal, akhir, dan bagian tengahItem bisa dideklarasikan agar hanya aktif ketika berada di dalam wilayah tertentu, dan relasi penyertaan juga bisa saling dideklarasikan
Di atas struktur makna dasar ini, ada berbagai fitur yang ditambahkan untuk situasi khusus. Bahkan Justine pun rasanya sulit membuatnya langsung di sesi wawancara; mungkin perlu setidaknya tugas semalaman
Di sini ada skrip
genmanyang menerima hasil konversi HTML manpage lalu memolesnya menjadi HTML manual TXR: https://www.kylheku.com/cgit/txr/tree/genman.txrBagian yang terlihat putih adalah template literal, sementara kode Lisp berada di dalam direktif seperti
@(do ...). Kata kunci TXR tampak ungu, kata kunci TXR Lisp tampak hijau, dan kata yang sama pun bisa berbeda tergantung konteksQuasi-string juga bisa memuat tata bahasa bertumpuk, dan di dalamnya bisa ada lagi kode tertanam atau quasi-string. File definisi sintaks
txr.vimdantl.vimkeduanya dihasilkan dari https://www.kylheku.com/cgit/txr/tree/genvim.txrKalau tidak dilakukan begitu, mungkin karena masalah efisiensi. Misalnya, alih-alih hanya menyorot bagian yang terlihat di layar, harus mem-parse seluruh file sehingga biayanya bisa membesar