Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

2025年のあれこれ

終了済み…

2025年12月のあれこれ

終了済み…

WORD編集長マニフェスト

記事を出す WORD comes back! 序文

(飛ばして良い)

記事を出すWORD comes back!などと書いてみた。

が、かつてWORDがそう記事を出していたことがあっただろうか。いや、ない。
だが、我々は編集部であるという名目においてこの3C212を占拠し活動している。したがって、存在を許されるには記事を書く必要は、ある。

では、記事を書くのは部屋であり続け存在を許されるためのただの手段なのだろうか。いや、違う。
記事を出す過程で日々の生活の中で少しずつあるだろう挑戦や発見が共有されたり、あるいは逆に記事を書こうと思うことが日々に発見をもたらすかもしれない。

WORDは、別にいつもいつも記事のことばかり考えているわけではないけれども、そこに場所がありWORDのおもろい日常があり、たまに記事を書くとおもろい。
そういうふうにしてWORDは、面白く、意義があるようにありたい。
そういうWORDを維持し躍進させていきたいと思う。

マニフェスト要点

記事を出すWORD

  • WORDは記事を出したほうがおもろい!(上参照)
  • 現状、我々が記事を書くのは年に4回(しかもそのうち2回は新歓でありディープな話題を避けるという人もいる)。
    • 少ない
      • ギリギリになって書かなきゃと言い出して1つの号に記事が殺到するというのは良くない
        • 記事の質が書くうえでも赤入れするうえでも下がる
        • 印刷に時間がかかりすぎ、負担が大きい
      • -> 2回くらい増えると良い

民主的で分散的なWORD

  • WORD全体に関わること(例えば記事関連など)は民主的に決定されるべき
  • 編集会議
    • かつてコロナ以前存在した編集会議
      • 週1は多い。月1~2回くらい。
      • 記事を書けるネタがある人がどれくらいいるのかを共有する機会(長大な会議をするというのではない)。
        • 号ごとのスケジューリングができる
  • 分散、冗長化
    • 編集長のみが手段を握っていて単一障害点となってしまう例(印刷など)はマヌケ
      • 編集長含む3人くらいに手段、権限を分散、冗長化し、単一障害点化や負担の過集中を防ぐ
        • たとえば副編集長を置くとか

狂っていても治安は悪くないWORD

  • WORDは変でなんぼですが、
    • 常識的な治安は維持していかなければならない

感想

…2026年、おもろいWORDにしましょう

公開md置き場

Biwa Language

ノベルゲームエンジン biwa のための言語 biwa言語 (biwa language) について記します。

biwa言語の規約 Biwa Language Specification

biwa言語の規約を示します。

なるべく快適に、柔軟でかつ厳密に、ノベルゲームを開発できるように、biwa言語の構文を設計しました。

構文は、各種の規則から構成されます。 biwa言語を使うプログラマ/スクリプタはこれらの構文を守ったソースコードを書かなければなりません。そうでなければコンパイラによってエラーと判断されるはずです。 一方で、biwa言語自体の開発者が開発に取り組んでいるコンパイラが、規則を満たしていない動作をすれば、それは規則違反でありバグです。そういうこともあります。

パッケージとモジュール

biwa言語で記述されたソースコードのパッケージとモジュールについての規則を示します。

パース可能な文法 Syntax

パース可能な文法を示します。

なお、パース可能なだけでは意味論上の文法の規則を必ずしも満たすわけではありません。 biwa言語のソースコードが最も最初に満たすべき規則が parsable syntax ということです。

意味論の規則 Semantics

ソースコードがパース可能であるのを前提として、その上で意味論上の満たさなければならない規則を示します。

名前解決の規則

ユーザが定義可能なあらゆる識別子(型名、関数名、変数名、シーン名など)の名前解決についての規則です。

型の規則

型に関する規則です。

内部のデータ構造と実行の規則

正当だと解釈された(コンパイルが通った)biwa言語のソースコードが、内部でどのようにデータを保持し、実行するかの規則です。

biwa言語を使うプログラマ/スクリプタが守る規則ではなく、biwa言語自体の開発者がそう動くように保証するべき規則です。

意味論 Semantics

名前解決の規則

ユーザが定義可能なあらゆる識別子(型名、関数名、変数名、シーン名など)の名前解決についての規則です。

  • 識別子の名前空間と解決順序
  • visibility の規則

型の規則

型に関する規則です。

パース可能な文法 Syntax

パース可能な文法をBNF1で示す。

なお、パース可能なだけでは意味論上の文法の規約を必ずしも満たすわけではない。

正しいコードの例

import bar::Bar;

fn add(x: Int, y: Int) -> Int {
  x + y
}

struct Foo[T] {
  a: Int,
  b: Bar,
  c: T,
}

impl[T] Foo[T] {
  fn new(b: Bar, c: T) -> Self {
    Self {
      a = 0,
      b = b,
      c = c,
    }
  }
  
  fn set_c(self, c: T) {
    self.c = c;
  }
}

<module>

::= <global-symbol>*

<global-symbol>

::= <import-declaration>
| <global-variable-definition>
| <function-definition>
| <type-definition>
| <implementation-block>
| <scene-definition>

モジュール(拡張子.biwaのファイルがモジュールそのものとなる)のトップレベルに置けるシンボルは、

のみである。

<scene-definition>

::= scene <identifier> <argument-declaration> -> <type-representation> {{ <novel-mode> }}

ノベルゲームのシーンを記述する。

詳しくはノベルモード Novel Modeを参照。

<import-declaration>

::= import <qualified-identifier> (as <identifier>)? ;

他のパッケージやモジュールのシンボルを短い名前で使用できるようにする。

foo::bar::baz() という関数があるとき、

  1. そもそもfoo::bar::baz()のままで使用することが可能である。
  2. import宣言で短縮した名前で使用することが可能である。
    • import foo::bar; としたとき、bar::baz()で使用できる。
    • import foo::bar::baz; としたとき、baz()で使用できる。

<function-definition>

::= fn <identifier> <type-generics-argument-declaration>? <argument-declaration> -> <type-representation> (<block-statement> | <block-expression>)

関数の定義。引数及び戻り値の型は明示する必要がある。

<argument-declaration>

::= ( (<identifier> : <type-representation> ,)* (<identifier> : <type-representation>)? )

<type-definition>

::= <struct-definition>
| <enum-definition>
| <type-alias-definition>

<struct-definition>

::= struct <identifier> <type-generics-argument-declaration> {
(<identifier> : <type-representation> ,)*
(<identifier> : <type-representation>)?
}

構造体の定義。構造体はメンバを定義した型のメンバを保持できる。

struct Point {
  x: Int,
  y: Int,
}

のように構造体Pointを定義したとき、 以下のように初期化でき、メンバにアクセスして使用できる。

let p = Point { x = 1, y = 2, }; // 初期化

p.x // メンバアクセス。 1 が得られる

<global-variable-definition> ::= ("let" | "const") <identifier> (":" <type-representator>)? "=" <expression> ";"
// <literal> が限界かもしれない

<enum-definition> ::= "enum" <identifier> "{" (<identifier> ",")* <identifier>? }"

<interface-definition> ::= "interface" <identifier> "[" <type-generics-argument-list> "]" "{"
    ("fn" <identifier> "(" <argument-declaration-list> ")" "->" <type-representator> ",")*
      ("fn" <identifier> "(" <argument-declaration-list> ")" "->" <type-representator>)?
  "}"



  1. Backus-Naur Form / Backus Normal Form. バッカス・ナウア記法 / バッカス標準記法 とも。 <foo> ::= <bar> の形式で左辺のシンボルが右辺の表現に展開されることを示す。ここでは正規表現記法的な ?, * などの使用を許すように拡張している。

式 Expression

<expression>

