文字列に埋め込み可能なミニスクリプト言語Scripty

#Tech

文字列に埋め込み可能なミニスクリプト言語Scripty Scripty:シンプルスク

Scriptyは、文字列に埋め込むことを前提とした極めてシンプルなスクリプト言語です。

変数の代入や条件分岐がないため、シンプルなクエリ言語として活用できます。

作者は自身の静的サイトジェネレーターZineで利用しており、将来的に静的解析やコンパイルを視野に入れています。

用途に応じて評価コンテキストを定義することで、多様なユーザーエクスペリエンスを実現可能です。

ソフトウェア開発者Kristoff Chee氏が、文字列やドキュメント内に埋め込むことを想定した極めてシンプルなスクリプト言語「Scripty」を公開しました。Scriptyは、ループや変数といった一般的な機能を持たない、単一の式で構成される特殊な言語です。Zineという静的サイトジェネレーターの一部として利用されてきたScriptyですが、今回、他の開発者も利用しやすいように実装例が公開されました。将来的な静的解析やコンパイルを視野に入れた設計が施されており、今後のWeb開発に新たな可能性をもたらすかもしれません。

Scriptyとは?その特徴

Scriptyは、従来のスクリプト言語とは一線を画す、非常にシンプルな言語とのことです。ループ処理や変数定義といった基本的な機能は持ちません。その代わりに、評価コンテキストと呼ばれる、データ型やメソッドを定義する仕組みを提供しており、これにより、Scriptyの表現力は大きく広がります。例えば、$site.page('blog').subpages().first().title のように、サイト、ページ、タイトルといった概念を定義することで、特定の情報を抽出するクエリを記述できます。この構造は、テーブルや銀行口座、音楽の楽譜など、他のデータ構造にも応用可能です。

技術的な背景と実装

ScriptyのVM(仮想マシン)は、Zigというプログラミング言語で実装されており、スタックベースのインタープリターを採用しています。パーサーが生成したノードをスタックにプッシュし、関数呼び出しの際に値をポップして処理を行うという仕組みです。Kristoff氏によると、実装は比較的単純で、MultiArrayListという構造体を使用した部分以外は、Zineの高速な静的サイトジェネレーターとして機能するほど効率的とのことです。また、AFL(American Fuzzy Lop)を用いたファジングテストも実施されており、安定性とセキュリティの確保に努めています。

今後の展望と可能性

Kristoff氏は、Scriptyの簡潔さを維持したまま、将来的に静的解析やコンパイルを可能にしたいと考えています。Zineでは既にSuperMDやSuperHTMLといった独自のドキュメントフォーマットの参照ドキュメントを生成するシステムが存在しますが、Scriptyの実装と連携させることで、より高度な機能が実現できる可能性があります。さらに、SuperHTML言語サーバーによるScripty式の自動補完機能の提供や、Zigをターゲットとしたコンパイル機能の追加も検討されています。これらの機能が実現すれば、ScriptyはWeb開発におけるクエリ言語として、あるいはテンプレートエンジンの一部として、より幅広い分野で活用されるかもしれません。

まとめ

Scriptyは、そのシンプルさゆえに、Web開発の新たな可能性を秘めた言語だと言えるでしょう。Kristoff氏によると、現在別のプロジェクトに注力しているため、Scriptyの開発は少し先になる可能性があるとのことですが、今後の進化に注目が集まります。特に、静的解析やコンパイルといった機能が実現すれば、Web開発の効率化やセキュリティ向上に大きく貢献することが期待されます。

原文の冒頭を表示(英語・3段落のみ)

