Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
プログラミング言語(?)を自作した話
Search
meil
December 06, 2019
Programming
0
770
プログラミング言語(?)を自作した話
meil
December 06, 2019
Tweet
Share
More Decks by meil
See All by meil
クラシルの開発で使ってるGitHub Actions
meilcli
0
180
GitHub ActionsのActionを作る
meilcli
0
410
GitHub Actions入門
meilcli
0
380
Azure Pipelinesのすゝめ
meilcli
0
300
Other Decks in Programming
See All in Programming
オニオンアーキテクチャを使って、 Unityと.NETでコードを共有する
soi013
0
350
Zoneless Testing
rainerhahnekamp
0
150
traP の部内 ISUCON とそれを支えるポータル / PISCON Portal
ikura_hamu
0
140
ATDDで素早く安定した デリバリを実現しよう!
tonnsama
1
1.2k
CQRS+ES の力を使って効果を感じる / Feel the effects of using the power of CQRS+ES
seike460
PRO
0
230
KubeCon + CloudNativeCon NA 2024 Overviewat Kubernetes Meetup Tokyo #68 / amsy810_k8sjp68
masayaaoyama
0
290
PHPとAPI Platformで作る本格的なWeb APIアプリケーション(入門編) / phpcon 2024 Intro to API Platform
ttskch
0
360
各クラウドサービスにおける.NETの対応と見解
ymd65536
0
230
return文におけるstd::moveについて
onihusube
1
1.4k
Effective Signals in Angular 19+: Rules and Helpers
manfredsteyer
PRO
0
350
命名をリントする
chiroruxx
1
570
ISUCON14感想戦で85万点まで頑張ってみた
ponyo877
1
220
Featured
See All Featured
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
19
2.3k
Producing Creativity
orderedlist
PRO
343
39k
Mobile First: as difficult as doing things right
swwweet
222
9k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
226
22k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
8
1.2k
Writing Fast Ruby
sferik
628
61k
Building an army of robots
kneath
302
44k
No one is an island. Learnings from fostering a developers community.
thoeni
19
3.1k
Being A Developer After 40
akosma
89
590k
Building Your Own Lightsaber
phodgson
104
6.2k
Fantastic passwords and where to find them - at NoRuKo
philnash
50
2.9k
Designing on Purpose - Digital PM Summit 2013
jponch
116
7k
Transcript
プログラミング言語(?)を自作した話 Mobile Act OSAKA #12
自己紹介 • Twitter: @penguin_sharp • GitHub: MeilCli • Web: https://meilcli.net
• Skill: C#, Kotlin, Android, Azure Pipelines, GitHub Actions • Work: Fenrir Inc. ◦ Android Application Engineer ◦ 発言は個人の見解であり所属する組織の公式見解ではありません
なぜ言語を自作することになったのか
A. GitHub ActionsのAction間でデータのやり取りを簡単にできるようにしたかったから jobs: carthage: runs-on: macOS-latest steps: - uses:
actions/checkout@v1 - uses: MeilCli/carthage-update-check-action@master id: outdated - uses: 8398a7/action-slack@v2 if: steps.outdated.outputs.has_carthage_update != 'false' with: status: ${{ job.status }} text: ${{ steps.outdated.outputs.carthage_update_text }} author_name: GitHub Actions env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 自作Action Slackに通知する Action
A. GitHub ActionsのAction間でデータのやり取りを簡単にできるようにしたかったから jobs: carthage: runs-on: macOS-latest steps: - uses:
actions/checkout@v1 - uses: MeilCli/carthage-update-check-action@master id: outdated - uses: 8398a7/action-slack@v2 if: steps.outdated.outputs.has_carthage_update != 'false' with: status: ${{ job.status }} text: ${{ steps.outdated.outputs.carthage_update_text }} author_name: GitHub Actions env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} OutputのIDを指定 自作Actionの出力 (テキスト)
A. GitHub ActionsのAction間でデータのやり取りを簡単にできるようにしたかったから jobs: carthage: runs-on: macOS-latest steps: - uses:
actions/checkout@v1 - uses: MeilCli/carthage-update-check-action@master id: outdated - uses: 8398a7/action-slack@v2 if: steps.outdated.outputs.has_carthage_update != 'false' with: status: ${{ job.status }} text: ${{ steps.outdated.outputs.carthage_update_text }} author_name: GitHub Actions env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} Json形式での出力 も対応してる そのまま通知されるので 人間が読める形式である 必要性
A. GitHub ActionsのAction間でデータのやり取りを簡単にできるようにしたかったから jobs: carthage: runs-on: macOS-latest steps: - uses:
actions/checkout@v1 - uses: MeilCli/carthage-update-check-action@master id: outdated - uses: 8398a7/action-slack@v2 if: steps.outdated.outputs.has_carthage_update != 'false' with: status: ${{ job.status }} text: ${{ steps.outdated.outputs.carthage_update_text }} author_name: GitHub Actions env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} Actionの間にJson to Textな変換ができる Actionがあれば便利そう
言語の要件 • GitHub Actionsで動かすのでNode.js上で動作 • JSON Object to TextやJSON Array
to TextなどなどTextへの柔軟な変換性 • TypeScriptで作成 ◦ JavaScript使いたくないので… • ついでに ◦ 実装と言語仕様は切り離して他言語での実装もできるように ◦ 言語仕様に対するテストデータを実装と切り離して用意 ▪ 各実装でのテストが楽になりそう
どういう感じの実装にするか
C#の場合 ※図はちょっとてきとーに作ってます コンパイラー プログラムコード 言語仕様など プログラムコード(CIL) ランタイム コンパイラーな ど 実行
C++やWeb Assemblyなど
作るもの コンパイラー プログラムコード 言語仕様など ?????????? ランタイム コンパイラーな ど 実行 C++やWeb
Assemblyなど Node.js Node.jsで動作
作るもの コンパイラー プログラムコード 言語仕様など ランタイム 実行 コンパイル結果を中間言語などにする必 要はなくそのままNode.js上で実行すれ ばいい インタプリタっぽい(?)
コンパイラーどうやって作るか
コンパイラーのしくみ Wikipediaによるとコンパイラーは以下の部分からなることが多いらしい • ソースコードを読み込み、トークンに分解する字句解析部 • トークン列をもとにプログラムの構文木を構築する構文解析部 • 構文木からオブジェクトコードを生成するコード生成部 https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9#%E3%81%97%E3%81%8F%E 3%81%BF%E3%81%A8%E8%A8%AD%E8%A8%88
なるほど
みようみまねでコンパイラーを作ってみる コンパイルから実行まで4つのフェーズに分ける • 字句解析(Lexer): コードをTokenに変換 • パーサー(AST Parser): Tokenから構文木に変換(実行不能形式) •
構文解析(Semantic Analyzer): 構文木を実行可能な構文木に変換 • コンパイラー(Compiler): 実行可能な構文木から実行用のオブジェクト生成 ◦ コンパイラーの中でコンパイラーって名前が出てきたややこしいですがいい名前が思いつかな かっただけです
Lexer 1. あらかじめ決めた言語仕様から意味上 の区別となるトークンを決定する 2. プログラムコードを1文字ずつ読み込み、 トークンの種類を抽出する 3. ついでにエスケープシークエンスを行っ ておく
https://github.com/MeilCli/Jfol.TS/blob/master/src/lexers/lexer.ts
AST Parser 1. トークンを1つずつ見ていき、 特定の意味のあるトークンが きたら特定の分解を行うという 感じにする 2. このときツリー状になるように 分解する
https://github.com/MeilCli/Jfol.TS/blob/master/src/ast/p arser.ts
Semantic Analyzer • AST ParserでパースしたNodeのま までは実行しにくい形になっている ◦ 式を単純に分解している • 演算子の優先度を加味した構文木
に変換する ◦ 逆ポーランド記法への変換を使う 中置記法: (2 + 4) * (1 + 3) 後置記法: 2 4 + 1 3 + * 前置記法: * + 2 4 + 1 3 これを構文木で↓のように表す * + + 2 4 1 3
Compiler • Semantic Analyzerで実行可能な構文木になっているので組み込みの関数や 演算子などと紐付ける • 紐づくNodeは以下の感じ ◦ リテラル ◦
関数 ◦ 演算子 ◦ フィールド(JSON) • 紐付けができたら実行するだけ ◦ 細かい仕組みを説明すると長くなるので割愛
肝心の構文について あまり深くは考えずに作成(実験的構文としてそのうち破壊的変更するかも) • $フィールド名でJSONのフィールドを参照 ◦ 配列の場合は$フィールド名[配列のループ時に実行するボディ ] • $$関数名(引数)[関数ボディ]で関数を実行 •
フィールドや関数以外の文字はそのまま出力
こういう感じ { "array": [ { "package": { "name": "pack1" }
}, { "package": { "name": "pack2" } } ] } Packages Total: $$(array.length) $array[$$index: $(package.name)$$separator[\n]] JSON 自作言語 Packages Total: 2 0: pack1 1: pack2 結果
おわりに • 言語仕様: https://github.com/MeilCli/Jfol • 実装: https://github.com/MeilCli/Jfol.TS • テストデータ: https://github.com/MeilCli/Jfol.Test
• Playground: https://github.com/MeilCli/Jfol.Playground なお、npmへ公開した直後に他のことにモチベが出たため 本題のGitHub ActionsのAction作成まではできてないです