::= <if-expression>
| <match-expression>
| <logical-additional-expression>

<if-expression>

::= if <expression> <block-expression>
(else if <block-expression>)*
else <block-expression>

::= “match” “{” ( “=>” “,”)* ( “=>” | “_” “=>” )? “}”

<logical-or-expression>

::= <logical-and-expression>
| <logical-and-expression> || <logical-and-expression>

<logical-and-expression>

::= <relational-expression>
| <relational-expression> && <relational-expression>

<relational-expression>

::= <additive-expression>
| <additive-expression> < <additive-expression>
| <additive-expression> > <additive-expression>
| <additive-expression> <= <additive-expression>
| <additive-expression> >= <additive-expression>
| <additive-expression> == <additive-expression>
| <additive-expression> != <additive-expression>

<additive-expression>

::= <multiplicative-expression>
| <multiplicative-expression> + <multiplicative-expression>
| <multiplicative-expression> - <multiplicative-expression>

<multiplicative-expression>

::= <unary-expression>
| <unary-expression> * <unary-expression>
| <unary-expression> / <unary-expression>
| <unary-expression> % <unary-expression>

<unary-expression>

::= <postfix-expression>
| + <postfix-expression>
| - <postfix-expression>
| ! <postfix-expression>

<postfix-expression>

::= <primary-expression>
| <postfix-expression> <function-calling-argument-list>
| <postfix-expression> . <identifier>
| <postfix-expression> . <identifier> <function-calling-argument-list>

<function-calling-argument-list>

::= ( (<expression> ,)* <expression>? )

<primary-expression>

::= <qualified-identifier>
| <literal>
| ( <expression> )
| <block-expression>

<block-expression>

::= { <statement>* <expression> }

<literal>

::= <integer-literal>
| <floating-literal>
| <boolean-literal>
| <string-literal>
| <struct-literal>
| NONE

<integer-literal>

::= [0-9]+u?
| 0x[0-9a-fA-F]+
| 0b[01]+

<floating-literal>

::= [0-9]+.[0-9]+

<boolean-literal>

::= TRUE
| FALSE

<string-literal>

::= ".*"

文字列リテラルは " で囲んで表す。

行をまたぐことは出来ない。

特殊な文字にはエスケープシーケンスを使用する。

<struct-literal>

::= <\qualified-identifier> {
(<identifier> = <expression> ,)* (<identifier> = <expression>)? }

構造体のリテラル(初期化表現)。

型名の明示する必要がある。

また、すべてのメンバを正しく初期化することが必要ある。

その他のシンボル misc

<qualified-identifier>

::= (package ::)? (<identifier> ::)* <identifier>

修飾された識別子。モジュールやパッケージを越えてシンボルにアクセスする際などに用いられる。

<identifier>

::= [a-zA-Z_][a-zA-Z0-9_]*

識別子(型名や関数名や変数名などユーザが命名するものすべて)はアルファベットかアンダースコアのいずれかから始まる必要があり、それ以降の文字には数字も使用できる。

ノベルモード Novel Mode

ノベルモードは、biwa言語がノベルゲーム開発用言語であるために最も特徴的で重要な文法部分である。

ノベルモードはscene定義により定義されたシーンの、記号{{から始まり、記号}}で始まる行までの間である。

ノベルモードでは、ノベルゲームの最も大きな構成要素がノベルのテキストであることから、ノベルのテキストを直接記述できるように設計されている。 アクション表現に必要な各種コマンドは特殊記号(#, $, @など)により修飾された部分で記述することとなる。

scene scene1(g: MyGame) -> MyGame {{
  // この部分がノベルモード

  // `@`によって、キャラクター`biwa`が会話する
  // (メッセージウィンドウに名前やアイコンを表示する)ことを明示
  // この`こんにちは!`と`わたしは琵琶。`はそのままメッセージウィンドウに表示される
  @biwa
  こんにちは!
  わたしは琵琶。

  // `#`で始まる行は命令を記述できる
  // `${}`は値を埋め込んで出力できる(表示可能な値の型に限る)
  #let se1 = Sound::new("sounds/se1.mp3")
  #play_se(se1)
  #if g.states.got_point > 50 {
    @akane
    @akane.appear_in(0, 0)
    すごいね、${g.states.got_point}ポイントも獲得しているよ!
  } else {
    まだポイントが足りないよ
  }
}}

<nobel-mode>

::= <^> <raw-novel-text> <$>
| <novel-mode-statement>

ノベルモードでは、

  • ノベルテキストそのもの
  • 制御構文やコマンドなどの文

のいずれかを使用できる。後者は文(<statement>)とほとんど同じであるが、あらゆる構文は明示的に改行が示されている箇所以外に改行があってはならない(その中で使われている<expression>についても同様に改行が含まれていてはならないが、それ以外の構文は同じである)。

ここでは、行頭を<^>、行末(改行)を<$>で表すことにする。

<novel-mode-statement>

::= <^> # <expression> <$>

文 Statement

<statement>

::= <block-statement>
| <expression-statement>
| <variable-definition-statement>
| <assignment-statement>
| <if-statement>
| <while-statement>
| <for-statement>
| | |

<block-statement>

::= { <statement>* }

<expression-statement>

::= <expression> ;

<variable-definition-statement>

::= let <identifier> (: <type-representation>)? = <expression> ;

<assignment-statement>

::= <assignable-expression> = <expression> ;

<assignable-expression>

::= <identifier>
| <assignable-expression> . <identifier>
| <assignable-expression> [ <expression> ]

<if-statement>

::= if <expression> <block-statement>
(else if <expression> <block-statement>)*
(else <block-statement>)?

<while-statement>

::= while <expression> <block-statement>

<for-statement>

::= for <identifier> in <expression> <block-statement>

<optional-statement>

::= some <identifier> = <expression> <block-statement> none <block-statement>

検討中。以下のように書けるようにするかもしれない

let opt_v: V? = foo();
some v = opt_v {
  // v を使った処理
  bar(v);
} none {
  // 値がない場合の処理
}

::= “try” “=” “catch”

::= “match” “{” ( “=>” )* (“_” “=>” )? “}”

型 Type

<type-representation>

::= Void
| Int
| Uint
| Float
| Bool
| Char (検討中)
| String
| <qualified-identifier> <type-generics-argument-list>?
| <type-representation> [ ]
| <type-representation> ?
| ( <type-representation> ! <type-representation> )
| ( (<type-representation> ,)* <type-representation>? ) -> <type-representation>

<type-generics-argument-list>

::= [ (<type-representation> ,)* <type-representation>? ]

<type-generics-argument-declaration>

::= [ (<identifier> (: <type-representation>)? ,)* <identifier> (“:” <type-representation>)? ]

型ジェネリクスの型引数宣言。型の定義や関数の定義で使用され、汎用な型について適用可能にする(パラメトリック多相)。

各型引数について、(trait? interface?)の制約を満たす必要を:以降に示せる。

Biwa TODO

  • visibility (pub, pub(package), なし(private))
  • external package
    • metadata
  • novel scene parse

public/index

見えていますか???

silverbulletはただのmdなので、公開するのが単体ではできず困った

  • そもそもsbはメンテ状況が悪い。酷い
  • -> のでmdbook(よくRustのドキュメントで見るやつ)に公開する部分は分けることで誤魔化した
    • mdbookはそこに含まれるmdの一覧をSUMMARY.mdに規定の形式で書く必要がある
      • auto-summary的なツールは存在するもののパースエラーなどをしまくって使い物にならない
      • 仕方ないのでshを書き、ディレクトリ以下をwalkして回っている
      • 注意: public/foo/bar.mdを適切な章立てで公開したければ、public/foo.mdも作ること。でないと雑なshのインデント機構で章立てが壊れる。sortして/を数えた分だけインデントしているだけなので