Scripty is an extremely simple (and deliberately limited) scripting language meant to be embedded in strings or other similar constructs, usually in a host document format (but not only).It looks like this: $site.page('blog').subpages().first().title.However, whether your evaluation context is made up of ‘sites’, ‘pages’ and ‘titles’, rather than ‘tables’, ‘bank accounts’, ‘musical notes’, ‘apple pies’ or anything else, that’s entirely up to you.Scripty allows you to provide an evaluation context that defines primitive and aggregate types, and also which methods can be called on them.Lastly, Scripty has no for loops, if statements or variable assignment. A Scripty program is just a single expression, so one way of thinking about it is as a framework for building simple query languages.I’ve been using Scripty for a while now as part of Zine, my static site generator, but until now I never really spent effort trying to make it usable for other people.So recently I set out to provide an example implementation, and in the process I’ve implemented a few simplifications that I thought about in the past but that I never bothered actually implementing.Setting up a Scripty VM requires being familiar with Zig, but it’s otherwise pretty easy, see https://github.com/kristoff-it/scripty.VM implementationThe Scripty VM is a stack-based interpreter. A parser produces nodes that get analyzed and pushed onto the stack, and on function call application (when a ) token is seen), some values are popped off the stack, the function call is performed, and the resulting value is pushed back on the stack.I would describe this implementation as mostly naive, although I do get a bit clever with MultiArrayList (struct of arrays), but overall this is good enough for Zine as it’s still one of the fastest static site generators that I know of (this blog builds in less than 20ms on a Mac Mini M2 Pro and evaluation of Scripty expressions is a minuscule fraction of that time).I’ve also given this implementation a good amount of fuzzing with AFL, although this code is now gone, to be replaced by a native Zig fuzzer implementation.Future workI’m purposefully keeping Scripty very simple in order to support static analysis and compilation in the future.In Zine I already have a system to generate reference docs for SuperMD documents and SuperHTML templates (SuperMD, SuperHTML), but it’s a bespoke system that is not directly driven by the Scripty implementation (although it’s not too hard to make it yourself, it’s just a matter of adding extra definitions to your Scripty evaluation context definition and then using Zig comptime reflection to generate the docs).On the subject of static analysis it would also be nice to have a way for the SuperHTML language server to provide autocomplete suggestions for Scripty expressions, something that is currently not available.Lastly, being able to compile Scripty expressions to native code would be a stepping stone towards being able to compile SuperHTML templates (and of course any other host language that other people might end up using Scripty with). My plan in this regard is to use Zig as the target and then let the Zig compiler do all the heavy lifting.I plan to get to all of these things (roughly in this same order, so docs first, compiler last), in the not-too-far future, but I am currently putting more effort into another somewhat ambitious project so it might take a bit before I circle back to Scripty.Scripty flavorsOne reason why I believe that Scripty is of some value despite its extreme simplicity, is how you can still use it to produce very different user experiences.The example of Scripty expression that I showed at the beginning is inspired by SuperHTML, where Scripty expressions are placed in HTML attributes and used to generate HTML code accordingly.$site.homepage.subpages().first().link()

In this example we navigate from what is presumably a Site struct, into an instance of a page, and so on.In SuperMD Scripty is used in a completely different way. Without getting too deep into the weeds of how SuperMD works, take a look at this example usage:$video.asset('video.mp4').autoplay(true).muted(false)

In SuperMD Scripty is used as a “builder”/“fluent” interface in order to define embeds. In this example we are defining a video embed and then setting some of its properties. Every function call sets a property on the original embed definition and then returns the mutated value so that the subsequent function call can do the same, and so forth.In ConclusionWhen I originally set out to implement Scripty it was as part of my effort to create a new HTML templating language (which then became SuperHTML). I had reached a breaking point with Hugo’s templating language and decided to free myself from having to use curly-braced templating languages (which are essentially macros, and I hate macros).The realization I had in the process is that all these templating languages (and not only) have essentially two languages in them: one to build expressions, and one to interoperate with the outer document.So I decided to make them truly separate languages, and the result is a tiny language that can both be very easy to get used to (it’s essentially just field navigation and function calls, no monkey business), but that can also be tailored to each specific use case by designing the evaluation context accordingly.

※ 著作権に配慮し、引用は冒頭3段落までです。続きは元記事をご覧ください。

元記事を読む ↗