-
Notifications
You must be signed in to change notification settings - Fork 85
マクロでコード中の位置を取得・使用する機能
2020年1月25日の0.0.4のリリースで導入された多段階計算とマクロの機構により,より簡潔な記述と素早いエラー発見を両立したDSLをSATySFi上で定義して使える状況が或る程度整いました.しかし,このマクロ機構ではエラーの際はどんなエラーになったかの種類を標準出力に出して停止することはできても具体的にどこが悪かったかを(型エラーのように)コード中の位置を指し示して報告することはできませんでした.そこで,マクロを適用して処理するステージ0の文字列の内容は実際にソースファイル中のどこにあるのかをエラー時に指し示せるようにするために,コード中の位置がステージ0で取得できる文字列リテラル @`…`
を導入しました(commit hash: 03d3991
).
まず,input-position
型 という新しい基本型が導入されました.そして位置つきの文字列リテラル @`…`
がステージ0で input-position * string
型をつけて扱われます.このリテラルを書くと,文字列の内容の先頭位置とそこから始まる実際の内容の組の値として扱われます.input-position
型の値からは以下のような型をもつ新しいプリミティヴ get-input-position
を用いることでファイル名・行番号・何文字目かを表す組を得ることができ,これを使ってコード中の位置を明示したエラー報告なりなんなりができるという算段です.
val get-input-position : input-position -> string * int * int
勿論エラー報告に限らず正常系でも使えます.最もシンプルな例として,単にメッセージと共に書いた行が取得できるマクロを示します:
@stage: 1
let-inline \message-with-pos@ ~poss =
~(let (ipos, msg) = poss in
let (fname, ln, _) = get-input-position ipos in
&(let it-msg = embed-string ~(lift-string msg) in
let it-fname = embed-string ~(lift-string fname) in
let it-ln = embed-string (arabic ~(lift-int ln)) in
{#it-msg; (at line #it-ln; in #it-fname;)}
)
)
poss
が input-position * string
型の引数であり,ここからファイル名 fname
と ln
を取り出しています.
こうして定義したマクロ \message-with-pos@
を以下の要領で使うと,
14| document (|
15| title = {Position};
16| author = {gfn};
17| |) '<
18| +p{
19| \message-with-pos@~(@`Hello, macro!`);
20| }
21| >
以下のような結果が得られます:
やったぜ.
エラー報告に使うために言語そのものに追加する機能としてはこれで十分ですが,簡単にエラー報告できるようにするには位置をトラックするパーサーコンビネータなどを整備する必要があると思います(satysfi-base
ライブラリの parser
パッケージを拡張するとよさそうです).また,SATySFiは当初あまり文字列を加工してほしくないという動機から文字列操作の機能が意図的にかなり貧弱になっていましたが,大々的にDSLを使えるようにするには文字列加工の言語機能やライブラリを整備する必要がありそうです(これも一応既に satysfi-base
の string
パッケージがわりと強力ではあります).
また,細かいこととして,今のまだリリースしていない実装ではファイル名としてbasenameだけが返るようになっていますが,絶対パスを返すようにした方が良さそうです.
- トップページ
- The SATySFibook Web公開版 第1版
- Wiki
- 目的別パッケージ一覧
- コマンドライン書式
- SATySFiコマンド一覧
- Satyrographos(パッケージマネージャ)
- 新しい言語機能の紹介
- 言語機能の構想