Slide 1

Slide 1 text

Wasmで動くRust製マーク ダウンパーサーを自作した話 0Yu 隅田川.dev

Slide 2

Slide 2 text

0yu(おゆ,ぜろゆー) 好きな技術 ● Webフロントエンド、Rust 趣味 ● 映画鑑賞・旅行・ゲーム etc ● 最近はハイラルの勇者をしています 自己紹介 っっっz yud0uhu 2

Slide 3

Slide 3 text

● Rustと言語処理系の勉強のため、簡易的なマークダウンパーサーを スクラッチで実装した ● 生成したWASMをNuxt3+Viteの環境で動かした はじめに

Slide 4

Slide 4 text

字句解析 ● テキストを字句の列(トークン)に分解する こと ● 字句解析を行うプログラムを字句解析器 (lexerまたはtokenizer)と呼ぶ 言語処理系の概要

Slide 5

Slide 5 text

構文解析 ● トークン列を抽象構文木(abstract syntax treeまたはAST)に変換する ● 抽象構文木とは、言語の構文を解釈し、 データ構造を取り出した(抽象化した)木構 造のこと 言語処理系の概要

Slide 6

Slide 6 text

意味解析 ● 構文木の意味を解析する ● コンパイラでは、この段階で中間コード を生成する 言語処理系の概要

Slide 7

Slide 7 text

最適化 ● 中間コードを変形して、効率のよいプロ グラムに変換すること ● コンパイラでは、パースしたソースコー ドから無駄な処理を分析し、コード最適 化を行う 言語処理系の概要

Slide 8

Slide 8 text

コード生成 ● 抽象構文木を入力とし、ターゲットとな る言語のコードを生成する ● コンパイラでは、この段階で中間コード をネイティブコード(ターゲットのCPUが 解釈できる実行形式のバイナリコード)に 変換する 言語処理系の概要

Slide 9

Slide 9 text

マークダウンテキストを入力とし トークンに分割(字句解析) →ASTに変換(構文解析) →HTMLを生成(コード生成) できるようにする パーサーの構成

Slide 10

Slide 10 text

● 字句の列(トークン)を定義する ● 入力されたテキストをトークンに分割する 字句解析器(Lexer)の実装

Slide 11

Slide 11 text

実装するマークダウンタグ ● 見出し(

~

) ● 太字() ● 斜体() ● 引用() ● リスト(
    ,
  • ) 字句解析器(Lexer)の実装

Slide 12

Slide 12 text

トークンを定義する ● Heading,Bold,Italic,BlockQu otes,Lists の5つのトークン を定義する 字句解析器(Lexer)の実装

Slide 13

Slide 13 text

字句解析(Tokenize)する ● 字句解析は関数lexが担う ● 字句解析のための文字列操作 はイテレータで行う ○ イテレータとは、複数個 の要素の集まり(配列・リ ストなど)から、次の要素 を一つずつ順に取り出す インターフェースのこと 字句解析器(Lexer)の実装

Slide 14

Slide 14 text

fn next(&mut self) -> Option ● nextはイテレータを消費するメソッド ● 呼び出されるたびにイテレータを消費してSome に包まれた一要素を 返し、繰り返しが終わるとNoneを返す ○ next()で入力された文字列を一つずつ取り出し、変数cに格納す る 字句解析器(Lexer)の実装

Slide 15

Slide 15 text

● 見出しタグの判定では、頭文字が#と (半角スペース)で始まる語句を 識別できるようにしたい ● 変数cが#、in_boldがfalse(太字ではない)でin_italicがfalse(斜体で はない)のときにのみ処理するようなパターンマッチングを書く 字句解析器(Lexer)の実装

Slide 16

Slide 16 text

● peekはイテレータを消費する前に、前もって参照を返す(新たなイテ レータPeekableを返す)メソッド ● 行頭に#が連続して出現する時(chars.peek()とSome(&'#')が等しい 時)、一文字ずつ文字列を読み進めながら、levelを1ずつ加算 字句解析器(Lexer)の実装

Slide 17

Slide 17 text

● peekはイテレータを消費する前に、前もって参照を返す(新たなイテ レータPeekableを返す)メソッド ● 行頭に#が連続して出現する時(chars.peek()とSome(&'#')が等しい 時)、一文字ずつ文字列を読み進めながら、levelを1ずつ加算 字句解析器(Lexer)の実装

Slide 18

Slide 18 text

● levelの値に応じて見出しのレベルを判定 ● 適切なToken::Headingをtokensに追加し、見出しをトークン化 字句解析器(Lexer)の実装

Slide 19

Slide 19 text

● 半角スペースの後に続くテキストがTokenの値に正しく解釈されるよ うにしたい ● 現在の文字が半角スペースのときにのみ、charsから文字を取り出す 処理を書く 字句解析器(Lexer)の実装

Slide 20

Slide 20 text

● トークンから抽象構文木(AST)を構築する ● ASTはノードが集まってできた木構造 ○ Heading(見出し)タグは、Heading Level(見出しレベル)ノード とText(文字列)ノードが集まってASTを構築する 構文解析器(Parser)の実装

Slide 21

Slide 21 text

● トークン配列からASTNodeを構築 構文解析器(Parser)の実装

Slide 22

Slide 22 text

● Token::Headingをパースして、AstNode::Headingに変換 構文解析器(Parser)の実装

Slide 23

Slide 23 text

● 構築されたASTをHTMLに変換する ○ AstNode型のスライスを参照するast: &[AstNode]を引数に持 ち、Stringを返す関数generate_htmlを定義 コード生成器(Generator)の実装

Slide 24

Slide 24 text

● パターンマッチング→ASTのノードをhtmlタグにフォーマットし、 result配列に追加する処理を愚直に書く コード生成器(Generator)の実装

Slide 25

Slide 25 text

● 関連関数text_to_tokenで呼び出す レンダリング

Slide 26

Slide 26 text

● wasm-packでビルドする ○ Cargo.tomlで環境設定を行う WASMの生成

Slide 27

Slide 27 text

● lib.rsに#[wasm_bindgen]アトリビュートを付与 WASMの生成

Slide 28

Slide 28 text

● % rustup target add wasm32-unknown-unknownでターゲット アーキテクチャを追加して% wasm-pack buildする ● target/wasm32-unknown-unknown/release に、最適化されたビ ルドバイナリが出力される WASMの生成