From 5d5367ed00c22cc194b8a2411b2b4b828751003b Mon Sep 17 00:00:00 2001
From: nsfisis 本日 PHP カンファレンス沖縄 2022 が開催された (らしい)。 カンファレンスには参加できなかったものの、懇親会の LT で出題されたコードゴルフの問題が Twitter に流れてきたので、解いてみた。 ツイート: https://twitter.com/m3m0r7/status/1563397620231712772 ツイート: https://twitter.com/m3m0r7/status/1563397620231712772 細かいレギュレーションは不明だったので、勝手に定めた。 書いたものがこちら: しめて 123 バイトとなった (末尾改行を含めずにカウント)。 しめて 123 バイトとなった (末尾改行を含めずにカウント)。 こちらは改行とスペースを追加したバージョン: 割と多くの言語のゴルフで使えるテクニック。 こんなものを作った。 コマンドライン引数として渡した文字列をターミナルに大きく表示する。 リポジトリはこちら: https://github.com/nsfisis/term-banner リポジトリはこちら: https://github.com/nsfisis/PHPerKaigi2022-tokens ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。 この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。 この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。 まず目につくのは大量の絵文字だろう。
@@ -323,18 +323,18 @@ Brainf*ck とは、難解プログラミング言語のひとつであり、こ
今回は、PHP 8.1 から追加された、 ソースコードのライセンスを示したこの部分だが、 完全に合法な PHP のコードである。
+ 完全に合法な PHP のコードである。
ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。
PHP では、型変換を利用することで任意の整数を作り出すことができる。 ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。 さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。
+ さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。
トークンを得るためには、ソースコードを読み、定数 ここでは、私の想定解を解説する。 まずはソースコードを読んでいく。 数値からなる まずは排他的論理和 (xor) を取り、 二進数に変換して、 0 を空白に、1 を 5文字ごとに区切ったあと、改行で結合している。 数値からなる まずは排他的論理和 (xor) を取り、 二進数に変換して、 0 を空白に、1 を 5文字ごとに区切ったあと、改行で結合している。 次に、ソースコードに書いてあるヒントを読んでいく。 ここまでわかれば、あと一歩で解ける。すなわち、 なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。 この一連の変換に対する逆変換を考えると、次のようになる。 これを実行すると、 なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。 この一連の変換に対する逆変換を考えると、次のようになる。 これを実行すると、 ソースコードはこちら。 コメントにもあるとおり、次のようにして実行すれば答えがでてくる。 実際にはもう少しパイプで繋げなければならない。 コメントにもあるとおり、次のようにして実行すれば答えがでてくる。 実際にはもう少しパイプで繋げなければならない。 コメントにもあるとおり、これは quine (風) のプログラムになっている。
@@ -522,27 +522,27 @@ Quine とは、自分のソースコードをそっくりそのまま出力す
Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。 では、普段単に では、普段単に 前提知識: 一般的なコンパイラの構造、用語。 大雑把な構造としては、 165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。 これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、 これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、 All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin. とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。 関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。
+ 関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。
なお、 重要なのは、これが 動作がわかったところで、例として次のコードを考える。 ここで ここで Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。 使われることは稀だが、Ruby では このキーワードが現れうる場所はいくつかあり、 このキーワードが現れうる場所はいくつかあり、 普通 Ruby のコードで 次のような構文エラーが出力される。 次のような構文エラーが出力される。 二つ目のメッセージは無視して一つ目を読むと、 ポイントは改行が 無事 Hello, World! と出力されるようになった。 無事 Hello, World! と出力されるようになった。 なぜ Ruby の場合、プログラマーが書きやすいよう改行でもって ここで、 これにより、 ところで、 ところで、
+
スライド: https://speakerdeck.com/memory1994/php-conference-okinawa-2022-extra?slide=3解
[<?php $n=$argv[1];foreach([1e4,5e3,2e3,1e3,500,100,50,10,5,1]as$x)for(;$n>=$x;$n-=$x)$r[]=$x;echo implode(', ',$r??[]);?>]
-[<?php $n=$argv[1];foreach([1e4,5e3,2e3,1e3,500,100,50,10,5,1]as$x)for(;$n>=$x;$n-=$x)$r[]=$x;echo implode(', ',$r??[]);?>]
+[<?php
-
-$n = $argv[1];
-foreach ([1e4, 5e3, 2e3, 1e3, 500, 100, 50, 10, 5, 1] as $x)
- for (; $n >= $x; $n -= $x)
- $r[] = $x;
-echo implode(', ', $r ?? []);
-
-?>]
-使用したテクニック
+[<?php
+
+$n = $argv[1];
+foreach ([1e4, 5e3, 2e3, 1e3, 500, 100, 50, 10, 5, 1] as $x)
+ for (; $n >= $x; $n -= $x)
+ $r[] = $x;
+echo implode(', ', $r ?? []);
+
+?>]
+使用したテクニック
指数表記
e を用いた指数表記で、大きな数を短く表す。このコードでは 10000、5000、2000、1000 を指数表記している。foreach や for の中身を1つの文に
@@ -146,7 +146,7 @@ $n = $argv[1https://blog.nsfisis.dev/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/
$ term-banner 'Hello, World!' 'こんにちは、' '世界!'
+$ term-banner 'Hello, World!' 'こんにちは、' '世界!'

第1問 brainf_ck.php
<?php
-
-declare(strict_types=0O1);
-
-namespace Dgcircus\PHPerKaigi\Y2022;
-
-/**
- * @todo
- * Run this program to acquire a PHPer token.
- */
-
-https://creativecommons.org/publicdomain/zero/1.0/
-
-\error_reporting(~+!'We are hiring!');
-
-$z = fn($f) => (fn($x) => $f(fn(...$xs) => $x($x)(...$xs)))(fn($x) => $f(fn(...$xs) => $x($x)(...$xs)));
-$id = \spl_object_id(...);
-$put = fn($c) => \printf('%c', $c);
-$mm = fn($p, $n) => new \ArrayObject(\array_fill(+!![], $n, $p));
-
-$👉 = fn($m, $p, $b, $e, $mp, $pc) => [++$mp, ++$pc];
-$👈 = fn($m, $p, $b, $e, $mp, $pc) => [--$mp, ++$pc];
-$👍 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, ++$m[$mp]];
-$👎 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, --$m[$mp]];
-$📝 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, $put($m[$mp])];
-$🤡 = fn($m, $p, $b, $e, $mp, $pc) => match ($m[$mp]) {
- +!![] => [$mp, $z(fn($loop) => fn($pc, $n) => match ($id($p[$pc])) {
- $b => $loop(++$pc, ++$n),
- $e => $n === +!![] ? ++$pc : $loop(++$pc, --$n),
- default => $loop(++$pc, $n),
- })($pc, -![])],
- default => [$mp, ++$pc],
-};
-$🎪 = fn($m, $p, $b, $e, $mp, $pc) => match ($m[$mp]) {
- +!![] => [$mp, ++$pc],
- default => [$mp, $z(fn($loop) => fn($pc, $n) => match ($id($p[$pc])) {
- $e => $loop(--$pc, ++$n),
- $b => $n === +!![] ? $pc+![] : $loop(--$pc, --$n),
- default => $loop(--$pc, $n),
- })($pc, -![])],
-};
-$🐘 = fn($p) => $z(fn($loop) => fn($m, $p, $b, $e, $mp, $pc) =>
- isset($p[$pc]) && $loop($m, $p, $b, $e, ...($p[$pc]($m, $p, $b, $e, $mp, $pc)))
-)($mm(+!![], +(![].![])), $p, $id($🤡), $id($🎪), +!![], +!![]);
-
-$🐘([
- $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
- $🤡,
- $👉, $👍, $👍, $👍,
- $👉, $👍, $👍, $👍, $👍, $👍,
- $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
- $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
- $👈, $👈, $👈, $👈, $👎,
- $🎪,
- $👉, $👍, $👍, $👍, $👍, $👍, $📝,
- $👎, $👎, $📝,
- $👉, $👎, $👎, $👎, $📝,
- $👉, $👎, $👎, $👎, $📝,
- $👎, $👎, $📝,
- $👎, $📝,
- $👈, $📝,
- $👉, $👉, $👎, $👎, $📝,
- $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝,
- $👈, $👎, $👎, $👎, $👎, $📝,
- $👈, $📝,
- $👉, $👍, $👍, $📝,
- $👉, $👎, $📝,
- $👈, $📝,
-]);
-<?php
+
+declare(strict_types=0O1);
+
+namespace Dgcircus\PHPerKaigi\Y2022;
+
+/**
+ * @todo
+ * Run this program to acquire a PHPer token.
+ */
+
+https://creativecommons.org/publicdomain/zero/1.0/
+
+\error_reporting(~+!'We are hiring!');
+
+$z = fn($f) => (fn($x) => $f(fn(...$xs) => $x($x)(...$xs)))(fn($x) => $f(fn(...$xs) => $x($x)(...$xs)));
+$id = \spl_object_id(...);
+$put = fn($c) => \printf('%c', $c);
+$mm = fn($p, $n) => new \ArrayObject(\array_fill(+!![], $n, $p));
+
+$👉 = fn($m, $p, $b, $e, $mp, $pc) => [++$mp, ++$pc];
+$👈 = fn($m, $p, $b, $e, $mp, $pc) => [--$mp, ++$pc];
+$👍 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, ++$m[$mp]];
+$👎 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, --$m[$mp]];
+$📝 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, $put($m[$mp])];
+$🤡 = fn($m, $p, $b, $e, $mp, $pc) => match ($m[$mp]) {
+ +!![] => [$mp, $z(fn($loop) => fn($pc, $n) => match ($id($p[$pc])) {
+ $b => $loop(++$pc, ++$n),
+ $e => $n === +!![] ? ++$pc : $loop(++$pc, --$n),
+ default => $loop(++$pc, $n),
+ })($pc, -![])],
+ default => [$mp, ++$pc],
+};
+$🎪 = fn($m, $p, $b, $e, $mp, $pc) => match ($m[$mp]) {
+ +!![] => [$mp, ++$pc],
+ default => [$mp, $z(fn($loop) => fn($pc, $n) => match ($id($p[$pc])) {
+ $e => $loop(--$pc, ++$n),
+ $b => $n === +!![] ? $pc+![] : $loop(--$pc, --$n),
+ default => $loop(--$pc, $n),
+ })($pc, -![])],
+};
+$🐘 = fn($p) => $z(fn($loop) => fn($m, $p, $b, $e, $mp, $pc) =>
+ isset($p[$pc]) && $loop($m, $p, $b, $e, ...($p[$pc]($m, $p, $b, $e, $mp, $pc)))
+)($mm(+!![], +(![].![])), $p, $id($🤡), $id($🎪), +!![], +!![]);
+
+$🐘([
+ $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
+ $🤡,
+ $👉, $👍, $👍, $👍,
+ $👉, $👍, $👍, $👍, $👍, $👍,
+ $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
+ $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
+ $👈, $👈, $👈, $👈, $👎,
+ $🎪,
+ $👉, $👍, $👍, $👍, $👍, $👍, $📝,
+ $👎, $👎, $📝,
+ $👉, $👎, $👎, $👎, $📝,
+ $👉, $👎, $👎, $👎, $📝,
+ $👎, $👎, $📝,
+ $👎, $📝,
+ $👈, $📝,
+ $👉, $👉, $👎, $👎, $📝,
+ $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝,
+ $👈, $👎, $👎, $👎, $👎, $📝,
+ $👈, $📝,
+ $👉, $👍, $👍, $📝,
+ $👉, $👎, $📝,
+ $👈, $📝,
+]);
+解説
絵文字
0O または 0o から始まる八進数リテラルを使った。URL
https://creativecommons.org/publicdomain/zero/1.0/
-https://creativecommons.org/publicdomain/zero/1.0/
+https: 部分はラベル、// 以降は行コメントになっている。リテラルなしで数値を生成する
assert(0 === +!![]);
-assert(1 === +![]);
-assert(2 === ![]+![]);
-assert(3 === ![]+![]+![]);
-assert(10 === +(![].+!![]));
-[] に ! を適用すると true が返ってくる。それに +
+assert(0 === +!![]);
+assert(1 === +![]);
+assert(2 === ![]+![]);
+assert(3 === ![]+![]+![]);
+assert(10 === +(![].+!![]));
+[] に ! を適用すると true が返ってくる。それに +
を適用すると、bool から int ヘの型変換が走り、1 が生成される。10
はさらにトリッキーだ。まず 1 と 0 を作り、. で文字列として結合する
('10')。これに + を適用すると、string から int
@@ -354,57 +354,57 @@ PHP では、型変換を利用することで任意の整数を作り出すこ
あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。第2問 riddle.php
<?php
-
-/*********************************************************
- * This program displays a PHPer token. *
- * Guess 'N'. *
- * *
- * Hints: *
- * - N itself has no special meaning, e.g., 42, 8128, *
- * it is selected at random. *
- * - Each element of $token represents a single letter. *
- * - One letter consists of 5x5 cells. *
- * - Remember, the output is a complete PHPer token. *
- * *
- * License: *
- * https://creativecommons.org/publicdomain/zero/1.0/ *
- *********************************************************/
-const N = 0 /* Change it to your answer. */;
-assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);
-
-$token = [
- 0x14B499C,
- 0x0BE34CC, 0x01C9C69,
- 0x0ECA069, 0x01C2449, 0x0FDB166, 0x01C9C69,
- 0x01C1C66, 0x0FC1C47, 0x01C1C66,
- 0x10C5858, 0x1E4E3B8, 0x1A2F2F8,
-];
-foreach ($token as $x) {
- $x = $x ^ N;
-
- $x = sprintf('%025b', $x);
- $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);
- $x = implode("\n", str_split($x, length: 5));
- echo "{$x}\n\n";
-}
-<?php
+
+/*********************************************************
+ * This program displays a PHPer token. *
+ * Guess 'N'. *
+ * *
+ * Hints: *
+ * - N itself has no special meaning, e.g., 42, 8128, *
+ * it is selected at random. *
+ * - Each element of $token represents a single letter. *
+ * - One letter consists of 5x5 cells. *
+ * - Remember, the output is a complete PHPer token. *
+ * *
+ * License: *
+ * https://creativecommons.org/publicdomain/zero/1.0/ *
+ *********************************************************/
+const N = 0 /* Change it to your answer. */;
+assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);
+
+$token = [
+ 0x14B499C,
+ 0x0BE34CC, 0x01C9C69,
+ 0x0ECA069, 0x01C2449, 0x0FDB166, 0x01C9C69,
+ 0x01C1C66, 0x0FC1C47, 0x01C1C66,
+ 0x10C5858, 0x1E4E3B8, 0x1A2F2F8,
+];
+foreach ($token as $x) {
+ $x = $x ^ N;
+
+ $x = sprintf('%025b', $x);
+ $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);
+ $x = implode("\n", str_split($x, length: 5));
+ echo "{$x}\n\n";
+}
+N を特定する必要がある。読解
$token = [
- // 略
-];
-$token があり、各要素をループしている。 $x = $x ^ N;
- $x = sprintf('%025b', $x);
- $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);
-# にし、 $x = implode("\n", str_split($x, length: 5));
-$token = [
+ // 略
+];
+$token があり、各要素をループしている。 $x = $x ^ N;
+ $x = sprintf('%025b', $x);
+ $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);
+# にし、 $x = implode("\n", str_split($x, length: 5));
+ヒント
@@ -418,76 +418,76 @@ $token = [
解く
0x14B499C が # に変換されるような N を見つければよい。N は高々assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);
-<?php
-
-$x = 0x14B499C;
-
-$x = $x ^ N;
-
-$x = sprintf('%025b', $x);
-$x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);
-$x = implode("\n", str_split($x, length: 5));
-
-assert($x ===
- " # # \n" .
- "#####\n" .
- " # # \n" .
- "#####\n" .
- " # # ");
-<?php
-
-$x =
- " # # \n" .
- "#####\n" .
- " # # \n" .
- "#####\n" .
- " # # ";
-
-$x = implode('', explode("\n", $x));
-$x = str_replace(search: [' ', '#'], replace: ['0', '1'], subject: $x);
-$x = bindec($x);
-
-$n = $x ^ 0x14B499C;
-
-echo "N = $n\n";
-N が得られる。assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);
+<?php
+
+$x = 0x14B499C;
+
+$x = $x ^ N;
+
+$x = sprintf('%025b', $x);
+$x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);
+$x = implode("\n", str_split($x, length: 5));
+
+assert($x ===
+ " # # \n" .
+ "#####\n" .
+ " # # \n" .
+ "#####\n" .
+ " # # ");
+<?php
+
+$x =
+ " # # \n" .
+ "#####\n" .
+ " # # \n" .
+ "#####\n" .
+ " # # ";
+
+$x = implode('', explode("\n", $x));
+$x = str_replace(search: [' ', '#'], replace: ['0', '1'], subject: $x);
+$x = bindec($x);
+
+$n = $x ^ 0x14B499C;
+
+echo "N = $n\n";
+N が得られる。第3問 toquine.php
<?php
-
-// License: https://creativecommons.org/publicdomain/zero/1.0/
-// This is a quine-like program to generate a PHPer token.
-// Execute it like this: php toquine.php | php | php | php | ...
-
-$s = <<<'Q'
-<?cuc
-// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/
-// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra.
-// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ...
-%f$f = %f;
-$f = fge_ebg13($f); $kf = [
-%f,
-];
-$g = ahyy.snyfr; sbe ($v = 0; $v <= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr
-$g .= vzcybqr("\a", fge_fcyvg(fge_ercynpr(['0','1'], [' ','##'], fcevags(pue(37) . '025o', $kf[$v])), 012)) . "\a\a";
-$jf = neenl_znc(sa($j) => vzcybqr(', ', $j), neenl_puhax(neenl_znc(sa($k) => fcevags('0k' . pue(37) . '07K', $k), $kf), 10));
-cevags($f, $g, fge_ebg13("<<<'Q'\a{$f}\aQ"), vzcybqr(",\a", $jf));
-Q;
-$s = str_rot13($s); $xs = [
-0x0AFABEA, 0x1F294A7, 0x1F2109F, 0x1F294A7, 0x0002800, 0x1F2109F, 0x0117041, 0x1F294A7, 0x1FAD6B5, 0x1F295B7,
-0x010FC21, 0x1FAD6B5, 0x1151151, 0x010FC21, 0x1F294A7, 0x1F295B7, 0x1FAD6B5, 0x1F294A7, 0x1F295B7, 0x1F8C63F,
-0x1F8C631, 0x1FAD6B5, 0x17AD6BD, 0x17AD6BD, 0x1F8C63F, 0x1F295B7,
-];
-$t = null.false; for ($i = 0; $i <= intdiv(__LINE__-035,6); ++$i) if (!isset($xs[$i])) break; else
-$t .= implode("\n", str_split(str_replace(['0','1'], [' ','##'], sprintf(chr(37) . '025b', $xs[$i])), 012)) . "\n\n";
-$ws = array_map(fn($w) => implode(', ', $w), array_chunk(array_map(fn($x) => sprintf('0x' . chr(37) . '07X', $x), $xs), 10));
-printf($s, $t, str_rot13("<<<'D'\n{$s}\nD"), implode(",\n", $ws));
-$ php toquine.php | php | php | php | ...
-<?php
+
+// License: https://creativecommons.org/publicdomain/zero/1.0/
+// This is a quine-like program to generate a PHPer token.
+// Execute it like this: php toquine.php | php | php | php | ...
+
+$s = <<<'Q'
+<?cuc
+// Yvprafr: uggcf://perngvirpbzzbaf.bet/choyvpqbznva/mreb/1.0/
+// Guvf vf n dhvar-yvxr cebtenz gb trarengr n CUCre gbxra.
+// Rkrphgr vg yvxr guvf: cuc gbdhvar.cuc | cuc | cuc | cuc | ...
+%f$f = %f;
+$f = fge_ebg13($f); $kf = [
+%f,
+];
+$g = ahyy.snyfr; sbe ($v = 0; $v <= vagqvi(__YVAR__-035,6); ++$v) vs (!vffrg($kf[$v])) oernx; ryfr
+$g .= vzcybqr("\a", fge_fcyvg(fge_ercynpr(['0','1'], [' ','##'], fcevags(pue(37) . '025o', $kf[$v])), 012)) . "\a\a";
+$jf = neenl_znc(sa($j) => vzcybqr(', ', $j), neenl_puhax(neenl_znc(sa($k) => fcevags('0k' . pue(37) . '07K', $k), $kf), 10));
+cevags($f, $g, fge_ebg13("<<<'Q'\a{$f}\aQ"), vzcybqr(",\a", $jf));
+Q;
+$s = str_rot13($s); $xs = [
+0x0AFABEA, 0x1F294A7, 0x1F2109F, 0x1F294A7, 0x0002800, 0x1F2109F, 0x0117041, 0x1F294A7, 0x1FAD6B5, 0x1F295B7,
+0x010FC21, 0x1FAD6B5, 0x1151151, 0x010FC21, 0x1F294A7, 0x1F295B7, 0x1FAD6B5, 0x1F294A7, 0x1F295B7, 0x1F8C63F,
+0x1F8C631, 0x1FAD6B5, 0x17AD6BD, 0x17AD6BD, 0x1F8C63F, 0x1F295B7,
+];
+$t = null.false; for ($i = 0; $i <= intdiv(__LINE__-035,6); ++$i) if (!isset($xs[$i])) break; else
+$t .= implode("\n", str_split(str_replace(['0','1'], [' ','##'], sprintf(chr(37) . '025b', $xs[$i])), 012)) . "\n\n";
+$ws = array_map(fn($w) => implode(', ', $w), array_chunk(array_map(fn($x) => sprintf('0x' . chr(37) . '07X', $x), $xs), 10));
+printf($s, $t, str_rot13("<<<'D'\n{$s}\nD"), implode(",\n", $ws));
+$ php toquine.php | php | php | php | ...
+解説
プログラム全体
前置き
#![allow(non_camel_case_types)]
-#![allow(dead_code)]
-
-struct bool;
-struct char;
-struct i8;
-struct i16;
-struct i32;
-struct i64;
-struct i128;
-struct isize;
-struct u8;
-struct u16;
-struct u32;
-struct u64;
-struct u128;
-struct usize;
-struct f32;
-struct f64;
-struct str;
-bool と書いたとき、この bool は一体どこから来ているのか。rustc のソースを追ってみた。#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+
+struct bool;
+struct char;
+struct i8;
+struct i16;
+struct i32;
+struct i64;
+struct i128;
+struct isize;
+struct u8;
+struct u16;
+struct u32;
+struct u64;
+struct u128;
+struct usize;
+struct f32;
+struct f64;
+struct str;
+bool と書いたとき、この bool は一体どこから来ているのか。rustc のソースを追ってみた。
@@ -553,91 +553,91 @@ Quine とは、自分のソースコードをそっくりそのまま出力す
rustc そのものの知識は不要 (というよりも筆者自身がよく知らない)compiler フォルダ以下に rustc_* という名前のクレートが数十個入っている。これがどうやら rustc コマンドの実装部のようだ。rustc はセルフホストされている (= rustc 自身が Rust で書かれている) ので、bool や char などで適当に検索をかけてもノイズが多すぎて話にならない。
しかし、お誂え向きなことに i128/u128 というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って git grep してみる。$ git grep "\bi128\b" | wc # i128
+$ git grep "\bi128\b" | wc # i128
165 1069 15790
-$ git grep "\bu128\b" | wc # u128
+$ git grep "\bu128\b" | wc # u128
293 2127 26667
-$ git grep "\bbool\b" | wc # cf. bool の結果
+$ git grep "\bbool\b" | wc # cf. bool の結果
3563 23577 294659
$ git grep "\bi128\b"
+$ git grep "\bi128\b"
...
rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
...
rustc_resolve というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。/// Interns the names of the primitive types.
-///
-/// All other types are defined somewhere and possibly imported, but the primitive ones need
-/// special handling, since they have no place of origin.
-struct PrimitiveTypeTable {
- primitive_types: FxHashMap<Symbol, PrimTy>,
-}
-
-impl PrimitiveTypeTable {
- fn new() -> PrimitiveTypeTable {
- let mut table = FxHashMap::default();
-
- table.insert(sym::bool, Bool);
- table.insert(sym::char, Char);
- table.insert(sym::f32, Float(FloatTy::F32));
- table.insert(sym::f64, Float(FloatTy::F64));
- table.insert(sym::isize, Int(IntTy::Isize));
- table.insert(sym::i8, Int(IntTy::I8));
- table.insert(sym::i16, Int(IntTy::I16));
- table.insert(sym::i32, Int(IntTy::I32));
- table.insert(sym::i64, Int(IntTy::I64));
- table.insert(sym::i128, Int(IntTy::I128));
- table.insert(sym::str, Str);
- table.insert(sym::usize, Uint(UintTy::Usize));
- table.insert(sym::u8, Uint(UintTy::U8));
- table.insert(sym::u16, Uint(UintTy::U16));
- table.insert(sym::u32, Uint(UintTy::U32));
- table.insert(sym::u64, Uint(UintTy::U64));
- table.insert(sym::u128, Uint(UintTy::U128));
- Self { primitive_types: table }
- }
-}
-/// Interns the names of the primitive types.
+///
+/// All other types are defined somewhere and possibly imported, but the primitive ones need
+/// special handling, since they have no place of origin.
+struct PrimitiveTypeTable {
+ primitive_types: FxHashMap<Symbol, PrimTy>,
+}
+
+impl PrimitiveTypeTable {
+ fn new() -> PrimitiveTypeTable {
+ let mut table = FxHashMap::default();
+
+ table.insert(sym::bool, Bool);
+ table.insert(sym::char, Char);
+ table.insert(sym::f32, Float(FloatTy::F32));
+ table.insert(sym::f64, Float(FloatTy::F64));
+ table.insert(sym::isize, Int(IntTy::Isize));
+ table.insert(sym::i8, Int(IntTy::I8));
+ table.insert(sym::i16, Int(IntTy::I16));
+ table.insert(sym::i32, Int(IntTy::I32));
+ table.insert(sym::i64, Int(IntTy::I64));
+ table.insert(sym::i128, Int(IntTy::I128));
+ table.insert(sym::str, Str);
+ table.insert(sym::usize, Uint(UintTy::Usize));
+ table.insert(sym::u8, Uint(UintTy::U8));
+ table.insert(sym::u16, Uint(UintTy::U16));
+ table.insert(sym::u32, Uint(UintTy::U32));
+ table.insert(sym::u64, Uint(UintTy::U64));
+ table.insert(sym::u128, Uint(UintTy::U128));
+ Self { primitive_types: table }
+ }
+}
+
/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
- /// (略)
- fn resolve_ident_in_lexical_scope(
- &mut self,
- mut ident: Ident,
- ns: Namespace,
- // (略)
- ) -> Option<LexicalScopeBinding<'a>> {
- // (略)
-
- if ns == TypeNS {
- if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) {
- let binding =
- (Res::PrimTy(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
- .to_name_binding(self.arenas);
- return Some(LexicalScopeBinding::Item(binding));
- }
- }
-
- None
- }
- /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
+ /// (略)
+ fn resolve_ident_in_lexical_scope(
+ &mut self,
+ mut ident: Ident,
+ ns: Namespace,
+ // (略)
+ ) -> Option<LexicalScopeBinding<'a>> {
+ // (略)
+
+ if ns == TypeNS {
+ if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) {
+ let binding =
+ (Res::PrimTy(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
+ .to_name_binding(self.arenas);
+ return Some(LexicalScopeBinding::Item(binding));
+ }
+ }
+
+ None
+ }
+if ns == TypeNS のブロック内では、primitive_type_table (上記の PrimitiveTypeTable::new() で作られた変数) に含まれている識別子 (bool、i32 など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。ns は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この if は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。resolve_ident_in_lexical_scope() の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。#![allow(non_camel_case_types)]
-
-struct bool;
-
-fn main() {
- let _: bool = bool;
-}
-main() の bool は struct bool として解決される。なぜなら、プリミティブ型の判定をする前に bool という名前の別の型が見つかるからだ。#![allow(non_camel_case_types)]
+
+struct bool;
+
+fn main() {
+ let _: bool = bool;
+}
+main() の bool は struct bool として解決される。なぜなら、プリミティブ型の判定をする前に bool という名前の別の型が見つかるからだ。まとめ
case - in によるパターンマッチング構文でも、case - when と同じように then が使える (場合によっては使う必要がある)。then とはthen がキーワードになっている。次のように使う:if cond then
- puts "Y"
-else
- puts "N"
-end
-if、unless、rescue、case 構文がそれに当たる。
+if cond then
+ puts "Y"
+else
+ puts "N"
+end
+if、unless、rescue、case 構文がそれに当たる。
上記のように、何か条件を書いた後 then を置き、式がそこで終了していることを示すマーカーとして機能する。# Example:
-
-if x then
- a
-end
-
-unless x then
- a
-end
-
-begin
- a
-rescue then
- b
-end
-
-case x
-when p then
- a
-end
-なぜ普段は書かなくてもよいのか
+# Example:
+
+if x then
+ a
+end
+
+unless x then
+ a
+end
+
+begin
+ a
+rescue then
+ b
+end
+
+case x
+when p then
+ a
+end
+なぜ普段は書かなくてもよいのか
then を書くことはない。なぜか。次のコードを実行してみるとわかる。if true puts 'Hello, World!' end
-20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n'
-if true puts 'Hello, World!' end
+if true puts 'Hello, World!' end
+20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n'
+if true puts 'Hello, World!' end
^~~~
-20:1: syntax error, unexpected `end', expecting end-of-input
-...f true puts 'Hello, World!' end
+20:1: syntax error, unexpected `end', expecting end-of-input
+...f true puts 'Hello, World!' end
then か ; か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。then (や ;) の代わりとなることである。true の後に改行を入れてみる。if true
-puts 'Hello, World!' end
-if true
+puts 'Hello, World!' end
+なぜ
then や ; や改行が必要かthen や ; や改行 (以下 「then 等」) が必要なのだろうか。次の例を見てほしい:if a b end
-then も ; も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。
+if a b end
+then も ; も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。
この例は二通りに解釈できる。# a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価
-if a then
- b
-end
-# a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、
-# その結果が truthy なら何もしない
-if a(b) then
-end
-then 等はこの曖昧性を排除するためにあり、条件式は if から then 等までの間にある、ということを明確にする。
+# a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価
+if a then
+ b
+end
+# a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、
+# その結果が truthy なら何もしない
+if a(b) then
+end
+then 等はこの曖昧性を排除するためにあり、条件式は if から then 等までの間にある、ということを明確にする。
C系の if 後に来る (/) や、Python の :、Rust/Go/Swift などの { も同じ役割を持つ。then が代用できるので、ほとんどの場合 then は必要ない。
@@ -748,33 +748,33 @@ C系の case - in における thenif 後に来る (/) や、Python
;
keyword_in は文字通り in、p_top_expr はいわゆるパターン、then は then キーワードのことではなく、この記事で then 等と呼んでいるもの、つまり then キーワード、;、改行のいずれかである。case - when による従来の構文と同じように、then 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:case x
-in 1 then a
-in 2 then b
-in 3 then c
-end
-
-case x
-in 1
- a
-in 2
- b
-in 3
- c
-end
-
-case x
-in 1; a
-in 2; b
-in 3; c
-end
-p_top_expr には if による guard clause が書けるので、その場合は if - then と似たような見た目になる。case x
-in 0 then a
-in n if n < 0 then b
-in n then c
-end
-まとめ
+case x
+in 1 then a
+in 2 then b
+in 3 then c
+end
+
+case x
+in 1
+ a
+in 2
+ b
+in 3
+ c
+end
+
+case x
+in 1; a
+in 2; b
+in 3; c
+end
+p_top_expr には if による guard clause が書けるので、その場合は if - then と似たような見た目になる。case x
+in 0 then a
+in n if n < 0 then b
+in n then c
+end
+まとめ
if や case の条件の後ろには then、;、改行のいずれかが必要
@@ -797,26 +797,26 @@ C系の
if 後に来る (/) や、Python
元 URL: https://qiita.com/nsfisis/items/94090937bcf860cfa93b
タイトル落ち。まずはこのコードを見て欲しい。
-#include <iostream>
-
-[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]
-[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]
-[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]
-[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]
-[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]
-[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]
-[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]
-[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]
-[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]
-[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]
-[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]
-[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]
-[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]
-// [[using]]
-int main() {
- std::cout << "Hello, World!" << std::endl;
-}
-+#include <iostream> + +[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]] +[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]] +[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]] +[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]] +[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]] +[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]] +[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]] +[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]] +[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]] +[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]] +[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]] +[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]] +[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]] +// [[using]] +int main() { + std::cout << "Hello, World!" << std::endl; +} +コンパイラのバージョン $ clang++ –version Apple clang version 11.0.0 (clang-1100.0.33.8) @@ -842,9 +842,9 @@ $ clang++ –std=c++17 hoge.cpp
同サイトの [keywords のページ] (https://en.cppreference.com/w/cpp/keyword) から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown attribute ‘〇〇’ ignored) がコンパイラから出力されるが、コンパイルできる。
上のコードでは
-[[using]]をコメントアウトしているが、これはusingキーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。// using の例 -[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文 -C++17 の仕様も見てみる (正確には標準化前のドラフト)。
+// using の例 +[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文 +C++17 の仕様も見てみる (正確には標準化前のドラフト)。
引用元: https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4
If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier.
@@ -878,13 +878,13 @@ $ clang++ –std=c++17 hoge.cpp
Objectクラスに定義されているRUBY_ENGINEという定数がこの用途に使える。上記ページの例から引用する:
-$ ruby-1.9.1 -ve 'p RUBY_ENGINE' -ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux] -"ruby" -$ jruby -ve 'p RUBY_ENGINE' -jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] -"jruby" -それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。
+$ ruby-1.9.1 -ve 'p RUBY_ENGINE' +ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux] +"ruby" +$ jruby -ve 'p RUBY_ENGINE' +jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] +"jruby" +それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。
What values for RUBY_ENGINE correspond to which Ruby implementations? より引用:
@@ -933,11 +933,11 @@ jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も
'ruby'が返ってくることを確認済み。この表にない主要な処理系として、mruby は
'mruby'を返す。mruby 該当部分のソース より引用:
-]]> +/* - * Ruby engine. - */ -#define MRUBY_RUBY_ENGINE "mruby" -]]>/* + * Ruby engine. + */ +#define MRUBY_RUBY_ENGINE "mruby" +- @@ -976,10 +976,10 @@ Huge version without GUI.
:g/^/m0のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。なお、
-:g/^/m0は全ての行を入れ替えるが、:N,Mg/^/mN-1とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。command! -bar -range=% - \ Reverse - \ <line1>,<line2>g/^/m<line1>-1 -これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。
+command! -bar -range=% + \ Reverse + \ <line1>,<line2>g/^/m<line1>-1 +これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。
:g/^/m0の問題点
:globalコマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。^は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。'hlsearch'オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうとnコマンドなどの際に不便である。@@ -991,14 +991,14 @@ Huge version without GUI. より簡潔な方法を見つけたので次節に追記した前述した
-:Reverseコマンドの定義を少し変えて、次のようにする:function! s:reverse_lines(from, to) abort - execute printf("%d,%dg/^/m%d", a:from, a:to, a:from - 1) -endfunction - -command! -bar -range=% - \ Reverse - \ call <SID>reverse_lines(<line1>, <line2>) -実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。
+function! s:reverse_lines(from, to) abort + execute printf("%d,%dg/^/m%d", a:from, a:to, a:from - 1) +endfunction + +command! -bar -range=% + \ Reverse + \ call <SID>reverse_lines(<line1>, <line2>) +実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。
この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが
^で上書きされることがなくなる。Vim のヘルプから該当箇所を引用する (強調は筆者による)。
@@ -1022,20 +1022,20 @@ executing autocommands |autocmd-searchpat|.-[2020/9/28追記] より簡潔な方法を見つけたため追記する
command! -bar -range=% - \ Reverse - \ keeppatterns <line1>,<line2>g/^/m<line1>-1 -まさにこのための Exコマンド、
+:keeppatternsが存在する。:keeppatterns {command}のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。command! -bar -range=% + \ Reverse + \ keeppatterns <line1>,<line2>g/^/m<line1>-1 +まさにこのための Exコマンド、
:keeppatternsが存在する。:keeppatterns {command}のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。:h :keeppatterns
コピペ用再掲
-]]> +" License: Public Domain - -command! -bar -range=% - \ Reverse - \ keeppatterns <line1>,<line2>g/^/m<line1>-1 -]]>" License: Public Domain + +command! -bar -range=% + \ Reverse + \ keeppatterns <line1>,<line2>g/^/m<line1>-1 +- @@ -1069,26 +1069,26 @@ executing autocommands |autocmd-searchpat|.
diff --git a/docs/index.html b/docs/index.html index 128abc3..aed015e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -15,7 +15,7 @@ - + diff --git a/docs/page/1/index.html b/docs/page/1/index.html index e0486f7..81da958 100644 --- a/docs/page/1/index.html +++ b/docs/page/1/index.html @@ -1 +1,10 @@ -vim のソースコード
以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。
https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86
-{"BufAdd", EVENT_BUFADD}, - {"BufCreate", EVENT_BUFADD}, -https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97
-{"BufRead", EVENT_BUFREADPOST}, - {"BufReadCmd", EVENT_BUFREADCMD}, - {"BufReadPost", EVENT_BUFREADPOST}, -https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105
-{"BufWrite", EVENT_BUFWRITEPRE}, - {"BufWritePost", EVENT_BUFWRITEPOST}, - {"BufWritePre", EVENT_BUFWRITEPRE}, -neovim のソースコード
+{"BufAdd", EVENT_BUFADD}, + {"BufCreate", EVENT_BUFADD}, +https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97
+{"BufRead", EVENT_BUFREADPOST}, + {"BufReadCmd", EVENT_BUFREADCMD}, + {"BufReadPost", EVENT_BUFREADPOST}, +https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105
+{"BufWrite", EVENT_BUFWRITEPRE}, + {"BufWritePost", EVENT_BUFWRITEPOST}, + {"BufWritePre", EVENT_BUFWRITEPRE}, +neovim のソースコード
neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり
-aliasesと書かれている。aliases = { - BufCreate = 'BufAdd', - BufRead = 'BufReadPost', - BufWrite = 'BufWritePre', - FileEncoding = 'EncodingChanged', - }, -ところで、上では取り上げなかった
+FileEncodingだが、これは:help FileEncodingにしっかりと書いてある。aliases = { + BufCreate = 'BufAdd', + BufRead = 'BufReadPost', + BufWrite = 'BufWritePre', + FileEncoding = 'EncodingChanged', + }, +ところで、上では取り上げなかった
FileEncodingだが、これは:help FileEncodingにしっかりと書いてある。*FileEncoding* FileEncoding Obsolete. It still works and is equivalent to |EncodingChanged|. @@ -1131,38 +1131,38 @@ FileEncoding Obsolete. It still works and is equivalent
本記事は Python 3.7.6 の動作結果を元にして書かれている。
Python でクロージャを作ろうと、次のようなコードを書いた。
-def f(): - x = 0 - def g(): - x += 1 - g() - -f() -関数
gから 関数fのスコープ内で定義された変数xを参照し、それに 1 を足そうとしている。 +def f(): + x = 0 + def g(): + x += 1 + g() + +f() +関数
gから 関数fのスコープ内で定義された変数xを参照し、それに 1 を足そうとしている。 これを実行するとx += 1の箇所でエラーが発生する。UnboundLocalError: local variable ‘x’ referenced before assignment
local変数
-xが代入前に参照された、とある。これは、fのxを参照するのではなく、新しく別の変数をg内に作ってしまっているため。 前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。varを変数宣言のための構文として擬似的に利用している。# 注: var は正しい Python の文法ではない。上記参照のこと -def f(): - var x # f の local変数 'x' を宣言 - x = 0 # x に 0 を代入 - def g(): # f の内部関数 g を定義 - var x # g の local変数 'x' を宣言 - # たまたま f にも同じ名前の変数があるが、それとは別の変数 - x += 1 # x に 1 を加算 (x = x + 1 の糖衣構文) - # 加算する前の値を参照しようとするが、まだ代入されていないためエラー - g() -当初の意図を表現するには、次のように書けばよい。
-def f(): - x = 0 - def g(): - nonlocal x ## (*) - x += 1 - g() -+
(*)のように、nonlocalを追加する。これにより一つ外側のスコープ (gの一つ外側 =f) で定義されているxを探しに行くようになる。# 注: var は正しい Python の文法ではない。上記参照のこと +def f(): + var x # f の local変数 'x' を宣言 + x = 0 # x に 0 を代入 + def g(): # f の内部関数 g を定義 + var x # g の local変数 'x' を宣言 + # たまたま f にも同じ名前の変数があるが、それとは別の変数 + x += 1 # x に 1 を加算 (x = x + 1 の糖衣構文) + # 加算する前の値を参照しようとするが、まだ代入されていないためエラー + g() +当初の意図を表現するには、次のように書けばよい。
+def f(): + x = 0 + def g(): + nonlocal x ## (*) + x += 1 + g() +]]>
(*)のように、nonlocalを追加する。これにより一つ外側のスコープ (gの一つ外側 =f) で定義されているxを探しに行くようになる。https://blog.nsfisis.dev/ \ No newline at end of file + + + +https://blog.nsfisis.dev/ + + + + + + diff --git a/docs/page/2/index.html b/docs/page/2/index.html index fcb0be7..6efc6f4 100644 --- a/docs/page/2/index.html +++ b/docs/page/2/index.html @@ -15,7 +15,7 @@ - + diff --git a/docs/posts/2021-03-05/my-first-post/index.html b/docs/posts/2021-03-05/my-first-post/index.html index 65fa969..cd1bbe8 100644 --- a/docs/posts/2021-03-05/my-first-post/index.html +++ b/docs/posts/2021-03-05/my-first-post/index.html @@ -15,7 +15,7 @@ - + diff --git a/docs/posts/2021-03-30/phperkaigi-2021/index.html b/docs/posts/2021-03-30/phperkaigi-2021/index.html index 242e034..a10cc08 100644 --- a/docs/posts/2021-03-30/phperkaigi-2021/index.html +++ b/docs/posts/2021-03-30/phperkaigi-2021/index.html @@ -15,7 +15,7 @@ - + diff --git a/docs/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html b/docs/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html index 7261530..38c34aa 100644 --- a/docs/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html +++ b/docs/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes/index.html @@ -15,7 +15,7 @@ - + @@ -47,26 +47,26 @@ 元 URL: https://qiita.com/nsfisis/items/94090937bcf860cfa93b
タイトル落ち。まずはこのコードを見て欲しい。
-#include <iostream> - -[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]] -[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]] -[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]] -[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]] -[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]] -[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]] -[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]] -[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]] -[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]] -[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]] -[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]] -[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]] -[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]] -// [[using]] -int main() { - std::cout << "Hello, World!" << std::endl; -} -+#include <iostream> + +[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]] +[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]] +[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]] +[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]] +[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]] +[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]] +[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]] +[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]] +[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]] +[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]] +[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]] +[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]] +[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]] +// [[using]] +int main() { + std::cout << "Hello, World!" << std::endl; +} +コンパイラのバージョン $ clang++ –version Apple clang version 11.0.0 (clang-1100.0.33.8) @@ -92,9 +92,9 @@ $ clang++ –std=c++17 hoge.cpp
同サイトの [keywords のページ] (https://en.cppreference.com/w/cpp/keyword) から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown attribute ‘〇〇’ ignored) がコンパイラから出力されるが、コンパイルできる。
上のコードでは
-[[using]]をコメントアウトしているが、これはusingキーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。// using の例 -[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文 -C++17 の仕様も見てみる (正確には標準化前のドラフト)。
+// using の例 +[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文 +C++17 の仕様も見てみる (正確には標準化前のドラフト)。
引用元: https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4
If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier.
diff --git a/docs/posts/2021-10-02/python-unbound-local-error/index.html b/docs/posts/2021-10-02/python-unbound-local-error/index.html index bfad1b3..35a880d 100644 --- a/docs/posts/2021-10-02/python-unbound-local-error/index.html +++ b/docs/posts/2021-10-02/python-unbound-local-error/index.html @@ -15,7 +15,7 @@ - + @@ -48,38 +48,38 @@
本記事は Python 3.7.6 の動作結果を元にして書かれている。
Python でクロージャを作ろうと、次のようなコードを書いた。
-def f(): - x = 0 - def g(): - x += 1 - g() - -f() -関数
gから 関数fのスコープ内で定義された変数xを参照し、それに 1 を足そうとしている。 +def f(): + x = 0 + def g(): + x += 1 + g() + +f() +関数
gから 関数fのスコープ内で定義された変数xを参照し、それに 1 を足そうとしている。 これを実行するとx += 1の箇所でエラーが発生する。UnboundLocalError: local variable ‘x’ referenced before assignment
local変数
-xが代入前に参照された、とある。これは、fのxを参照するのではなく、新しく別の変数をg内に作ってしまっているため。 前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。varを変数宣言のための構文として擬似的に利用している。# 注: var は正しい Python の文法ではない。上記参照のこと -def f(): - var x # f の local変数 'x' を宣言 - x = 0 # x に 0 を代入 - def g(): # f の内部関数 g を定義 - var x # g の local変数 'x' を宣言 - # たまたま f にも同じ名前の変数があるが、それとは別の変数 - x += 1 # x に 1 を加算 (x = x + 1 の糖衣構文) - # 加算する前の値を参照しようとするが、まだ代入されていないためエラー - g() -当初の意図を表現するには、次のように書けばよい。
-def f(): - x = 0 - def g(): - nonlocal x ## (*) - x += 1 - g() -+
(*)のように、nonlocalを追加する。これにより一つ外側のスコープ (gの一つ外側 =f) で定義されているxを探しに行くようになる。# 注: var は正しい Python の文法ではない。上記参照のこと +def f(): + var x # f の local変数 'x' を宣言 + x = 0 # x に 0 を代入 + def g(): # f の内部関数 g を定義 + var x # g の local変数 'x' を宣言 + # たまたま f にも同じ名前の変数があるが、それとは別の変数 + x += 1 # x に 1 を加算 (x = x + 1 の糖衣構文) + # 加算する前の値を参照しようとするが、まだ代入されていないためエラー + g() +当初の意図を表現するには、次のように書けばよい。
+def f(): + x = 0 + def g(): + nonlocal x ## (*) + x += 1 + g() +diff --git a/docs/posts/2021-10-02/ruby-detect-running-implementation/index.html b/docs/posts/2021-10-02/ruby-detect-running-implementation/index.html index 864dc28..71eadba 100644 --- a/docs/posts/2021-10-02/ruby-detect-running-implementation/index.html +++ b/docs/posts/2021-10-02/ruby-detect-running-implementation/index.html @@ -15,7 +15,7 @@ - + @@ -49,13 +49,13 @@
(*)のように、nonlocalを追加する。これにより一つ外側のスコープ (gの一つ外側 =f) で定義されているxを探しに行くようになる。
Objectクラスに定義されているRUBY_ENGINEという定数がこの用途に使える。上記ページの例から引用する:
-$ ruby-1.9.1 -ve 'p RUBY_ENGINE' -ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux] -"ruby" -$ jruby -ve 'p RUBY_ENGINE' -jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] -"jruby" -それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。
+$ ruby-1.9.1 -ve 'p RUBY_ENGINE' +ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux] +"ruby" +$ jruby -ve 'p RUBY_ENGINE' +jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java] +"jruby" +それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。
What values for RUBY_ENGINE correspond to which Ruby implementations? より引用:
@@ -104,11 +104,11 @@ jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も
'ruby'が返ってくることを確認済み。この表にない主要な処理系として、mruby は
'mruby'を返す。mruby 該当部分のソース より引用:
-+/* - * Ruby engine. - */ -#define MRUBY_RUBY_ENGINE "mruby" -/* + * Ruby engine. + */ +#define MRUBY_RUBY_ENGINE "mruby" +