SatooRu's Profile

全ての記事梶研の進捗日常の記録制作物一覧

ncss(自作プログラミング言語)

2023年1月6日

thumbnail

なぜ

今までの会話でこんなことがありました

A. 使ったことあるプログラミング言語は?
B. うーん... HTMLCSS かな?

経験者なら違和感を感じると思います

どっちもプログラミング言語じゃなくね?

厳密に言うと HTML は マークアップ言語で CSS は スタイルシート言語 です。
プログラミング言語だ、と言う人もいれば違うと言う人もいます。

そこで私は思いつきました。
「プログラミング言語にすればいい!」

ということで作りました
目標は

CSSをプログラミング言語にする

はじめに

プログラミング言語を作るには、他のプログラミング言語を使用します

  • Ruby は C言語
  • Python は C言語, Java...

やはりC言語で実装するのが基本的ぽい、が、めんどくさい!
そこで私は JavaScript で実装することにしました。

決め手は以下の通りです

  • 使い慣れている
  • ブラウザで実行できる
  • 公開しやすい
  • パクれる 参考になるリポジトリがあった

自作言語について

言語仕様は この (GitHub) ようにしました。
サンプルコードは こちら (GitHub) です。

言語名は

CSS(カスケーディング・スタイル・シート) ではない

ということで

NCSS (not CSS)

としました。SCSSを意識してますね

工夫点はcssらしくしたことです。(目標だから当然)
さらに scss らしいあの うるさい ネストを再現できるように、
グループ というものを追加しました。

1/* scssらしいうるささの再現 */ 2#main { 3 width: 100vw; 4 5 .container { 6 margin: 10px; 7 8 .content { 9 font-size: 1.2rem; 10 background-color: aqua; 11 } 12 } 13}

実装には JavaScriptを使った と書きましたが、制作は TypeScript に切り替えました。
型が無いとあまりにも不便だったからです。型を定義すれば文字列でも選択肢を絞れるから楽でした。
公開する前に JavaScript にコンパイルしています。

使い方

node が入っている場合は↓でインストールできます

npm i -g @satooru65536/ncss

↓ でncssを実行できます。

ncss ./main.ncss

ncss を使うためにVScodeの拡張機能も作りました。

難しかった点

こぴぺしたので あまり苦労しませんでしたが、returnberak の扱いが厄介でした。
関数の中で同じ関数をなん度も呼び出しているので、どこまで遡って中断すればいいか分からなかったからです。

何言ってるか分からない場合は ↓ を見て察してください。(簡単に説明する方法わからない)

1/* mian.ncss */ 2#main { 3 sub: ""; 4 content: "main!!"; 5 return: ""; 6} 7 8#sub { 9 --i: 0; 10 .while [--i < 3] { 11 .if [--i == 0] { 12 return: "sub return"; 13 } 14 transform: --i var(--i) + 1; 15 } 16 content: "error"; 17}
1// ブロック内の処理を順番に実行する関数 2function eval_statement_list(/* ... */) { 3 for (/* ブロック内の処理を一つずつ */) { 4 eal_statement(/* ... */); 5 } 6} 7 8// 処理を実行する関数 9function eval_statement(/* ... */) { 10 ... 11 else if (/* 関数を呼び出す場合 */) eval_statement_list(/* ... */); 12 else if (/* 代入の場合 */) eval_assign(/* ... */); 13 else if (/* 変数宣言の場合 */) eval_assign(/* ... */); 14 ... 15}
1[処理手順はイメージこんな感じ] 2 3#main 内のブロックを処理 eval_statement_list() 4 #sub 内のブロックを処理 eval_statement_list() 5 eal_statement(--i: 0;) 6 eal_statement(.while) 7 .while 内のブロックを処理 eval_statement_list() 8 eal_statement(.if) 9 .if 内のブロックを処理 eval_statement_list() 10 eal_statement(return) // eval_statement_list を何回遡れば...? 11 // if ブロック > 中断 12 // eal_statement(transform) 13 14 // while ブロック > 中断 15 // eal_statement(.if) 16 // eal_statement(.if) 17 18 // #sub ブロック > 中断 19 // eal_statement(content) 20 21// #main ブロック > 続行 22 eal_statement(content) 23 eal_statement(return) 24// #main ブロック > 中断 25// プログラム終了 26 27/* ------------------------------------ */ 28 29// 中断と続行の判断基準は? 30// => https://github.com/ncss-project/ncss/blob/main/src/evaluator.ts#L70 31// called_global_func フラッグがポイント 32// 関数のブロックから直接呼び出されているかを判断(if/else/group...のブロックはfalse) 33// false なら中断する 34// => https://github.com/ncss-project/ncss/blob/main/src/evaluator.ts#L78

おわりに

ちゃんとしたプログラミング言語は難しくても、この程度ならとても簡単でした。
ぜひ ソースコード を解読してみてください

GitHub

ncss-project