Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>LoopholeNew to Visual Studio Code? Get it now.
Loophole

Loophole

Ray Huang

| (0) | Free
Syntax highlighting, inline diagnostics, CodeLens, hover, completion and a run button for the wish and genie languages.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Loophole for VS Code

.wish 和 .genie 的語法高亮、行內診斷,以及一個播放鍵。

Loophole 是什麼

一個工程師笑話,被當成技術規格認真對待。

精靈說「你有三個願望」。工程師說:「我許願,扣掉我三個願望。」 願望數存在一個兩位元的格子裡,沒有負數這種東西——於是它繞回最大值。

「已實現。您現在還有三個願望。」

Loophole 是一個編譯器, 把那個笑話變成機器可以驗證的東西。它讀兩種語言:

誰寫的 裡面有什麼
.wish 許願的人 一個世界,和在裡面許的願望
.genie 精靈 它禁什麼,以及它以為自己守著什麼

不用裝任何東西就能試——線上有二十八章的課程, 編譯器跑在你的瀏覽器裡。

這個套件做什麼

語法高亮

  • 兩種語言都上色,註解(#)、括號配對、大括號自動縮排
  • uint<N> 的寬度單獨上色——那個數字是整個笑話的來源
  • define 綁的別名跟真正的操作同色,因為它就是同一件事

行內診斷——套件內含編譯器本體(WebAssembly),所以判決來自編譯器自己, 不是另外寫一套規則。你打字的時候它就在判。

顯示成
讀不懂這個檔案 錯誤。什麼都沒被判,這是唯一真正的問題
精靈拒絕了這個願望 提示,附上是哪條規則擋的
EXPLOIT——合規卻拆穿了 提示,附上破了哪幾條不變量
什麼都沒破 不顯示

破掉不變量不算錯誤,這是刻意的。 在這個語言裡,寫出一個合規卻拆穿精靈的願望 就是你的目標。把它算進錯誤數,等於編輯器在騙你說你做壞了。 所以左下角那個紅色數字只數一件事:編譯器讀不懂的檔案。

.wish 開頭寫 # genie: mine.genie 就會用那個精靈來判(跟編譯器的 make run 同一個慣例),沒寫就用內建的。那個檔案還沒存檔也算—— 編輯精靈的時候,願望那邊的波浪線會跟著動。

單獨寫一個 .genie 也會即時檢查語法。 你在調精靈的規則、還沒寫任何願望的時候, 打錯字(少一個括號之類)會當場劃出來,不用等到某個願望去引用它才發現。 只查語法——精靈引用的 register 存不存在要看願望裡的世界,光看精靈不知道。

每個願望上方直接寫著它成不成。 EXPLOIT · broke I2、not granted · R1、 或者 clean——這個語言唯一想回答的問題,掛在程式碼上,不用去開面板。

滑過去看說明。 滑到保留字上會顯示它的語法和意思——那句話是編譯器自己的, 從 loophole --keywords 來的,不是插件另外寫的一份。 滑到 register 上更有意思:它顯示這個值在每個願望之後是多少,

wishes  uint<64>
after each wish: 3 → 2 → 18446744073709551615

那就是下溢,直接給你看。(那個數字是精確的——編譯器把它當字串傳, 因為 JSON 的 number 在瀏覽器裡是浮點,會把它讀成 ...552000。)

自動補全。 保留字帶說明,而且看得懂上下文:sub 後面給你 register, kill 後面給你人。名字從編譯器判決來,檔案還沒寫完不能判的時候退回讀原始碼。

大綱和跳定義。 左側邊欄(或 ⌘⇧O)列出這個檔案宣告了什麼——register、 attribute、人、願望,而 define 掛在做它的那個願望底下。精靈檔案列 concept、 rule、invariant。

⌘ 點一個名字會跳到它的宣告,而這在這個語言裡有戲:

    mercy rival        ⌘點 mercy  →  define mercy := kill

你點下去才發現這個溫柔的名字指向什麼,而且大綱裡就直接寫著 mercy → kill。 define 可以重綁,所以跳的是「在你問的那一行當下生效的那個綁定」。

位置全部來自編譯器,不是插件用 regex 猜的——因為要知道 mercy 是什麼, 就得解析 define mercy := kill,而那是別名軸,是這個語言的一半。

執行

上面那些都是環境式的——你打字它就在判,你沒有要求過。但一個會執行的語言 應該有「執行」這個動作,所以編輯器右上角有一個播放鍵:

loophole --genie mine.genie w.wish

它把這行原字打進終端機,你看得到指令、按上鍵可以重跑。輸出是編譯器真正的 那份報告,有時間順序——先看規則能不能擋、收過路費、執行、事後才量:

wish experiment
    rules     passed. no rule refuses this wish.
    toll      wishes 3 -> 2
    ran       sub    wishes, 3   (2 - 3 on uint<2> = 3)
    checks    I2          VIOLATED  wishes <= max(before(wishes) - toll, 0)
    verdict   EXPLOIT. legal, yet it broke I2.

⌘⇧B 也可以,那是同一件事的 task 版本,而且錯誤會進 Problems 面板。

執行需要你裝了本體。 波浪線用的是套件內含的 WebAssembly 編譯器, 但「執行」跑的是你 PATH 上真正的 loophole——沒裝的話它會直說並給你安裝指令, 不會偷偷用內含的那個代跑。兩者的判決證明過完全相同(CI 每次都在驗), 但如果偷偷代跑,「執行」這個動作在不同機器上就會是不同的事。

裝的版本跟套件內含的版本不一樣時它也會講一聲——不然編輯器和終端機可能會 給你兩種說法,而你不知道為什麼。

裝

在 VS Code 的擴充套件裡搜 Loophole,或者:

code --install-extension rayhuang2006.loophole

裝編譯器本體

上一節的播放鍵需要它。沒有它,套件仍然會上色、會判、會給你 lens 和 hover—— 就是不能執行:

curl -L -o loophole https://github.com/rayhuang2006/Loophole/releases/latest/download/loophole-macos-arm64
chmod +x loophole && sudo mv loophole /usr/local/bin/

Linux 換成 loophole-linux-x86_64。或者 git clone 之後 make—— 一個 C++ 檔案,沒有任何相依。裝在別的地方的話,設定 loophole.path。

裝好之後終端機也是一等公民,而且有些事只有它做得到—— --hunt 讓機器自己去把洞找出來、批次判一整個資料夾、 用離開碼在 CI 裡擋 PR:

loophole --hunt w.wish && echo "滴水不漏"

授權

MIT。改這個套件請看 CONTRIBUTING.md。

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft