Dev Study
← Rust で小さなブラウザを作る コース

用語集: Rust で小さなブラウザを作る

このコースに出てくる語を 236 項目、一言ずつ説明しています。レッスンの本文で点線の付いた語をタップしても、同じ説明がその場に出ます。

コマンド

cargoCargo

Rust のビルドとパッケージ管理のコマンドです。Cargo.toml を読んで src/ をまとめてコンパイルします。このコースは外部の依存を使いません。

近いもの: npm

詳しく: プロジェクトの形 — src/ の 20 のモジュールと、1 ファイル版の対応 →

cargo run

src/main.rs をビルドして実行するコマンドです。cargo run -- http://localhost:8000/ のように、-- の後ろがプログラムへの引数になります。

近いもの: npm start

詳しく: 全部つなぐ — main.rs、ローカルサーバー、途中の木を覗くオプション →

cargo test

クレートの中の #[test] を全部コンパイルして実行するコマンドです。参照実装では 78 本のテストが通ります。

近いもの: npm test

詳しく: プロジェクトの形 — src/ の 20 のモジュールと、1 ファイル版の対応 →

python3 -m http.serverhttp.server

Python に同梱の簡易 Web サーバーです。今いるフォルダのファイルを http://localhost:8000/ で配ります。自作ブラウザの相手役に使います。

近いもの: npx serve

詳しく: 全部つなぐ — main.rs、ローカルサーバー、途中の木を覗くオプション →

rustc

Rust のコンパイラです。rustc --edition 2021 -o x file.rs のように 1 ファイルを実行ファイルにします。cargo は内側でこれを呼んでいます。

近いもの: tsc

詳しく: プロジェクトの形 — src/ の 20 のモジュールと、1 ファイル版の対応 →

rustc --test--test

rustc に --test を付けると、main ではなく #[test] の関数を順に走らせる実行ファイルができます。1 ファイル版のテストはこれで動かします。

詳しく: プロジェクトの形 — src/ の 20 のモジュールと、1 ファイル版の対応 →

コマンドのオプション・設定名

--dom--tokens / --layout / --display-list / --headers

tinybrowser の途中結果を表示するオプション群です。--tokens は HTML のトークン、--dom は DOM、--layout は箱の木、--display-list は表示リスト、--headers は HTTP のヘッダーを出します。

詳しく: 全部つなぐ — main.rs、ローカルサーバー、途中の木を覗くオプション →

--editionedition

Rust の言語の版(2015 / 2018 / 2021 / 2024)を選ぶ指定です。文法の細部が違い、サイトの実行環境は 2015、Cargo.toml は 2021 です。

近いもの: tsconfig の target

詳しく: プロジェクトの形 — src/ の 20 のモジュールと、1 ファイル版の対応 →

--file

tinybrowser の起動オプションで、HTTP で取りに行かずローカルの HTML ファイルを読んで描きます。サーバーなしで試せます。

詳しく: 全部つなぐ — main.rs、ローカルサーバー、途中の木を覗くオプション →

ファイル・フォルダ・ファイルの中の項目

Cargo.toml

クレートの設定ファイルです。名前・版・edition・依存を書きます。tinybrowser の [dependencies] は空で、std だけで書いてあります。

近いもの: package.json

詳しく: プロジェクトの形 — src/ の 20 のモジュールと、1 ファイル版の対応 →

modpub mod / mod.rs

モジュールの宣言です。mod url; と書くと src/url.rs(またはフォルダの mod.rs)がそのモジュールになり、pub を付けると外から見えます。

近いもの: ES modules のファイル分割

詳しく: プロジェクトの形 — src/ の 20 のモジュールと、1 ファイル版の対応 →

src/lib.rslib.rs

ライブラリの入口のファイルです。pub mod url; のように、どのモジュールがあるかを並べます。他のファイルはここから辿られます。

近いもの: index.ts

詳しく: プロジェクトの形 — src/ の 20 のモジュールと、1 ファイル版の対応 →

src/main.rsmain.rs

実行ファイルの入口です。コマンドライン引数を読み、lib.rs の部品(url / http / Page)を呼んでつなぎます。

近いもの: bin/cli.ts

詳しく: 全部つなぐ — main.rs、ローカルサーバー、途中の木を覗くオプション →

steps/1 ファイル版

参照実装の、レッスンの段階ごとに 1 ファイルで動く版を置いたフォルダです。src/ のモジュール版と中身は同じで、rustc 1 回で試せます。

詳しく: プロジェクトの形 — src/ の 20 のモジュールと、1 ファイル版の対応 →

Web

authority

URL の「://」の後から、次の「/」か「?」までの host[:port] の部分。URL Standard ではユーザー情報(user:pass@)も含みますが、この実装は扱いません。

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

chunkedchunked 転送符号化 / Transfer-Encoding: chunked

本文を「16 進の長さ CRLF データ CRLF」の塊の列で送る方式。長さ 0 の塊が終わりの印です(RFC 9112 §7.1)。全体の長さが先に分からないときに使われます。

詳しく: レスポンスの分解 — status-line、field-line、そして本文の長さをどう決めるか →

Connection: closeConnection

「この 1 往復が終わったら接続を閉じる」と伝えるヘッダー。これを送ると、サーバーが閉じるまで読めば本文の終わりになるので、受信が単純になります。

詳しく: リクエストの形 — 行末は CRLF、Host は必須、Connection: close で終わりが分かる →

Content-Length

本文のバイト数を書くヘッダー。受け手はこの数だけ読めば本文の終わりが分かります。chunked のときは付きません(付いても無視)。

詳しく: レスポンスの分解 — status-line、field-line、そして本文の長さをどう決めるか →

ECMAScript

JavaScript の言語仕様の正式名(ECMA-262)。文法は生成規則の形で書かれていて、この実装の AST の名前はその非終端記号に合わせてあります。

詳しく: 構文解析と AST — 生成規則 1 つが関数 1 つ(再帰下降) →

GET

HTTP のメソッドの 1 つで「この URL のものを送ってください」という要求。本文は付けません。この実装が送るのは GET だけです。

詳しく: リクエストの形 — 行末は CRLF、Host は必須、Connection: close で終わりが分かる →

Host ヘッダーHost

どのホストへの要求かを書くヘッダー。HTTP/1.1 のリクエストでは必須です(RFC 9112 §3.2)。この実装は既定の 80 以外のときだけ :ポート を付けます。

詳しく: リクエストの形 — 行末は CRLF、Host は必須、Connection: close で終わりが分かる →

HTTP/1.1

このコースが話す HTTP の版。1 行ずつのテキストでやり取りし、構文は RFC 9112、意味は RFC 9110 が定めます。HTTP/2 や 3 はバイナリで、扱いません。

詳しく: リクエストの形 — 行末は CRLF、Host は必須、Connection: close で終わりが分かる →

HTTPSTLS / https

HTTP を TLS(暗号化と相手の確認)の上に乗せたもの。TLS を実装しないので、この実装は https:// を UnsupportedScheme として断ります。

詳しく: 失敗を型にする — UrlError と Result で「どう壊れていたか」を返す →

request-targetorigin-form / request_target

リクエスト行の 2 番目の部分。通常は origin-form と呼ばれるパスと ?クエリをつないだもの(/docs/index.html?q=rust)で、ホストは含みません。

詳しく: リクエストの形 — 行末は CRLF、Host は必須、Connection: close で終わりが分かる →

RFC

インターネットの標準文書の連番。HTTP/1.1 は RFC 9112(構文)と RFC 9110(意味)です。本文の「§」はその中の節番号です。

詳しく: 何を作るか — ブラウザは「変換の列」でできている →

TCP

Transmission Control Protocol。HTTP/1.1 が乗る、順序と到達を保証するバイト列の接続です。接続時の 3 ウェイハンドシェイクは TcpStream::connect の中で起きます。

詳しく: TCP で送って受け取る — 名前解決、接続、タイムアウト、閉じるまで読む →

Transfer-Encoding

本文の送り方(符号化)を書くヘッダー。Content-Length より優先します。この実装は値が chunked のときだけ解け、それ以外は UnsupportedBody にします。

詳しく: レスポンスの分解 — status-line、field-line、そして本文の長さをどう決めるか →

URL

Uniform Resource Locator。http://host:port/path?query#fragment の形の文字列で、どの部品をどう読むかは WHATWG URL Standard が定めます。

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

User-Agent

送り手のソフト名を書くリクエストヘッダーです。この実装は tinybrowser/0.1 と名乗ります。サーバーのログに残る程度で、無くても動きます。

詳しく: リクエストの形 — 行末は CRLF、Host は必須、Connection: close で終わりが分かる →

W3C

CSS の仕様(CSS Syntax Level 3、Selectors Level 4、CSS Cascade Level 4 など)を出している団体。CSS はモジュールごとに Level 番号が付きます。

詳しく: 何を作るか — ブラウザは「変換の列」でできている →

WHATWG

HTML・DOM・URL の各 Standard を書いている団体。仕様は「Living Standard」として常に更新され、版の番号を持ちません。本文で「HTML Standard 13.2.5」とあればこの文書です。

詳しく: 何を作るか — ブラウザは「変換の列」でできている →

クエリquery

URL の「?」より後ろの部分(q=rust&page=2)。サーバーへの追加の指定で、リクエストの request-target にパスと一緒に載せます。

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

スキームscheme

URL の「://」より前の部分(http、https、file など)。どのプロトコルで取りに行くかを表します。この実装は http だけを受け付けます。

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

ステータス行status-line / ステータスコード / reason-phrase / status_code

レスポンスの 1 行目。HTTP-version SP status-code SP reason-phrase の形で、例は HTTP/1.1 200 OK。3 桁の数字がステータスコード、OK が reason-phrase です。

詳しく: レスポンスの分解 — status-line、field-line、そして本文の長さをどう決めるか →

ソケットsocket

OS が用意する通信の口。プログラムはここに書けば相手に届き、読めば相手からのデータが取れます。Rust では TcpStream がその包みです。

近いもの: net.Socket

詳しく: TCP で送って受け取る — 名前解決、接続、タイムアウト、閉じるまで読む →

タイムアウトtimeout / connect_timeout / set_read_timeout

待つ時間の上限。相手が応えないときに永久に止まらないため、接続に 5 秒・読み取りに 10 秒の上限を置いています。

詳しく: TCP で送って受け取る — 名前解決、接続、タイムアウト、閉じるまで読む →

パスpath

URL のホスト(とポート)の後ろ、「/」から「?」までの部分。サーバー上の場所を指し、大文字小文字を区別します。無ければ「/」と見なします。

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

フラグメントfragment

URL の「#」より後ろの部分(#section-2)。ページ内の位置を表すブラウザ側だけの情報で、サーバーには送りません。この実装は読み捨てます。

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

ヘッダーfield-line / field-name / field-value / ヘッダ / header

ステータス行(リクエスト行)の後ろに並ぶ 名前: 値 の行。RFC 9112 は field-line と呼び、名前は大文字小文字を区別しません。空行が来たら本文です。

詳しく: レスポンスの分解 — status-line、field-line、そして本文の長さをどう決めるか →

ポートport

ホストの後ろの「:8000」のような番号で、サーバー側の受け口を選びます。URL に無ければスキームの既定(http は 80)になります。

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

ホストhost

URL の「://」の後の、サーバーの名前か IP アドレス(example.com、localhost)。大文字小文字を区別しないので小文字に揃えます。

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

リクエスト行request-line

リクエストの 1 行目。method SP request-target SP HTTP-version の形で、例は GET /index.html HTTP/1.1 です(RFC 9112 §3)。

詳しく: リクエストの形 — 行末は CRLF、Host は必須、Connection: close で終わりが分かる →

特別なスキームspecial scheme

URL Standard が既定ポートを定めているスキームの組(http は 80、https は 443、ws は 80、wss は 443、ftp は 21、file は無し)。ポート省略時の値の出どころです。

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

本文message-body

ヘッダーの後の空行より後ろ、HTML などの中身の部分。長さの決め方は Transfer-Encoding → Content-Length → 接続が閉じるまで、の順です(RFC 9112 §6.3)。

詳しく: レスポンスの分解 — status-line、field-line、そして本文の長さをどう決めるか →

名前解決DNS / リゾルバ

example.com のような名前を IP アドレスに変えること。DNS(Domain Name System)に問い合わせますが、この実装は OS のリゾルバに任せます(to_socket_addrs)。

近いもの: dns.lookup

詳しく: TCP で送って受け取る — 名前解決、接続、タイムアウト、閉じるまで読む →

略語

ABNF

RFC が構文を書くのに使う記法(RFC 5234)。A = B SP C のように「A は B と空白と C の並び」と読みます。*( ) は 0 回以上の繰り返しです。

詳しく: リクエストの形 — 行末は CRLF、Host は必須、Connection: close で終わりが分かる →

ASCII

英数字と記号の 128 文字の文字集合。タグ名や属性名は ASCII の範囲で小文字に揃えます(to_ascii_lowercase)。文字のキャンバスも ASCII に近い罫線で描きます。

詳しく: 属性の 8 つの状態 — 引用符 3 種類と、値のない属性 →

CRLF

CR(復帰 \r)と LF(改行 \n)の 2 文字の並び。HTTP/1.1 の行末の正式な形で、リクエストの各行はこれで終えます。

詳しく: リクエストの形 — 行末は CRLF、Host は必須、Connection: close で終わりが分かる →

EOF

End Of File。入力の終わり。HTML の字句解析器はどの状態で入力が尽きても最後に EOF トークンを 1 つ出し、構文解析器はそれで閉じ忘れを直します。

詳しく: テストで固める — トークン列を丸ごと比べ、境界と壊れた入力を押さえる →

HTTP

Hypertext Transfer Protocol。ブラウザがサーバーに要求を送り、応答を受け取る手順。このコースではテキスト形式の HTTP/1.1 を使います。

詳しく: リクエストの形 — 行末は CRLF、Host は必須、Connection: close で終わりが分かる →

LF

Line Feed(改行 \n)。HTTP の行末は CRLF が正式ですが、RFC 9112 §2.2 は受け手が LF 単独も行末と認めてよいとしていて、この実装も受け付けます。

詳しく: レスポンスの分解 — status-line、field-line、そして本文の長さをどう決めるか →

OWS

Optional Whitespace。ABNF で「空白かタブが 0 個以上」。field-line の「:」の後ろや値の後ろに入ってよい空白で、受け手は取り除きます。

詳しく: レスポンスの分解 — status-line、field-line、そして本文の長さをどう決めるか →

px

CSS の長さの単位ピクセル。16px は dimension トークンで、数 16 と単位 px に分かれます。この実装は 1 文字の幅を font-size × 0.5 px と見なします。

詳しく: CSS のトークン — 先頭の数文字で種類が決まる →

SP

ABNF での空白 1 文字(0x20)。request-line の method SP request-target SP HTTP-version のように、区切りに使われます。

詳しく: リクエストの形 — 行末は CRLF、Host は必須、Connection: close で終わりが分かる →

UA

User Agent。利用者の代わりにサーバーと話すソフト、つまりブラウザのこと。User-Agent ヘッダーも、ブラウザ既定の UA スタイルシートも、この語から来ています。

詳しく: カスケードと詳細度 — 当たった宣言を (A,B,C) と出現順で並べ、最後が勝つ →

UTF-8

文字をバイト列にする方式。Rust の String は常に UTF-8 なので、受信したバイト列は from_utf8_lossy で変換してから扱います。

詳しく: TCP で送って受け取る — 名前解決、接続、タイムアウト、閉じるまで読む →

Rust

? 演算子?演算子

Result や Option の後ろに付けて、Err / None なら関数からそのまま早期 return し、Ok / Some なら中身を取り出す記法。url::parse や HttpResponse::parse の各段で使っています。

詳しく: 失敗を型にする — UrlError と Result で「どう壊れていたか」を返す →

&str文字列スライス

文字列の一部を借りて指す型。split_once などで切り出した部品は元の文字列の中を指す &str で、持ち主にするには to_string() で String にします。

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

#[cfg(test)]mod tests

テストのビルドのときだけコンパイルする印。各ファイル末尾の #[cfg(test)] mod tests { .. } がテストの置き場で、通常のビルドには含まれません。

詳しく: テストで固める — トークン列を丸ごと比べ、境界と壊れた入力を押さえる →

#[test]

この関数はテストだという印。cargo test や rustc --test で集めて実行され、中で panic(assert の失敗)すると失敗になります。

近いもの: test() / it()

詳しく: 失敗を型にする — UrlError と Result で「どう壊れていたか」を返す →

assert_eq!assert!

左右が == で等しいことを確かめ、違えば両方の値を表示して失敗にするマクロ。トークン列や DOM の形の比較に使います。assert! は条件が true かだけを見ます。

近いもの: expect(a).toEqual(b)

詳しく: テストで固める — トークン列を丸ごと比べ、境界と壊れた入力を押さえる →

BoxBox<Node>

ヒープに置いた値へのポインタ。enum が自分自身を含む(AST の Node が Box<Node> を持つ)ときに、大きさを決めるために必要です。持ち主は 1 つで、Rc と違い数えません。

詳しく: 構文解析と AST — 生成規則 1 つが関数 1 つ(再帰下降) →

clone.clone()

値の複製。Rc に対しては中身を複製せず、同じものを指すポインタをもう 1 つ作って数を増やすだけ(安い)。doc.clone() は DOM 全体のコピーではありません。

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

crateクレート

Rust のコンパイルとパッケージの単位。tinybrowser が 1 つのクレートで、crate::html::dom のようなパスはその根からの道です。外部クレート = 他人のパッケージです。

近いもの: npm パッケージ

詳しく: プロジェクトの形 — src/ の 20 のモジュールと、1 ファイル版の対応 →

derive#[derive

#[derive(Debug, Clone, PartialEq, Eq)] のように書くと、コンパイラがそのトレイトの実装を自動で作ります。Debug で {:?} 表示、PartialEq で == と assert_eq! が使えます。

詳しく: 失敗を型にする — UrlError と Result で「どう壊れていたか」を返す →

enum列挙型

「このどれか 1 つ」を表す型。HtmlToken(StartTag / EndTag / Char / Eof)や State のように、種類ごとに違うデータを持たせられます。

近いもの: 判別可能なユニオン型(discriminated union)

詳しく: 状態機械という読み方 — 1 文字読んで、状態を変えるか、トークンを出すか →

fmt::Displaystd::error::Error

{} で表示できるようにするトレイト。impl fmt::Display for UrlError で、エラーを人が読める文に変えます。std::error::Error はそれに「エラー型」の印を足すトレイト。renderer の Display enum は別物です。

詳しく: 失敗を型にする — UrlError と Result で「どう壊れていたか」を返す →

from_utf8_lossyString::from_utf8_lossy

バイト列を文字列にする関数で、UTF-8 として読めない箇所は U+FFFD(�)に置き換えて進みます。受信した本文で落ちないようにこれを使います。

詳しく: TCP で送って受け取る — 名前解決、接続、タイムアウト、閉じるまで読む →

HashMap

キー → 値 の表。JavaScript の環境(変数名 → 値)を HashMap<String, RuntimeValue> で持ちます。

近いもの: Map<K, V>

詳しく: 評価と環境 — 変数の表を外側へ辿り、関数呼び出しごとに新しい表を作る →

implimpl ブロック

型にメソッドを付けるブロック。impl Url { fn request_target(..) } が自前のメソッド、impl Iterator for X { .. } がトレイトの実装です。

近いもの: class の中のメソッド定義

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

Iteratorimpl Iterator / next()

next() を呼ぶたびに次の値(Some)を返し、尽きたら None を返すトレイト。字句解析器はこれを実装し、for 文や collect() でトークンを取り出せます。

近いもの: イテレータプロトコル(next() が {value, done} を返す)

詳しく: テストで固める — トークン列を丸ごと比べ、境界と壊れた入力を押さえる →

let-else

let Some(x) = 式 else { return .. }; の形。パターンに合えば x を取り出し、合わなければ else で抜けます。Rust 1.65 以降の書き方で、main.rs の引数処理などに出ます。

詳しく: 全部つなぐ — main.rs、ローカルサーバー、途中の木を覗くオプション →

lines()

文字列を行ごとに返すイテレータ。行末の \n だけでなく \r\n も 1 つの行末として扱い、\r を残しません。ヘッダー部を CRLF でも LF でも同じに読めるのはこのためです。

詳しく: レスポンスの分解 — status-line、field-line、そして本文の長さをどう決めるか →

map_err

Result の Err の中身を別の型に変える関数。OS のエラーを HttpError::Network(文字列) に包み直すのに使います。似た形の ok_or / ok_or_else は Option を Result に変えます。

詳しく: TCP で送って受け取る — 名前解決、接続、タイムアウト、閉じるまで読む →

matchmatch 式

enum の種類などで分岐する式。全部の場合を書かないとコンパイルが通りません。状態機械の「状態 × 文字」の表は match を 2 段重ねて書きます。

近いもの: switch に型の絞り込みと網羅チェックが付いたもの

詳しく: 状態機械という読み方 — 1 文字読んで、状態を変えるか、トークンを出すか →

NodeRef

Rc<Node> の別名(type NodeRef = Rc<Node>)。DOM のノードを指す値はすべてこの型で、clone してもノードは複製されず、同じノードを指す参照が増えるだけです。

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

Option

値が有る(Some(値))か無い(None)かを表す enum。query のように「無いこともある」部品や、見つからないかもしれない検索結果に使います。

近いもの: T | null

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

Peekablepeekable / peek

Iterator を包んで、次の値を消費せずに覗く peek() を足したもの。CSS の構文解析器は「次が : か」を見て進むかを決めるので、トークナイザを .peekable() にして使います。

詳しく: CSSOM — ルールは prelude と宣言ブロック、読めないものは捨てて先へ進む →

RcRc::new / strong_count

参照カウント付きのポインタ。clone すると数が 1 増え、全部消えたら中身が解放されます。DOM の子は親と JavaScript の両方から掴まれるので Rc<Node> で持ちます。

近いもの: GC が黙ってやっている「まだ誰か使っているか」を数で持つもの

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

read_to_end

相手が接続を閉じる(EOF)まで読み続けて Vec<u8> に溜める Read のメソッド。Connection: close を送っているので、これだけで本文の終わりまで読めます。

近いもの: socket の data を end まで溜める

詳しく: TCP で送って受け取る — 名前解決、接続、タイムアウト、閉じるまで読む →

RefCellborrow_mut / borrow()

借用の規則をコンパイル時でなく実行時に調べる包み。borrow() で読み、borrow_mut() で書けます。&self のまま子の列を付け外しするために使います。

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

Result

成功(Ok(値))か失敗(Err(理由))のどちらかを表す enum。失敗を例外ではなく戻り値で返し、呼ぶ側に処理を強制します。url::parse は Result<Url, UrlError> を返します。

近いもの: throw / try-catch の代わりに戻り値で返す

詳しく: 失敗を型にする — UrlError と Result で「どう壊れていたか」を返す →

split_oncersplit_once

文字列を区切りの最初の 1 か所で (前, 後) に分け、無ければ None を返す関数。URL を「://」や「?」で切るのに使います。rsplit_once は最後の 1 か所で分けます(host:port 用)。

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

std標準ライブラリ

Rust に同梱の標準ライブラリ。Vec・HashMap・Rc・TcpStream などが入っています。このコースは std 以外のクレートを使いません。

詳しく: プロジェクトの形 — src/ の 20 のモジュールと、1 ファイル版の対応 →

String

持ち主付きで伸び縮みする文字列。&str から to_string() で作れます。Url や Header の各項目はこの型で持ち、中身は常に UTF-8 です。

近いもの: string(TS は 1 種類だが Rust は &str と String の 2 つ)

詳しく: URL の部品 — scheme / host / port / path / query を左から切る →

TcpStreamstd::net::TcpStream

TCP の接続を表す std の型。connect_timeout でつなぎ、write_all で送り、read_to_end で読みます。drop されると接続が閉じます。

近いもの: net.Socket

詳しく: TCP で送って受け取る — 名前解決、接続、タイムアウト、閉じるまで読む →

ToSocketAddrsto_socket_addrs

「ホスト名とポート」から接続先アドレスの列を作るトレイト。("example.com", 80) のような組に実装されていて、呼ぶと OS の名前解決が走ります。

近いもの: dns.lookup

詳しく: TCP で送って受け取る — 名前解決、接続、タイムアウト、閉じるまで読む →

Vec

伸び縮みする配列。属性の列(Vec<Attribute>)、開いている要素のスタック(Vec<NodeRef>、push / pop)、表示リスト(Vec<DisplayItem>)に使います。

近いもの: T[]

詳しく: 挿入モードと開いている要素のスタック — トークンを木に置く場所の決め方 →

VecDeque

両端から出し入れできる待ち行列。字句解析で 1 回の遷移から複数のトークンを出すとき、push_back で溜めて pop_front で順に返します(pending)。

近いもの: push と shift を両方速くした配列

詳しく: 自己終了タグと script の中身 — 「適切な終了タグ」が来るまでは全部文字 →

WeakRc::downgrade / upgrade

数に入らない Rc の弱い参照。upgrade() で生きていれば Some(Rc) が返ります。子 → 親を Weak にすることで、親 ↔ 子の循環参照で解放されなくなるのを防ぎます。

近いもの: WeakRef

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

トレイトtrait

型が「これができる」と約束するメソッドの組。Iterator や fmt::Display がそれで、impl Iterator for HtmlTokenizer のように自分の型に実装します。

近いもの: interface

詳しく: テストで固める — トークン列を丸ごと比べ、境界と壊れた入力を押さえる →

安定ソートsort_by_key / stable sort

並べ替えで、キーが同じ要素の元の順番を保つこと。Vec の sort_by_key は安定なので、詳細度が同じ宣言は出現順のまま残り、カスケードの「後が勝つ」がそのまま実現します。

詳しく: カスケードと詳細度 — 当たった宣言を (A,B,C) と出現順で並べ、最後が勝つ →

循環参照

A が B を、B が A を Rc で持つ形。数が 0 にならず、どちらも解放されません(メモリリーク)。DOM では親 → 子を Rc、子 → 親を Weak にして避けます。

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

所有権

値には持ち主が 1 つあり、持ち主が消えると値も消えるという Rust の決まり。木のように持ち主が複数いる形は、そのままでは書けないので Rc を使います。

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

内部可変性interior mutability

外から見ると不変(&T)なのに中身を書き換えられる仕組み。RefCell や Cell がそれで、Rc の中身を書き換えるには Rc<RefCell<T>> の形が要ります。

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

ブラウザの内部

//netnet/

Chromium の通信ライブラリ(ディレクトリ net/)。URLRequest・HttpNetworkTransaction・HttpCache・ソケットプール・名前解決が入り、Network Service の中で動きます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

adoption agency algorithm

HTML Standard の木構築で、<b><p></b> のような書式要素の入れ違いを直す手順。Blink の HTMLTreeBuilder::CallTheAdoptionAgency() にあります。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

AST抽象構文木

Abstract Syntax Tree。プログラムの構造を木にしたもので、構文解析の出力・評価の入力です。この実装の節の名前(VariableDeclaration、CallExpression など)は ECMAScript の文法に合わせてあります。

近いもの: TypeScript の ts.Node、ESLint のルールが受け取る木

詳しく: 構文解析と AST — 生成規則 1 つが関数 1 つ(再帰下降) →

Blink

Chromium の描画エンジン(HTML・CSS・DOM・レイアウト・描画)。ソースは third_party/blink/renderer/ にあり、core/ が DOM・CSS・レイアウト、platform/ が下回りです。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

blockブロック

display の値の 1 つ。block の箱は行を改めて縦に積まれ、幅は親いっぱい、高さは中身で決まります。p / div / h1 などの UA 既定です。

詳しく: 箱の木 — block・inline・text の 3 種類と、箱にならないもの →

cc::Layercc/

Chromium のコンポジタのライブラリ(ディレクトリ cc/)。メインスレッドの層の木を pending tree → active tree へ commit / activate し、タイルに分けて並列にラスタライズし、フレームを Viz へ送ります。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

Chromium

Google が公開しているブラウザのソース。Chrome や Edge の土台です。描画エンジンは Blink、JS エンジンは V8、通信は //net ディレクトリで、chromium.googlesource.com で読めます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

ComputedStylestyle struct

計算値を入れる構造体(Blink は core/style/computed_style.h、Firefox は layout/style/ComputedStyle.h)。Firefox は関連プロパティを style struct に分け、親子で共有してメモリを節約します。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

ConstraintSpace

LayoutNG で親から子へ渡す制約(使える幅など)。この実装の layout_block() に渡す Cursor の本物版です。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

Cookie

サーバーが Set-Cookie で渡し、ブラウザが次の要求に付ける小さな値。Chromium では Network Service の cookie_monster.cc が持ち、描画プロセスには渡しません。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

CORS

別オリジンへの要求を通すかどうかを、応答ヘッダー(Access-Control-Allow-Origin など)で決める仕組み。Chromium では Network Service の cors_url_loader.cc が見ます。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

CSP

Content Security Policy。ページがどこから script や画像を読み込めるかをヘッダーで制限する仕組み。Blink は content_security_policy.cc、Firefox は nsCSPContext.cpp。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

CSSOM

CSS Object Model。CSS を構文解析して作る木で、スタイルシート → ルール → セレクタと宣言、と並びます。HTML の DOM に当たるものです。

近いもの: document.styleSheets で触れるもの

詳しく: CSSOM — ルールは prelude と宣言ブロック、読めないものは捨てて先へ進む →

cssparserrust-cssparser

Stylo が使う Rust の CSS 字句・構文解析のクレート(third_party/rust/cssparser)。このコースの F 章の Rust コードに最も近い本物です。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

disk_cachesimple cache / blockfile

Chromium の HTTP キャッシュの保存先(net/disk_cache)。Windows は blockfile、Android・ChromeOS・Linux・macOS は 1 エントリ 1 ファイルの simple cache、シークレットはメモリだけ。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

display item表示項目

描画の 1 命令(矩形を塗る・文字を描く)。この実装の DisplayItem と同じ役で、Blink は PaintController に積んで前回分をキャッシュします。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

display: none

その要素と子孫が箱を作らない指定(CSS Display 3)。表示されないだけでなく、レイアウトからも消えます。UA スタイルシートが head や script に付けているので、中身が画面に出ません。

詳しく: 箱の木 — block・inline・text の 3 種類と、箱にならないもの →

DOCTYPE

<!DOCTYPE html> の宣言。本物は initial 挿入モードでこれを見て互換モードを決めますが、この実装は <! から > までを読み捨てます。

詳しく: 挿入モードと開いている要素のスタック — トークンを木に置く場所の決め方 →

Documentdocument

DOM の木の根のノード。自分は要素ではなく、子に <html> を 1 つ持ちます。JavaScript から見える document オブジェクトは、この根を指す窓口です。

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

DOM

Document Object Model。HTML を構文解析して作る木で、要素・テキストなどのノードが親子でつながります。CSS もレイアウトも JavaScript もこの木を見ます(DOM Standard 4.2)。

近いもの: ブラウザで document から触っている木そのもの

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

feedback

V8 が実行中に集める『このオブジェクトはどんな形か、この演算はどんな型か』の記録。これが安定した関数ほど上の段でコンパイルされます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

fetch API

JS から HTTP 要求を出す現行の API(Promise を返す)。Blink は core/fetch/fetch_manager.cc、Firefox は dom/fetch/FetchDriver.cpp。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

frame treensIFrame

Firefox の『描くための木』。各ノードは nsIFrame で、display:none の要素には frame がありません。Blink の LayoutObject の木にあたります。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

Gecko

Firefox の描画エンジン。DOM は dom/、レイアウトは layout/、通信は netwerk/(Necko)、JS は js/src/(SpiderMonkey)にあります。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

getElementByIdget_element_by_id

子孫のうち tree order で最初の、id 属性がその値である要素を返し、無ければ null を返します(DOM Standard)。この実装では Node::get_element_by_id です。

近いもの: document.getElementById そのもの

詳しく: ブラウザ API — document.getElementById と textContent で DOM を書き換え、描き直す →

GPU プロセス

画面への合成と GPU の操作を行う子プロセス。Chromium は Viz、Firefox は WebRender がここで動きます。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

HarfBuzz

文字列をフォントの字形(グリフ)の列に変えて幅を出すライブラリ。Blink も Firefox もこれで文字幅を実測します。この実装の『文字数 × 比率』はその代わりです。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

HTTP キャッシュRFC 9111 / HttpCache / cache2

RFC 9111 に従って応答を保存し、新鮮なうちは通信せず返し、古ければ条件付き要求で確かめるキャッシュ。Chromium は Network Service の HttpCache + disk_cache、Firefox は netwerk/cache2。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

Ignition

V8 のインタプリタ。JS はまずバイトコードにされてここで実行され、その間に型や形の情報(feedback)を集めます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

inlineインライン

display の値の 1 つで初期値。inline の箱と文字は行の中に横に並び、右端で折り返します。a / span などの UA 既定です。

詳しく: 箱の木 — block・inline・text の 3 種類と、箱にならないもの →

LayoutNG

Blink の現行レイアウト。入力(BlockNode + ConstraintSpace)を限定し、出力を書き換え不可の PhysicalFragment の木にして、同じ入力なら前回の結果を再利用します。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

LayoutObject

Blink の『描くための木』のノード(core/layout/layout_object.h)。DOM と計算値から作られ、Firefox の nsIFrame にあたります。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

list of available images利用可能な画像のリスト

HTML Standard が Document ごとに持たせる画像の表。鍵は (絶対 URL, CORS 設定属性のモード, origin)。img の src を更新する手順の最初にここを見ます。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

localStorageIndexedDB

ページがオリジンごとに文字列を保存する API。Blink は modules/storage から、ブラウザ側の dom_storage に書き、Firefox は dom/storage/LocalStorage.cpp。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

Maglev

V8 の 3 段目の最適化コンパイラ。Sparkplug より速いコードを、TurboFan より速く生成します。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

Mojo

Chromium のプロセス間通信(IPC)の仕組み。描画プロセスと Network Service の間で、要求や本文のデータパイプを運びます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

Necko

Firefox の通信部品(ディレクトリ netwerk/)。nsHttpChannel → nsHttpTransaction → nsSocketTransport の順で HTTP を扱い、キャッシュは cache2 です。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

Network Serviceネットワークサービス

Chromium で通信だけを担う別プロセス。描画プロセスは URLLoaderFactory 経由でここに要求を頼みます。落ちても新しいプロセスで再起動されます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

OilpanMember<T> / WeakMember<T>

Blink の C++ オブジェクト用のトレース GC。GarbageCollected<T> を継承し、Member<T>(強)/ WeakMember<T>(弱)で参照し、Trace(Visitor*) で参照を列挙します。この実装の Rc / Weak の代わりです。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

OrinocoScavenger / Mark-Compact / nursery

V8 の GC の名前。新しいオブジェクトを nursery に置いて Scavenger で生き残りだけ移す世代別の設計で、Mark-Compact を並列・増分・並行で行って停止時間を削ります。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

PagePage::load

部品を 1 ページ分つなぐ型(browser.rs)。load で HTML → DOM → <style> から CSSOM → <script> を実行 → 箱の木 → 表示リスト、と順に進めます。

詳しく: 全部つなぐ — main.rs、ローカルサーバー、途中の木を覗くオプション →

PaintChunk

Blink で、同じ座標変換・クリップ・効果を共有する連続した display item のまとまり。これが cc::Layer に変換されます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

parse errorパースエラー

HTML Standard が「ここは誤り」と印を付けた箇所。止まるのではなく、仕様が決めた直し方(無視する・暗黙の要素を作る)で処理を続けます。だから壊れた HTML も表示されます。

詳しく: 壊れた HTML を直す — 閉じ忘れ、迷子の終了タグ、無い html / head / body →

PhysicalFragment

LayoutNG のレイアウト結果。位置と大きさを持つ書き換え不可の箱で、1 要素が複数の fragment になれます(行で折れたときなど)。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

prelude

qualified rule の「{」より前の部分のトークン列。CSS Syntax 3 はここを何と読むか決めておらず、スタイルルールではセレクタとして読み替えます。

詳しく: CSSOM — ルールは prelude と宣言ブロック、読めないものは捨てて先へ進む →

qualified rule修飾ルール / QualifiedRule

p { color: red } のような普通のルール(CSS Syntax 3 §5)。「{」の前の prelude と、「{ }」の中の宣言の列からなります。@media などの at-rule はこれとは別で、この実装は読み捨てます。

詳しく: CSSOM — ルールは prelude と宣言ブロック、読めないものは捨てて先へ進む →

RAWTEXTRCDATA

中身をタグとして読まない要素の状態。仕様では style が RAWTEXT、title と textarea が RCDATA(文字参照は解く)と分かれますが、この実装は script data と同じ 1 つの状態で読みます。

詳しく: 自己終了タグと script の中身 — 「適切な終了タグ」が来るまでは全部文字 →

reconsume再消費 / reconsume_in

状態を切り替えたうえで、今読んだ文字をもう一度(新しい状態で)読み直すこと。仕様の「reconsume in the X state」で、この実装は reconsume フラグで表します。

詳しく: 状態機械という読み方 — 1 文字読んで、状態を変えるか、トークンを出すか →

reflow

Firefox でレイアウトを計算し直すこと。親の制約 ReflowInput を受けて ReflowOutput を返し、dirty ビットが立った部分だけやり直します。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

RuleSet

Blink が照合のためにルールを入れ直す表。各ルールの一番右のセレクタで棚分けし(p.cname は ClassRules の cname)、関係ない棚は見ません。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

script dataScriptData

<script> の中身を読む状態(HTML Standard 13.2.5.4)。「<」が来てもタグにせず文字として出し、</script> という適切な終了タグだけを探します。

詳しく: 自己終了タグと script の中身 — 「適切な終了タグ」が来るまでは全部文字 →

Sparkplug

V8 の 2 段目。バイトコードを素早く機械語に変えるベースラインコンパイラで、Ignition と最適化コンパイラの間を埋めます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

SpiderMonkey

Firefox の JavaScript エンジン(js/src/)。Interpreter → Baseline(インラインキャッシュ付き)→ WarpMonkey の段階と、世代別・増分の GC を持ちます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

StyleResolverStyleCascade / SelectorChecker

Blink で 1 要素の計算値を作る起点(StyleResolver::ResolveStyle)。候補を集める ElementRuleCollector、当たりを見る SelectorChecker、決着させる StyleCascade を呼びます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

Styloservo/components/style

Firefox 57 以降のスタイルシステム。Servo 由来の Rust で書かれ(servo/components/style)、cssparser で解析し、rayon で木を並列に走査します。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

textContenttext_content / set_text_content

読むと子孫のテキストをつないだ文字列、書くと子を全部外して新しい Text ノード 1 つに置き換えます(DOM Standard の string replace all)。タグは解釈しません。

近いもの: 同名の DOM プロパティ。innerHTML と違いタグを解釈しない

詳しく: ブラウザ API — document.getElementById と textContent で DOM を書き換え、描き直す →

tree order木の順

DOM Standard が定める木の並び順。深さ優先で、親を見てから子を順に見ます(先行順)。getElementById が「最初に見つかった要素」を返すときの「最初」はこの順です。

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

TurboFan

V8 の最上位の最適化コンパイラ。安定した feedback をもとに推測的に最適化し、外れたら前の段へ戻します(deoptimization)。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

UA スタイルシートUA stylesheet / user agent stylesheet / ブラウザ既定のスタイル

ブラウザ(UA)が最初から持っている既定のスタイル。h1 を大きく、a を青い下線に、head を display: none に、など。HTML Standard 15 Rendering に期待される内容があり、作者のスタイルはこれに勝ちます。

詳しく: カスケードと詳細度 — 当たった宣言を (A,B,C) と出現順で並べ、最後が勝つ →

update the rendering

イベントループの中で、必要ならスタイル → レイアウト → 描画をやり直す手順。この実装の Page::load() の後半を、本物は毎フレーム必要な段から回します。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

V8

Chromium(と Node.js)の JavaScript エンジン。字句・構文解析のあとバイトコードにし、Ignition → Sparkplug → Maglev → TurboFan の順に速いコードへ段階的にコンパイルします。

近いもの: Node.js の中身も V8

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

validator.nuhtmlparser

Java で書かれた HTML5 パーサー(htmlparser)。Firefox の nsHtml5Tokenizer.cpp / nsHtml5TreeBuilder.cpp はこれを機械翻訳した C++ です。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

Viz

Chromium の表示コンポジタ(components/viz)。GPU プロセスで動き、各クライアントの CompositorFrame を 1 枚に合成して画面に出します。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

void 要素void element / void elements / VOID_ELEMENTS

終了タグを持たない要素(HTML Standard 13.1.2)。br, img, input, meta, link, hr など 13 種で、開始タグを読んだらすぐスタックから下ろし、子を持ちません。

詳しく: 壊れた HTML を直す — 閉じ忘れ、迷子の終了タグ、無い html / head / body →

WarpMonkeyBaseline / インラインキャッシュ

SpiderMonkey の最適化 JIT(IonMonkey の後継)。Baseline のインラインキャッシュで観測したデータに合わせて特化したコードを作ります。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

Web IDLwebidl

ブラウザ API の形(document.getElementById の引数と戻り値など)を書く定義言語。Blink と Firefox はこの .idl / .webidl から JS と C++ をつなぐコードを生成します。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

WebRender

Firefox の描画器。Rust で書かれ、GPU プロセスで表示リストを Scene → Frame → GPU 命令に変えて描きます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

Windowwindow

本物のブラウザで、document や console をぶら下げているグローバルオブジェクト。この実装には無く、グローバルの環境に document と console を直接置いています。

詳しく: ブラウザ API — document.getElementById と textContent で DOM を書き換え、描き直す →

WPTWeb Platform Tests

Web Platform Tests。ブラウザが共通で走らせるテスト集。HTML パーサーの入力と期待する木の組は html/syntax/parsing に入っています。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

XMLHttpRequestXHR

JS から HTTP 要求を出す古い API。send() は通信を並行して始めてすぐ戻り、応答はタスクとして後から届き、readystatechange → load → loadend の順に発火します。

近いもの: fetch() の前身

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

イベントループ

HTML Standard が決めた『タスクを 1 つ選んで実行し、マイクロタスクを片付け、必要なら描画を更新する』の繰り返し。setTimeout・XHR の応答・クリックはみなタスクとして並びます。

近いもの: Node.js のイベントループと同じ考え

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

インタプリタinterpreter

プログラムを機械語に変換せず、AST をその場で辿って実行するもの。この実装の JsRuntime がそれで、本物の V8 のような JIT コンパイルはしません。

近いもの: Node.js(V8)が JS を実行する役

詳しく: 評価と環境 — 変数の表を外側へ辿り、関数呼び出しごとに新しい表を作る →

オリジン同一オリジン

(scheme, host, port) の組。同一オリジンかどうかが、JS が別のページのデータを読めるかの基本単位です。Chromium は url::Origin、Firefox は BasePrincipal。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

カスケードcascade

同じプロパティに複数の宣言が当たるとき、1 つを選ぶ手順(CSS Cascade 4 §6)。出所(UA か作者か)→ 詳細度 → 出現順の順で比べ、最後に残った宣言が勝ちます。

詳しく: カスケードと詳細度 — 当たった宣言を (A,B,C) と出現順で並べ、最後が勝つ →

キャンバスrender_ascii

表示リストを描き込む先。この実装はウィンドウを持たないので、1 セル = 8×24px の文字の格子に描き(背景は ░、文字はそのまま)、標準出力に出します。

詳しく: 表示リストと描画 — 「何をどこに描くか」の命令列にしてから描く →

クロージャclosure

JS では、関数が定義されたときの環境を閉じ込めて持つこと。呼ばれると「定義された場所の外側」を辿れるので、外の変数が読めます。Rust では |x| x + 1 のような無名関数を指し、こちらも周りの変数を取り込めます。

詳しく: 評価と環境 — 変数の表を外側へ辿り、関数呼び出しごとに新しい表を作る →

サイクルコレクタcycle collector

Firefox が DOM の循環参照を回収する仕組み(xpcom/base/nsCycleCollector.cpp)。参照カウントでは消えない輪を見つけて解きます。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

サイト分離Site Isolation / Fission / eTLD+1

Chromium で描画プロセスを 1 サイト(scheme + eTLD+1)に固定し、ブラウザプロセスが IPC を検査し、ネットワーク側で別オリジンの読み取りを遮る(CORB / ORB)仕組み。Firefox では Fission。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

サンドボックス

描画プロセスの権限を落として、乗っ取られてもファイルやネットワークに直接触れないようにする OS の仕組みの利用。Chromium の docs/design/sandbox.md。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

スコープチェーンscope chain

変数を探すとき、今の環境に無ければ外側の環境へ、さらにその外側へと辿っていく鎖。どこにも無ければ ReferenceError になります。

近いもの: Scope パネルの Local → Closure → Global

詳しく: 評価と環境 — 変数の表を外側へ辿り、関数呼び出しごとに新しい表を作る →

スタイルシートStyleSheet / stylesheet

CSS のルールを出現順に並べたもの。この実装は DOM の <style> の中身を全部集めて 1 つの StyleSheet にします。外部ファイル(<link>)は読みません。

詳しく: CSSOM — ルールは prelude と宣言ブロック、読めないものは捨てて先へ進む →

セレクタselector / Selector

ルールをどの要素に当てるかの条件。この実装は型セレクタ(p)・クラス(.note)・ID(#main)・全称(*)の 4 つの単純セレクタだけで、div p のような組み合わせは Unsupported として何にも当てません。

近いもの: querySelector に渡す文字列

詳しく: CSSOM — ルールは prelude と宣言ブロック、読めないものは捨てて先へ進む →

タスクキュータスク / TaskType / task source

イベントループが取り出す仕事の列。task source(通信、タイマー、DOM 操作など)ごとに分かれ、Blink では TaskType を付けてフレームのタスクランナーに積みます。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

テキストノードText ノード / 文字ノード

タグの間の文字列を持つノード。子は持ちません。字句解析が 1 文字ずつ出した Char トークンを、構文解析でまとめて 1 つの Text にします。

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

トークンtoken

字句解析の出力の 1 単位。HTML では開始タグ・終了タグ・文字(1 文字ずつ)・EOF、CSS では ident や dimension、JS では識別子や数値などです。

詳しく: 状態機械という読み方 — 1 文字読んで、状態を変えるか、トークンを出すか →

ノードnode / Node

DOM の木の 1 つの点。親(parent)と子の順序付きの列(children)を持ちます。この実装の種類は Document・Element・Text の 3 つで、Rust では Node 型です。JS の AST にも同名の Node 型があります。

近いもの: lib.dom.d.ts の Node

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

バイトコード

ソースと機械語の中間の命令列。V8 も SpiderMonkey も AST を直接歩かず、まずこれに変換して実行します。この実装は AST を歩く段で止めています。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

バインディングbindings

JS のオブジェクトと C++ の DOM オブジェクトをつなぐ生成コード(Blink は bindings/、Firefox は dom/bindings/Codegen.py)。この実装の ConsoleLog / GetElementById を手書きで 2 本だけ書いたものにあたります。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

ビューポートviewport

ページを表示する領域。本物はウィンドウの中身の大きさで、この実装は幅 640px の定数(VIEWPORT_WIDTH)です。body の箱の幅はこれになります。

近いもの: @media (max-width) が見る幅

詳しく: 位置と大きさ — block は縦に積み、inline は横に並べ、右端で折り返す →

ブラウザ APIWeb API

JavaScript から見える、ブラウザが用意した道具。この実装にあるのは document.getElementById・要素の textContent・console.log だけで、呼ばれると Rust 側の DOM を読み書きします。

詳しく: ブラウザ API — document.getElementById と textContent で DOM を書き換え、描き直す →

ブラウザプロセスparent プロセス

UI・タブ・ナビゲーション・Cookie を持つ親のプロセス(Firefox では parent プロセス)。子プロセスを起こし、その IPC を検査します。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

プロパティproperty

CSS では宣言の名前の側。この実装が扱うのは display・color・background-color・font-size・text-decoration・width・height の 7 つ。JS では textContent のようなオブジェクトの項目を指します。

詳しく: CSSOM — ルールは prelude と宣言ブロック、読めないものは捨てて先へ進む →

マイクロタスク

Promise の then などが積まれる小さな仕事の列。タスク 1 つが終わるたびに全部片付けられ、次のタスクより先に動きます。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

メインスレッド

描画プロセスの中で JS の実行・DOM・CSS・レイアウトを行う 1 本のスレッド。Blink の文書は「重要なことの大半がここで起きる」と書いています。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

メモリキャッシュMemoryCache

描画プロセスが持つ、画像・script・CSS を URL を鍵に保持する表(Blink の MemoryCache、Firefox の imgLoader の表)。同じページで同じ URL を 2 度取らないための層です。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

ラスタライズ

描画命令(display item)を実際の画素に変えること。この実装では render_ascii() が文字のマス目に対して行っています。本物はタイル単位で GPU やワーカースレッドで行います。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

ラッパーwrapper

C++ の DOM オブジェクトを JS から見せるための JS オブジェクト。寿命は JS エンジンの GC が管理します。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

レンダリングレンダラ / renderer

DOM と CSSOM から画面の見た目を作る工程の全体。計算値を決め(style)、箱の位置と大きさを決め(layout)、描く(paint)の 3 段で、この実装の renderer モジュールがそれです。

詳しく: 何を作るか — ブラウザは「変換の列」でできている →

開いている要素のスタックstack of open elements / open_elements

開始タグが来て、まだ終了タグが来ていない要素を積んだ列(HTML Standard 13.2.4.2)。一番上が「今の要素」で、新しい要素はその子になります。終了タグで下ろします。

詳しく: 挿入モードと開いている要素のスタック — トークンを木に置く場所の決め方 →

巻き上げhoisting / ホイスティング

function 宣言が、書かれた位置より前でも呼べること。ブロックの実行前に先に定義されるためです。この実装は関数宣言だけを巻き上げ、var の巻き上げはしません。

詳しく: 評価と環境 — 変数の表を外側へ辿り、関数呼び出しごとに新しい表を作る →

環境Environment / EnvRef / environment

変数名 → 値 の表と、外側の環境への参照を持つもの(ECMAScript の Environment Record)。関数を呼ぶたびに新しく作られ、この実装では Environment 型を Rc<RefCell<..>> で共有します。

近いもの: devtools の Scope パネル

詳しく: 評価と環境 — 変数の表を外側へ辿り、関数呼び出しごとに新しい表を作る →

空白の折りたたみcollapse_whitespace

テキストの中の連続する空白・改行を 1 つの空白にまとめること(CSS Text の white-space: normal の挙動)。HTML の字下げが画面に出ないのはこのためです。

詳しく: 箱の木 — block・inline・text の 3 種類と、箱にならないもの →

継承inherit / 継承値

宣言が無いプロパティを、親要素の計算値で埋めること(CSS Cascade 4 §7.1)。color や font-size は継承し、background-color は継承しません。実装は text-decoration も単純化して継承扱いです。

詳しく: 継承と初期値 — 宣言が無いとき、値はどこから来るか →

計算値computed value

指定値を、プロパティごとの決まりで解決した値(CSS Cascade 4 §4.2)。font-size の large を 18px にするなど。継承で子に渡るのはこの値で、この実装では ComputedStyle 型です。

詳しく: 継承と初期値 — 宣言が無いとき、値はどこから来るか →

構文解析パーサ / パーサー / 構文解析器 / parser

トークンの列から木(HTML なら DOM、CSS なら CSSOM、JS なら AST)を組み立てる段階。壊れた入力でも止まらず、仕様が決めた直し方で続けます。

近いもの: tsc の parser

詳しく: 挿入モードと開いている要素のスタック — トークンを木に置く場所の決め方 →

左結合右結合

同じ演算子が並んだときのまとめ方。左結合は 1 - 2 - 3 = (1 - 2) - 3(加減算)、右結合は a = b = 1 を a = (b = 1) と読みます(代入)。この実装はループと再帰で書き分けます。

詳しく: 構文解析と AST — 生成規則 1 つが関数 1 つ(再帰下降) →

再レイアウトrelayout / リフロー

JavaScript が DOM を書き換えた後、箱の木と表示リストを作り直すこと。textContent への代入で起き、この実装では Page::relayout が DOM と CSSOM から全部作り直します。

詳しく: ブラウザ API — document.getElementById と textContent で DOM を書き換え、描き直す →

再帰下降recursive descent / 再帰下降構文解析

生成規則 1 つに関数 1 つを対応させ、関数が互いを呼び合って木を作る構文解析の書き方。左再帰(A : A + B)はそのままだと無限に呼ぶので、ループに書き換えます。

詳しく: 構文解析と AST — 生成規則 1 つが関数 1 つ(再帰下降) →

作者スタイル作者の宣言 / 作者スタイルシート

ページを書いた人が <style> などで指定したスタイル。カスケードの出所の区分で、UA スタイルシートより優先されます(!important を除く。この実装は扱いません)。

詳しく: カスケードと詳細度 — 当たった宣言を (A,B,C) と出現順で並べ、最後が勝つ →

指定値specified value

カスケードの結果その要素に選ばれた値(無ければ継承値か初期値)。CSS Cascade 4 §4.1。「作者がこの要素に意図した値」と考えると分かりやすいです。

詳しく: 継承と初期値 — 宣言が無いとき、値はどこから来るか →

字句解析トークナイザ / 字句解析器 / トークン化 / tokenizer / lexer

文字の列を意味のある単位(トークン)に切り分ける段階。HTML では HTML Standard 13.2.5 の状態機械、CSS と JavaScript では先頭の文字で種類を決めて読みます。

近いもの: tsc の scanner

詳しく: 状態機械という読み方 — 1 文字読んで、状態を変えるか、トークンを出すか →

自己終了タグself-closing / self_closing

<br/> のように「/>」で閉じた開始タグ。HTML Standard では void 要素以外に付けた「/」は無視されます(parse error)。この実装は「/」があれば要素を閉じる扱いにしていて、仕様より単純です。

詳しく: 自己終了タグと script の中身 — 「適切な終了タグ」が来るまでは全部文字 →

自動セミコロン挿入ASI

文末の「;」が無くても、改行などから補って読む ECMAScript の規則。この実装は「; があれば読む、無くても進む」というごく粗い代用です。

詳しく: 構文解析と AST — 生成規則 1 つが関数 1 つ(再帰下降) →

識別子identifier / Identifier

変数名・関数名・プロパティ名として使える名前(document、getElementById)。英字・_・$ で始まり、英数字が続きます。予約語は識別子になれません。

詳しく: JavaScript の字句解析 — 識別子と予約語、数値、文字列、コメント →

出現順order of appearance

カスケードの最後の決め手。詳細度まで同じなら、スタイルシートの中で後に書かれた宣言が勝ちます。この実装では rules の添字で表し、安定ソートで順を保ちます。

詳しく: カスケードと詳細度 — 当たった宣言を (A,B,C) と出現順で並べ、最後が勝つ →

初期値initial value

宣言も継承も無いときのプロパティの値で、プロパティごとに仕様が定めます(CSS Cascade 4 §7.2)。display は inline、background-color は transparent、font-size は 16px(medium)。

詳しく: 継承と初期値 — 宣言が無いとき、値はどこから来るか →

詳細度specificity

セレクタの強さを (A, B, C) の 3 つ組で表したもの(Selectors 4 §17)。A は ID、B はクラス、C は型セレクタの数で、左から順に比べます。全称は (0,0,0) です。

近いもの: devtools の Styles で取り消し線が付く理由

詳しく: カスケードと詳細度 — 当たった宣言を (A,B,C) と出現順で並べ、最後が勝つ →

条件付き要求If-None-Match / ETag / 304

『手元の版が古くなければ本文は要らない』と伝える要求。If-None-Match(ETag)や If-Modified-Since を付け、304 Not Modified なら保存済みの本文を使います。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

状態State

状態機械が「今どこにいるか」を表す値。Data(タグの外)、TagOpen(< の直後)、TagName などで、名前は HTML Standard 13.2.5 の節の名前に合わせてあります。

詳しく: 状態機械という読み方 — 1 文字読んで、状態を変えるか、トークンを出すか →

状態機械state machine

「今の状態」と「読んだ 1 文字」から次の状態と動作を決める仕組み。HTML Standard 13.2.5 は字句解析をこの形で定め、仕様は 80 状態、この実装は 17 + 1 状態です。

近いもの: reducer(状態 + 入力 → 次の状態)

詳しく: 状態機械という読み方 — 1 文字読んで、状態を変えるか、トークンを出すか →

新鮮さfreshness / max-age / Expires

キャッシュした応答をまだ使ってよいかの判断。s-maxage → max-age → Expires − Date → ヒューリスティックの順で寿命を決め、現在の年齢と比べます(RFC 9111 §4.2)。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

世代別 GC世代別

『ほとんどのオブジェクトはすぐ死ぬ』前提で、新しい世代を頻繁に小さく回収し、生き残ったものだけ古い世代へ移す GC の設計。V8 と SpiderMonkey が採用しています。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

生成規則production / 文法規則

文法の 1 行。「Statement : VariableStatement | ReturnStatement | ...」のように、左の記号が右のどんな並びで作られるかを書きます。ECMAScript の仕様はこの形で書かれています。

詳しく: 構文解析と AST — 生成規則 1 つが関数 1 つ(再帰下降) →

折り返し

行の右端(箱の幅)を超える文字を次の行へ送ること。この実装は 1 文字の幅を font-size × 0.5 として、入らなくなったら行を改めます。単語の区切りは見ません。

詳しく: 位置と大きさ — block は縦に積み、inline は横に並べ、右端で折り返す →

先読みspeculative HTML parsing / HTMLPreloadScanner / プリロードスキャナ

HTML パーサーが script 待ちで止まっている間に、先の img や link を別に走査して取りに行く仕組み。仕様は speculative HTML parsing、Blink は HTMLPreloadScanner、Firefox は nsHtml5SpeculativeLoad。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

宣言declaration / Declaration

CSS では color: red のような プロパティ: 値 の 1 組(CSS Syntax 3 §5)。「:」が無いなど読めない宣言は捨てて次へ進みます。JS の「変数宣言・関数宣言」は別の意味で、var や function の文のことです。

詳しく: CSSOM — ルールは prelude と宣言ブロック、読めないものは捨てて先へ進む →

挿入モードinsertion mode / InsertionMode

HTML の構文解析器が「今どこを読んでいるか」を表す状態(HTML Standard 13.2.4.1)。before html → in head → in body と進み、同じトークンでもモードで処理が変わります。仕様は 23 個、実装は 9 個。

詳しく: 挿入モードと開いている要素のスタック — トークンを木に置く場所の決め方 →

属性attribute / Attribute

開始タグに付く 名前=値 の組(href="/x")。値は二重引用符・単一引用符・引用符なしの 3 通りで書け、値なし(disabled)も許されます。名前は小文字に揃えます。

詳しく: 属性の 8 つの状態 — 引用符 3 種類と、値のない属性 →

遅延解析lazy parsing / preparser

まだ呼ばれない関数の中身を本解析せず、構文の確認だけで済ませる手法。V8 の preparser、SpiderMonkey の lazy parsing。起動を速くします。

詳しく: 本物のブラウザではどこにあたるか — Chromium と Firefox の部品との対応表 →

通常フローnormal flow

float も position も無いときの、箱の並べ方の基本(CSS 2 の visual formatting model)。block は縦に積み、inline は横に並べて折り返す。この実装が扱うのはこれだけです。

詳しく: 位置と大きさ — block は縦に積み、inline は横に並べ、右端で折り返す →

適切な終了タグappropriate end tag

script data の中で見つけた終了タグが、最後に出した開始タグと同じ名前であること。これが来たときだけ script の中身が終わり、</div> などは文字のままです。

詳しく: 自己終了タグと script の中身 — 「適切な終了タグ」が来るまでは全部文字 →

箱ボックス / box

レイアウトの単位。要素やテキストから作られ、位置(x, y)と大きさ(width, height)を持ちます。CSS Display 3 の box。この実装では LayoutBox 型です。

詳しく: 箱の木 — block・inline・text の 3 種類と、箱にならないもの →

箱の木box tree / LayoutBox / レイアウトツリー

DOM と計算値から作る、箱の親子関係の木(CSS Display 3)。display: none の要素は子孫ごと箱を作らないので、DOM より小さくなります。

詳しく: 箱の木 — block・inline・text の 3 種類と、箱にならないもの →

表示リストdisplay list / DisplayItem

「どこに何を描くか」の命令の列。箱の木を辿って、背景の四角(Rect)と 1 行分の文字(Text)を順に並べたものです。本物もレイアウト結果を一度この形にしてから GPU に渡します。

近いもの: Canvas の fillRect / fillText の呼び出し列

詳しく: 表示リストと描画 — 「何をどこに描くか」の命令列にしてから描く →

評価evaluate / eval

AST の節を根から辿って値を計算すること。1 + 2 の節なら左右を評価して足し、f(x) なら f を評価して呼びます。この実装では JsRuntime::eval です。

詳しく: 評価と環境 — 変数の表を外側へ辿り、関数呼び出しごとに新しい表を作る →

描画ペイント / paint

箱の木から表示リストを作り、画面(この実装では文字のキャンバス)に描く段階。親の背景を先に、文字を後に描くので、後のものが上に重なります。

詳しく: 表示リストと描画 — 「何をどこに描くか」の命令列にしてから描く →

描画プロセスcontent プロセス / レンダラープロセス

Blink / Gecko と JS エンジンが動く子プロセス(Chromium は renderer、Firefox は content)。サンドボックスの中で、通信も GPU も別プロセスへ頼みます。

詳しく: 作っていない機能は本物のどこで動いているか — 通信・キャッシュ・XHR・時間・メモリ・保存・安全 →

予約語キーワード / keyword / Keyword

言語が意味を決めている語で、変数名に使えないもの。この実装は var let const function return の 5 つを Keyword トークンにします(本物の一覧はもっと長い)。

詳しく: JavaScript の字句解析 — 識別子と予約語、数値、文字列、コメント →

要素element / Element

<p> や <a> のようなタグから作られるノード。タグ名と属性の列を持ち、子を持てます。この実装では NodeKind::Element(Element) で表します。

詳しく: ノードを Rust で持つ — 親は Weak、子は Rc、付け外しは RefCell →

その他

tinybrowser

このコースの参照実装のクレート名。url / http / html / css / renderer / js / browser の 7 モジュールからなり、cargo test で 78 本のテストが通ります。

詳しく: 作るもの・作らないもの — 本物との差を先に知っておく →

Wandbox

サイトのサンプルの「実行」ボタンが使うオンラインの実行環境。Rust 1.82・edition 2015 で動くので、サンプルはその範囲の文法で書いてあります。ネットワークに出るものは実行できません。

詳しく: 作るもの・作らないもの — 本物との差を先に知っておく →