From 0766039bd9e6b9f5e6334e84666f5be698d41fc3 Mon Sep 17 00:00:00 2001
From: nsfisis
#include <iostream>
+ #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;
+[[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;
}
@@ -134,8 +134,8 @@ std::cout << "Hello, World!" << std::endl;
上のコードでは[[using]]をコメントアウトしているが、これはusingキーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。
- // using の例
-[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文
+ // using の例
+[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文
C++17 の仕様も見てみる (正確には標準化前のドラフト)。
diff --git a/public/posts/2021-10-02/python-unbound-local-error/index.html b/public/posts/2021-10-02/python-unbound-local-error/index.html
index 4461af8..1631ccb 100644
--- a/public/posts/2021-10-02/python-unbound-local-error/index.html
+++ b/public/posts/2021-10-02/python-unbound-local-error/index.html
@@ -10,7 +10,7 @@
【Python】 クロージャとUnboundLocalError: local variable 'x' referenced before assignment | REPL: Rest-Eat-Program Loop
-
+
@@ -70,10 +70,10 @@
Python でクロージャを作ろうと、次のようなコードを書いた。
- def f():
-x = 0
-def g():
-x += 1
+ def f():
+x = 0
+def g():
+x += 1
g()
f()
@@ -92,26 +92,26 @@ f()
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 の糖衣構文)
-# 加算する前の値を参照しようとするが、まだ代入されていないためエラー
+ # 注: 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
+ def f():
+x = 0
+def g():
+nonlocal x ## (*)
+x += 1
g()
diff --git a/public/posts/2021-10-02/ruby-detect-running-implementation/index.html b/public/posts/2021-10-02/ruby-detect-running-implementation/index.html
index 06b5eb5..03bae40 100644
--- a/public/posts/2021-10-02/ruby-detect-running-implementation/index.html
+++ b/public/posts/2021-10-02/ruby-detect-running-implementation/index.html
@@ -10,7 +10,7 @@
【Ruby】 自身を実行している処理系の種類を判定する | REPL: Rest-Eat-Program Loop
-
+
@@ -75,10 +75,10 @@
上記ページの例から引用する:
- $ ruby-1.9.1 -ve 'p 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 -ve 'p RUBY_ENGINE'
jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
"jruby"
@@ -200,10 +200,10 @@ jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
mruby 該当部分のソースより引用:
- /*
+ /*
* Ruby engine.
-*/
-#define MRUBY_RUBY_ENGINE "mruby"
+*/
+#define MRUBY_RUBY_ENGINE "mruby"
diff --git a/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html
index 49127f6..f66ae0b 100644
--- a/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html
+++ b/public/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html
@@ -10,7 +10,7 @@
【Ruby】 then キーワードと case in | REPL: Rest-Eat-Program Loop
-
+
@@ -75,36 +75,36 @@
使われることは稀だが、Ruby ではthenがキーワードになっている。次のように使う:
- if cond then
- puts "Y"
- else
- puts "N"
- end
+ if cond then
+ puts "Y"
+ else
+ puts "N"
+ end
このキーワードが現れうる場所はいくつかあり、if、unless、rescue、case構文がそれに当たる。 上記のように、何か条件を書いた後thenを置き、式がそこで終了していることを示すマーカーとして機能する。
- # Example:
+ # Example:
-if x then
+if x then
a
-end
+end
-unless x then
+unless x then
a
-end
+end
-begin
+begin
a
-rescue then
+rescue then
b
-end
+end
-case x
-when p then
+case x
+when p then
a
-end
+end
@@ -113,17 +113,17 @@ end
普通 Ruby のコードでthenを書くことはない。なぜか。次のコードを実行してみるとわかる。
- 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 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か;か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。
@@ -133,8 +133,8 @@ if true puts 'Hello, World!' end
ポイントは改行がthen(や;) の代わりとなることである。trueの後に改行を入れてみる。
- if true
-puts 'Hello, World!' end
+ if true
+puts 'Hello, World!' end
無事 Hello, World! と出力されるようになった。
@@ -147,21 +147,21 @@ puts 'Hello, World!' end
なぜthenや;や改行 (以下 「then等」) が必要なのだろうか。次の例を見てほしい:
- if a b end
+ if a b end
thenも;も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 この例は二通りに解釈できる。
- # a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価
-if a then
+ # a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価
+if a then
b
-end
+end
- # a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、
-# その結果が truthy なら何もしない
-if a(b) then
-end
+ # a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、
+# その結果が truthy なら何もしない
+if a(b) then
+end
then等はこの曖昧性を排除するためにあり、条件式はifからthen等までの間にある、ということを明確にする。 C系のif後に来る(/)や、Python の:、Rust/Go/Swift などの{も同じ役割を持つ。
@@ -182,7 +182,7 @@ end
https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986
- p_case_body : keyword_in
+ p_case_body : keyword_in
{
SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
p->command_start = FALSE;
@@ -213,7 +213,7 @@ end
簡略版:
- p_case_body : keyword_in p_top_expr then compstmt p_cases
+ p_case_body : keyword_in p_top_expr then compstmt p_cases
;
@@ -224,36 +224,36 @@ end
これにより、case-whenによる従来の構文と同じように、then等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:
- case x
-in 1 then a
-in 2 then b
-in 3 then c
-end
+ case x
+in 1 then a
+in 2 then b
+in 3 then c
+end
-case x
-in 1
+case x
+in 1
a
-in 2
+in 2
b
-in 3
+in 3
c
-end
+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 0 then a
+in n if n < 0 then b
+in n then c
+end
diff --git a/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html
index e86d724..bc40aaa 100644
--- a/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html
+++ b/public/posts/2021-10-02/rust-where-are-primitive-types-from/index.html
@@ -10,7 +10,7 @@
Rust のプリミティブ型はどこからやって来るか | REPL: Rest-Eat-Program Loop
-
+
@@ -65,26 +65,26 @@
Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。
- #![allow(non_camel_case_types)]
-#![allow(dead_code)]
+ #![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;
+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 のソースを追ってみた。
@@ -119,20 +119,20 @@ struct str;
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
165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。
- $ git grep "\bi128\b"
+ $ git grep "\bi128\b"
...
rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
...
@@ -141,36 +141,36 @@ 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 {
+ /// 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();
+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 }
+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 }
}
}
@@ -188,26 +188,26 @@ Self { primitive_types: table }
とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。
- /// 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,
+ /// 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>> {
-// (略)
+// (略)
+) -> 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));
+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
+None
}
@@ -226,12 +226,12 @@ None
動作がわかったところで、例として次のコードを考える。
- #![allow(non_camel_case_types)]
+ #![allow(non_camel_case_types)]
-struct bool;
+struct bool;
-fn main() {
-let _: bool = bool;
+fn main() {
+let _: bool = bool;
}
diff --git a/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html b/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html
index 049afdc..f45df6b 100644
--- a/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html
+++ b/public/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html
@@ -10,7 +10,7 @@
【Vim】 autocmd events の BufWrite/BufWritePre の違い | REPL: Rest-Eat-Program Loop
-
+
@@ -122,24 +122,24 @@
https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86
- {"BufAdd", EVENT_BUFADD},
-{"BufCreate", EVENT_BUFADD},
+ {"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},
+ {"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},
+ {"BufWrite", EVENT_BUFWRITEPRE},
+{"BufWritePost", EVENT_BUFWRITEPOST},
+{"BufWritePre", EVENT_BUFWRITEPRE},
@@ -152,11 +152,11 @@
https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124
- aliases = {
-BufCreate = 'BufAdd',
-BufRead = 'BufReadPost',
-BufWrite = 'BufWritePre',
-FileEncoding = 'EncodingChanged',
+ aliases = {
+BufCreate = 'BufAdd',
+BufRead = 'BufReadPost',
+BufWrite = 'BufWritePre',
+FileEncoding = 'EncodingChanged',
},
diff --git a/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html b/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html
index 366912c..8dbea05 100644
--- a/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html
+++ b/public/posts/2021-10-02/vim-swap-order-of-selected-lines/index.html
@@ -10,7 +10,7 @@
Vimで選択した行の順番を入れ替える | REPL: Rest-Eat-Program Loop
-
+
@@ -125,7 +125,7 @@
なお、:g/^/m0は全ての行を入れ替えるが、:N,Mg/^/mN-1とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。
- command! -bar -range=%
+ command! -bar -range=%
\ Reverse
\ <line1>,<line2>g/^/m<line1>-1
@@ -160,7 +160,7 @@
前述した:Reverseコマンドの定義を少し変えて、次のようにする:
- function! s:reverse_lines(from, to) abort
+ function! s:reverse_lines(from, to) abort
execute printf("%d,%dg/^/m%d", a:from, a:to, a:from - 1)
endfunction
@@ -217,7 +217,7 @@
- command! -bar -range=%
+ command! -bar -range=%
\ Reverse
\ keeppatterns <line1>,<line2>g/^/m<line1>-1
@@ -234,7 +234,7 @@
コピペ用再掲
- " License: Public Domain
+ " License: Public Domain
command! -bar -range=%
\ Reverse
diff --git a/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html
index 9ac3f90..25873b7 100644
--- a/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html
+++ b/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html
@@ -10,7 +10,7 @@
PHPerKaigi 2022 トークン問題の解説 | REPL: Rest-Eat-Program Loop
-
+
@@ -76,50 +76,50 @@
ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。
- <?php
+ <?php
- declare(strict_types=0O1);
+ declare(strict_types=0O1);
- namespace Dgcircus\PHPerKaigi\Y2022;
+ namespace Dgcircus\PHPerKaigi\Y2022;
- /**
- * @todo
+ /**
+ * @todo
* Run this program to acquire a PHPer token.
- */
+ */
- https://creativecommons.org/publicdomain/zero/1.0/
+ https://creativecommons.org/publicdomain/zero/1.0/
- \error_reporting(~+!'We are hiring!');
+ \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));
+ $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) => [++$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($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($🎪), +!![], +!![]);
+ $🐘 = 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($🎪), +!![], +!![]);
$🐘([
$👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
@@ -175,26 +175,26 @@
+ + + + + + + + + +
[
-> + + +
-> + + + + +
-> + + + + + + + + + + + +
-> + + + + + + + + + +
-< < < < -
+> + + +
+> + + + + +
+> + + + + + + + + + + + +
+> + + + + + + + + + +
+< < < < -
]
-> + + + + + .
+> + + + + + .
- - .
-> - - - .
-> - - - .
+> - - - .
+> - - - .
- - .
- .
-< .
-> > - - .
+< .
+> > - - .
+ + + + + + + .
-< - - - - .
-< .
-> + + .
-> - .
-< .
+< - - - - .
+< .
+> + + .
+> - .
+< .
実行結果はこちら:https://ideone.com/22VWmb
@@ -277,7 +277,7 @@
ソースコードのライセンスを示したこの部分だが、
- https://creativecommons.org/publicdomain/zero/1.0/
+ https://creativecommons.org/publicdomain/zero/1.0/
完全に合法な PHP のコードである。https:部分はラベル、//以降は行コメントになっている。
@@ -290,11 +290,11 @@
ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 PHP では、型変換を利用することで任意の整数を作り出すことができる。
- assert(0 === +!![]);
-assert(1 === +![]);
-assert(2 === ![]+![]);
-assert(3 === ![]+![]+![]);
-assert(10 === +(![].+!![]));
+ assert(0 === +!![]);
+assert(1 === +![]);
+assert(2 === ![]+![]);
+assert(3 === ![]+![]+![]);
+assert(10 === +(![].+!![]));
[]に!を適用するとtrueが返ってくる。それに+を適用すると、boolからintヘの型変換が走り、1が生成される。10はさらにトリッキーだ。まず1と0を作り、.で文字列として結合する ('10')。これに+を適用すると、stringからintへの型変換が走り、10が生まれる (コード量に頓着しないなら、1を 10 個足し合わせてももちろん 10 が作れる)。
@@ -335,11 +335,11 @@ assert(10 === +(![].+!![]));
ソースコードはこちら。実行には PHP 8.0 以上が必要なので注意。
- <?php
+ <?php
- /*********************************************************
+ /*********************************************************
* This program displays a PHPer token. *
- * Guess 'N'. *
+ * Guess 'N'. *
* *
* Hints: *
* - N itself has no special meaning, e.g., 42, 8128, *
@@ -350,24 +350,24 @@ assert(10 === +(![].+!![]));
* *
* 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);
+ *********************************************************/
+ 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,
+ $token = [
+ 0x14B499C,
+ 0x0BE34CC, 0x01C9C69,
+ 0x0ECA069, 0x01C2449, 0x0FDB166, 0x01C9C69,
+ 0x01C1C66, 0x0FC1C47, 0x01C1C66,
+ 0x10C5858, 0x1E4E3B8, 0x1A2F2F8,
];
- foreach ($token as $x) {
- $x = $x ^ N;
+ 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";
+ $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";
}
@@ -384,33 +384,33 @@ assert(10 === +(![].+!![]));
まずはソースコードを読んでいく。
- $token = [
- // 略
+ $token = [
+ // 略
];
数値からなる$tokenがあり、各要素をループしている。
- $x = $x ^ N;
+ $x = $x ^ N;
まずは排他的論理和 (xor) を取り、
- $x = sprintf('%025b', $x);
+ $x = sprintf('%025b', $x);
二進数に変換して、
- $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);
+ $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);
0 を空白に、1 を#にし、
- $x = implode("\n", str_split($x, length: 5));
+ $x = implode("\n", str_split($x, length: 5));
5文字ごとに区切ったあと、改行で結合している。
@@ -464,49 +464,49 @@ assert(10 === +(![].+!![]));
Nは高々
- assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);
+ assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);
なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。
- <?php
+ <?php
- $x = 0x14B499C;
+ $x = 0x14B499C;
- $x = $x ^ N;
+ $x = $x ^ N;
- $x = sprintf('%025b', $x);
- $x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);
- $x = implode("\n", str_split($x, length: 5));
+ $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" .
- " # # ");
+ assert($x ===
+ " # # \n" .
+ "#####\n" .
+ " # # \n" .
+ "#####\n" .
+ " # # ");
この一連の変換に対する逆変換を考えると、次のようになる。
- <?php
+ <?php
-$x =
-" # # \n" .
-"#####\n" .
-" # # \n" .
-"#####\n" .
-" # # ";
+$x =
+" # # \n" .
+"#####\n" .
+" # # \n" .
+"#####\n" .
+" # # ";
-$x = implode('', explode("\n", $x));
-$x = str_replace(search: [' ', '#'], replace: ['0', '1'], subject: $x);
-$x = bindec($x);
+$x = implode('', explode("\n", $x));
+$x = str_replace(search: [' ', '#'], replace: ['0', '1'], subject: $x);
+$x = bindec($x);
-$n = $x ^ 0x14B499C;
+$n = $x ^ 0x14B499C;
-echo "N = $n\n";
+echo "N = $n\n";
これを実行すると、Nが得られる。
@@ -520,41 +520,41 @@ echo "N = $n\n";
ソースコードはこちら。
- <?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 | ...
+ // 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 = [
+ $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));
+ $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,
+ $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));
+ $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 toquine.php | php | php | php | ...
実際にはもう少しパイプで繋げなければならない。
diff --git a/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html b/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html
index eb55d81..8ae0fa6 100644
--- a/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html
+++ b/public/posts/2022-04-24/term-banner-write-tool-showing-banner-in-terminal/index.html
@@ -9,7 +9,7 @@
term-banner: ターミナルにバナーを表示するツールを書いた | REPL: Rest-Eat-Program Loop
-
+
@@ -53,7 +53,7 @@
こんなものを作った。
- $ term-banner 'Hello, World!' 'こんにちは、' '世界!'
+ $ term-banner 'Hello, World!' 'こんにちは、' '世界!'
image::https://raw.githubusercontent.com/nsfisis/term-banner/main/screenshot.png[term-banner のスクリーンショット]
diff --git a/public/posts/2022-05-01/phperkaigi-2022/index.html b/public/posts/2022-05-01/phperkaigi-2022/index.html
index ea9c581..a722db0 100644
--- a/public/posts/2022-05-01/phperkaigi-2022/index.html
+++ b/public/posts/2022-05-01/phperkaigi-2022/index.html
@@ -10,7 +10,7 @@
PHPerKaigi 2022 | REPL: Rest-Eat-Program Loop
-
+
diff --git a/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html b/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html
index 851f76c..1e124bf 100644
--- a/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html
+++ b/public/posts/2022-08-27/php-conference-okinawa-code-golf/index.html
@@ -10,7 +10,7 @@
PHP カンファレンス沖縄で出題されたコードゴルフの問題を解いてみた | REPL: Rest-Eat-Program Loop
-
+
@@ -121,7 +121,7 @@
書いたものがこちら:
- [<?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??[]);?>]
しめて 123 バイトとなった (末尾改行を含めずにカウント)。
@@ -131,15 +131,15 @@
こちらは改行とスペースを追加したバージョン:
- [<?php
+ [<?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 ?? []);
+ $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 ?? []);
- ?>]
+ ?>]
diff --git a/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html b/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html
index cc4f96e..a0e072b 100644
--- a/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html
+++ b/public/posts/2022-08-31/support-for-communty-is-employee-benefits/index.html
@@ -9,7 +9,7 @@
弊社の PHP Foundation への寄付に寄せて | REPL: Rest-Eat-Program Loop
-
+
diff --git a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html
index b450a07..7546291 100644
--- a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html
+++ b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html
@@ -10,7 +10,7 @@
【PHP】 fizzbuzz を書く。1行あたり2文字で。 | REPL: Rest-Eat-Program Loop
-
+
@@ -135,7 +135,7 @@
特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。
- #\
+ #\
i\
n\
c\
@@ -143,7 +143,7 @@ l\
u\
d\
e\
-<\
+<\
s\
t\
d\
@@ -151,14 +151,14 @@ i\
o\
.\
h\
->\
-/*
-*/
+>\
+/*
+*/
i\
n\
t\
-/*
-*/
+/*
+*/
m\
a\
i\
@@ -170,30 +170,30 @@ r(
i\
n\
t\
-/*
-*/
+/*
+*/
i=
-1;
-i<
-1\
-0\
-0;
+1;
+i<
+1\
+0\
+0;
i\
+\
+)
-if
+if
(i
%\
-15
+15
==
-0)
+0)
p\
r\
i\
n\
t\
f(
-"\
+"\
F\
i\
z\
@@ -204,11 +204,11 @@ z\
z\
%\
c\
-",
-10
+",
+10
);
-/* あとは同じように普通のプログラムを変形するだけなので省略 */
+/* あとは同じように普通のプログラムを変形するだけなので省略 */
バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。
@@ -268,9 +268,9 @@ c\
また、2文字だと文字列がまともに書けないのも辛い。''だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので
- $a
-='
-a'
+ $a
+='
+a'
;;
@@ -290,10 +290,10 @@ a'
まずは普通に書くとしよう。
- <?php
+ <?php
-for ($i = 1; $i < 100; $i++) {
- echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n";
+for ($i = 1; $i < 100; $i++) {
+ echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n";
}
@@ -307,13 +307,13 @@ for ($i = 1; $i < 100; $i++) {
forは、3文字もある長いキーワードである。こんなものは使えない。array_系の関数を使って、適当に置き換えるとしよう。
- <?php
+ <?php
-$s = range(1, 100);
-array_walk(
- $s,
- fn($i) =>
- printf((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"),
+$s = range(1, 100);
+array_walk(
+ $s,
+ fn($i) =>
+ printf((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"),
);
@@ -327,17 +327,17 @@ array_walk(
range、array_walk、printfは長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。
- <?php
+ <?php
-$r = 'range';
-$w = 'array_walk';
-$p = 'printf';
+$r = 'range';
+$w = 'array_walk';
+$p = 'printf';
-$s = $r(1, 100);
-$w(
- $s,
- fn($i) =>
- $p((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"),
+$s = $r(1, 100);
+$w(
+ $s,
+ fn($i) =>
+ $p((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"),
);
@@ -365,7 +365,7 @@ $w(
というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、Fizzという文字列が欲しければ、次のようにする。
- $f
+ $f
=F
.i
.z
@@ -376,13 +376,13 @@ $w(
こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、@演算子を使って抑制してやるとよい。
- $f
+ $f
=@
F.
@i
-.#
+.#
@z
-.#
+.#
@z
;;
@@ -401,66 +401,66 @@ F.
ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (&、|、^) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。
- $a = "12345";
-$b = "world";
+ $a = "12345";
+$b = "world";
-// $a ^ $b は次のコードと同じ
-$result = '';
-for ($i = 0; $i < min(strlen($a), strlen($b)); $i++) {
-$result .= $a[$i] ^ $b[$i];
+// $a ^ $b は次のコードと同じ
+$result = '';
+for ($i = 0; $i < min(strlen($a), strlen($b)); $i++) {
+$result .= $a[$i] ^ $b[$i];
}
-echo $result;
-// => F]AXQ
+echo $result;
+// => F]AXQ
これを踏まえ、次のコードを見てみよう。
- $x = "x\nOm\n";
-$y = "\nk!\no";
-$r = $x ^ $y;
-echo "$r\n";
+ $x = "x\nOm\n";
+$y = "\nk!\no";
+$r = $x ^ $y;
+echo "$r\n";
実行すると、rangeが表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。
- $x
-='x
+ $x
+='x
Om
-';
-$y
-='
+';
+$y
+='
k!
-o'
+o'
;
-$r = $x ^ $y;
-echo "$r\n";
+$r = $x ^ $y;
+echo "$r\n";
さらに#を使って適当に調整すると、次のようになる。
- $x
-=#
-'x
+ $x
+=#
+'x
Om
-';
-$y
-='
+';
+$y
+='
k!
-o'
-;#
-$r
-=#
-$x
-^#
-$y
-;#
+o'
+;#
+$r
+=#
+$x
+^#
+$y
+;#
-echo "$r\n";
+echo "$r\n";
1行あたり2文字で、rangeという文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。
@@ -478,154 +478,154 @@ echo "$r\n";
完成したものがこちら。
- <?php
+ <?php
-$x
-=#
-'i
-S'
+$x
+=#
+'i
+S'
;;
-$y
-='
+$y
+='
b!
-';
-$c
-=#
-$x
-^#
-$y
-;#
-$x
-=#
-'x
+';
+$c
+=#
+$x
+^#
+$y
+;#
+$x
+=#
+'x
Om
-';
-$y
-='
+';
+$y
+='
k!
-o'
-;#
-$r
-=#
-$x
-^#
-$y
-;#
-$x
-=#
-'k
+o'
+;#
+$r
+=#
+$x
+^#
+$y
+;#
+$x
+=#
+'k
Sk
~}
Ma
-';
-$y
-='
+';
+$y
+='
x!
s!
k!
-';
-$w
-=#
-$x
-^#
-$y
-;#
-$x
-=#
-'z
+';
+$w
+=#
+$x
+^#
+$y
+;#
+$x
+=#
+'z
Hd
-G'
-;#
-$y
-='
+G'
+;#
+$y
+='
x!
~!
-';
-$p
-=#
-$x
-^#
-$y
-;#
-$x
-=#
-'L
+';
+$p
+=#
+$x
+^#
+$y
+;#
+$x
+=#
+'L
[p
-';
-$y
-='
+';
+$y
+='
c!
-';
-$f
-=#
-$x
-^#
-$y
-;#
-$x
-=#
-'H
+';
+$f
+=#
+$x
+^#
+$y
+;#
+$x
+=#
+'H
[p
-';
-$y
-='
+';
+$y
+='
_!
-';
-$b
-=#
-$x
-^#
-$y
-;#
-$b
-[1
+';
+$b
+=#
+$x
+^#
+$y
+;#
+$b
+[1
]=
-$c
-(#
-13
-*9
+$c
+(#
+13
+*9
);
-$s
-=#
-$r
-(1
+$s
+=#
+$r
+(1
,(
-10
+10
**
-2)
+2)
);
-$w
-(#
-$s
-,#
-fn
-(#
-$i
-)#
-=>
-$p
+$w
+(#
+$s
+,#
+fn
+(#
+$i
+)#
+=>
+$p
((
-(#
-$i
-%3
-?#
-''
-:#
-$f
+(#
+$i
+%3
+?#
+''
+:#
+$f
).
-(#
-$i
-%5
-?#
-''
-:#
-$b
+(#
+$i
+%5
+?#
+''
+:#
+$b
)?
-:#
-$i
-)#
-.'
-')
+:#
+$i
+)#
+.'
+')
);
@@ -646,17 +646,17 @@ $i
PHP では、バッククォートを使ってシェルを呼び出せる。これはshell_exec関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。
- <?php
+ <?php
-printf(`
+printf(`
e\
c\
h\
o\
\
-1\
-2\
-3\
+1\
+2\
+3\
`);
@@ -685,34 +685,34 @@ o\
もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。
- <?php
+ <?php
-$c = 'chr';
+$c = 'chr';
${
-'_
-'}
-=#
-$c
-(#
-32
+'_
+'}
+=#
+$c
+(#
+32
).
-$c
-(#
-92
+$c
+(#
+92
);
-printf(`
+printf(`
e\
c\
h\
o\
${
-'_
-'}
-1\
-2\
-3\
+'_
+'}
+1\
+2\
+3\
`);
@@ -720,8 +720,8 @@ ${
${
-'_
-'}
+'_
+'}
は変数で、中にはスペースとエスケープが入っている (chr(32) . chr(92))。シェルに渡されている文字列は次のようになる。
@@ -749,8 +749,8 @@ o\
${
-'_
-'}
+'_
+'}
最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。
diff --git a/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html b/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html
index d7f71aa..10ef763 100644
--- a/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html
+++ b/public/posts/2022-10-23/phperkaigi-2023-unused-token-quiz-1/index.html
@@ -10,7 +10,7 @@
PHPerKaigi 2023: ボツになったトークン問題 その 1 | REPL: Rest-Eat-Program Loop
-
+
@@ -78,26 +78,26 @@
注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。
- <?php
+ <?php
-$π = $argv[1] ?? null;
-if ($π === null) {
-exit('No input.');
+$π = $argv[1] ?? null;
+if ($π === null) {
+exit('No input.');
}
-$π = trim($π);
-if (!is_numeric($π)) {
-exit('Invalid input.');
+$π = trim($π);
+if (!is_numeric($π)) {
+exit('Invalid input.');
}
-$s = implode(array_map(chr(...), str_split($π, 2)));
+$s = implode(array_map(chr(...), str_split($π, 2)));
-preg_match('/(\x23.+?) /', $s, $m);
-$t = $m[1] ?? '';
+preg_match('/(\x23.+?) /', $s, $m);
+$t = $m[1] ?? '';
-if (md5($t) === '056e831a4146bf123e8ea16613303d2e') {
-echo "Token: {$t}\n";
-} else {
-echo "Failed.\n";
+if (md5($t) === '056e831a4146bf123e8ea16613303d2e') {
+echo "Token: {$t}\n";
+} else {
+echo "Failed.\n";
}
@@ -107,14 +107,14 @@ echo "Failed.\n";
ソースを見るとわかるとおり、$argv[1]を参照している。それを$πなる変数に代入しているので、円周率を渡してみる。
- $ php Q.php 3.14
+ $ php Q.php 3.14
Failed.
失敗してしまった。精度を上げてみる。
- $ php Q.php 3.1415
+ $ php Q.php 3.1415
Failed.
@@ -125,7 +125,7 @@ Failed.
最初にトークンが得られるのは、小数点以下 16 桁目まで入力したときで、こうなる。
- $ php Q.php 3.1415926535897932
+ $ php Q.php 3.1415926535897932
Token: #YO
@@ -139,20 +139,20 @@ Token: #YO
短いので頭から追っていく。
- $π = $argv[1] ?? null;
- if ($π === null) {
- exit('No input.');
+ $π = $argv[1] ?? null;
+ if ($π === null) {
+ exit('No input.');
}
- $π = trim($π);
- if (!is_numeric($π)) {
- exit('Invalid input.');
+ $π = trim($π);
+ if (!is_numeric($π)) {
+ exit('Invalid input.');
}
入力のバリデーション部分。数値のみ受け付ける。
- $s = implode(array_map(chr(...), str_split($π, 2)));
+ $s = implode(array_map(chr(...), str_split($π, 2)));
$πを 2 文字ごとに区切り (str_split)、数値を ASCII コードと見做して文字に変換 (chr) して結合 (implode) している。
@@ -162,13 +162,13 @@ Token: #YO
例えば、$πが'656667'だったとすると、65、66、67に対応した'A'、'B'、'C'へと変換され、'ABC'になる。
- $π = '656667';
-$s = implode(array_map(chr(...), str_split($π, 2)));
-echo $s;
-// => ABC
+ $π = '656667';
+$s = implode(array_map(chr(...), str_split($π, 2)));
+echo $s;
+// => ABC
- preg_match('/(\x23.+?) /', $s, $m);
-$t = $m[1] ?? '';
+ preg_match('/(\x23.+?) /', $s, $m);
+$t = $m[1] ?? '';
正規表現でマッチングしている。\x23は#と同じであることに留意すると、この正規表現は「#から始まる 2 以上の長さ (含#) の文字列で、最初に現れるスペースまで」にマッチする。つまりこれは、PHPerKaigi におけるトークンである。
@@ -178,10 +178,10 @@ $t = $m[1] ?? '';
なお、#を直接書いていないのは、/#.+?) /と書くと、#.+?)という意図せぬトークンが登録されてしまうからである。
- if (md5($t) === '056e831a4146bf123e8ea16613303d2e') {
-echo "Token: {$t}\n";
-} else {
-echo "Failed.\n";
+ if (md5($t) === '056e831a4146bf123e8ea16613303d2e') {
+echo "Token: {$t}\n";
+} else {
+echo "Failed.\n";
}
diff --git a/public/posts/2022-10-28/setup-server-for-this-site/index.html b/public/posts/2022-10-28/setup-server-for-this-site/index.html
index e050bac..2f458ad 100644
--- a/public/posts/2022-10-28/setup-server-for-this-site/index.html
+++ b/public/posts/2022-10-28/setup-server-for-this-site/index.html
@@ -10,7 +10,7 @@
【備忘録】 このサイト用の VPS をセットアップしたときのメモ | REPL: Rest-Eat-Program Loop
-
+
@@ -83,7 +83,7 @@
ローカルマシンで鍵を生成する。
- $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key
+ $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/teika.key
$ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github2teika.key
@@ -97,7 +97,7 @@
.ssh/configに設定しておく。
- Host teika
+ Host teika
HostName **********
User **********
Port **********
@@ -120,7 +120,7 @@
管理者ユーザで作業すると危ないので、メインで使うユーザを作成する。sudoグループに追加してsudoできるようにし、suで切り替え。
- $ sudo adduser **********
+ $ sudo adduser **********
$ sudo adduser ********** sudo
$ su **********
$ cd
@@ -128,12 +128,12 @@
ホスト名を変える
- $ sudo hostname teika
+ $ sudo hostname teika
公開鍵を置く
- $ mkdir ~/.ssh
+ $ mkdir ~/.ssh
$ chmod 700 ~/.ssh
$ vi ~/.ssh/authorized_keys
@@ -148,7 +148,7 @@
SSH の設定を変更し、少しでも安全にしておく。
- $ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
+ $ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
$ sudo vi /etc/ssh/sshd_config
@@ -175,7 +175,7 @@
そして設定を反映。
-
$ sudo systemctl restart sshd
+ $ sudo systemctl restart sshd
$ sudo systemctl status sshd
@@ -185,7 +185,7 @@ $ sudo systemctl status sshd
今の SSH セッションは閉じずに、ターミナルを別途開いて疎通確認する。セッションを閉じてしまうと、SSH の設定に不備があった場合に締め出しをくらう。
- $ ssh teika
+ $ ssh teika
@@ -194,7 +194,7 @@ $ sudo systemctl status sshd
デフォルトの 22 番を閉じ、設定したポートだけ空ける。
- $ sudo ufw deny ssh
+ $ sudo ufw deny ssh
$ sudo ufw allow *******
$ sudo ufw enable
$ sudo ufw reload
@@ -211,20 +211,20 @@ $ sudo systemctl status sshd
GitHub に置いてある private リポジトリをサーバから clone したいので、SSH 鍵を生成して置いておく。
- $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github.key
+ $ ssh-keygen -t ed25519 -b 521 -f ~/.ssh/github.key
$ cat ~/.ssh/github.key.pub
GitHub の設定画面から、この公開鍵を追加する。
- $ vi ~/.ssh/config
+ $ vi ~/.ssh/config
設定はこう。
- Host github.com
+ Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github.key
@@ -233,12 +233,12 @@ IdentityFile ~/.ssh/github.key
最後に接続できるか確認しておく。
- ssh -T github.com
+ ssh -T github.com
パッケージの更新
- $ sudo apt update
+ $ sudo apt update
$ sudo apt upgrade
$ sudo apt update
$ sudo apt upgrade
@@ -257,12 +257,12 @@ IdentityFile ~/.ssh/github.key
使うソフトウェアのインストール
- $ sudo apt install docker docker-compose git make
+ $ sudo apt install docker docker-compose git make
メインユーザが Docker を使えるように
- sudo adduser ********** docker
+ sudo adduser ********** docker
@@ -271,7 +271,7 @@ IdentityFile ~/.ssh/github.key
80 番と 443 番を空ける。
- $ sudo ufw allow 80/tcp
+ $ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp
$ sudo ufw reload
$ sudo ufw status
@@ -279,7 +279,7 @@ IdentityFile ~/.ssh/github.key
リポジトリのクローン
- $ cd
+ $ cd
$ git clone git@github.com:nsfisis/nsfisis.dev.git
$ cd nsfisis.dev
$ git submodule update --init
@@ -287,13 +287,13 @@ IdentityFile ~/.ssh/github.key
certbot で証明書取得
- $ docker-compose up -d acme-challenge
+ $ docker-compose up -d acme-challenge
$ make setup
サーバを稼動させる
- $ make serve
+ $ make serve
diff --git a/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html b/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html
index fd1a1d2..e78fdce 100644
--- a/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html
+++ b/public/posts/2022-11-19/phperkaigi-2023-unused-token-quiz-2/index.html
@@ -10,7 +10,7 @@
PHPerKaigi 2023: ボツになったトークン問題 その 2 | REPL: Rest-Eat-Program Loop
-
+
@@ -82,17 +82,17 @@
注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。
-
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
@@ -106,42 +106,42 @@
実行してみると、次のような出力が得られる。
-
- #
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+
+ #
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
1 行目を除き、先ほどのコードとほぼ同じものが出てきた。もう一度実行してみる。
-
- #
+
+ #
W
-<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
-<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
-<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
-<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
-<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
-<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
-<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
- <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+ <?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s='<?php printf((isset($s)?fn($s)=>trim($s,""):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
今度は 2 行目が書き換えられた。すべての行が変化するまで繰り返すと次のようになる。
-
- #
+
+ #
W
E
L
@@ -168,8 +168,8 @@ W
Vim で開くと次のようになる (1 行目を抜粋)。
-
- <?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
+
+ <?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>')."\n","\x27$s\x27");?>
@@ -195,16 +195,16 @@ W
続いて、トークンへの変換ロジックを解析する。注目すべきはこの部分だ。以下、ゼロ幅スペースは Vim での表示に合わせて<200b>と記載する。
-
- fn($s)=>chr(strlen($s)/3)
+
+ fn($s)=>chr(strlen($s)/3)
PHP のstrlen()は文字列のバイト数を返す。1 行目の$sは以下の内容となっており、
-
- $s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'
+
+ $s='<200b><?php printf((isset($s)?fn($s)=>trim($s,"<200b>"):fn($s)=>chr(strlen($s)/3))($s=%s)."\n","\x27$s\x27");?>'
diff --git a/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html b/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html
index ab47b2b..61d9880 100644
--- a/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html
+++ b/public/posts/2023-01-10/phperkaigi-2023-unused-token-quiz-3/index.html
@@ -10,7 +10,7 @@
PHPerKaigi 2023: ボツになったトークン問題 その 3 | REPL: Rest-Eat-Program Loop
-
+
@@ -92,24 +92,24 @@
注意: これはボツ問なので、得られたトークンを PHPerKaigi で入力してもポイントにはならない。
- <?php
-try {
- f(g() / __LINE__);
-} catch (Throwable $e) {
- while ($e = $e->getPrevious()) printf('%c', $e->getLine() + 23);
- echo "\n";
+ <?php
+try {
+ f(g() / __LINE__);
+} catch (Throwable $e) {
+ while ($e = $e->getPrevious()) printf('%c', $e->getLine() + 23);
+ echo "\n";
}
-function f(int $i) {
- if ($i < 0) f();
- try {
- match ($i) {
- 0 => 0 / 0,
+function f(int $i) {
+ if ($i < 0) f();
+ try {
+ match ($i) {
+ 0 => 0 / 0,
- 15, 36 => 0 / 0,
- 14 => 0 / 0,
- 37 => 0 / 0,
+ 15, 36 => 0 / 0,
+ 14 => 0 / 0,
+ 37 => 0 / 0,
@@ -120,16 +120,16 @@ function f(int $i) {
- 6 => 0 / 0,
+ 6 => 0 / 0,
- 5 => 0 / 0,
+ 5 => 0 / 0,
- 22 => 0 / 0,
+ 22 => 0 / 0,
- 34, 35 => 0 / 0,
+ 34, 35 => 0 / 0,
@@ -138,10 +138,10 @@ function f(int $i) {
- 25 => 0 / 0,
- 17, 21 => 0 / 0,
+ 25 => 0 / 0,
+ 17, 21 => 0 / 0,
- 24, 32 => 0 / 0,
+ 24, 32 => 0 / 0,
@@ -149,12 +149,12 @@ function f(int $i) {
- 33 => 0 / 0,
+ 33 => 0 / 0,
- 16 => 0 / 0,
+ 16 => 0 / 0,
- 18 => 0 / 0,
+ 18 => 0 / 0,
@@ -163,35 +163,35 @@ function f(int $i) {
- 7 => 0 / 0,
+ 7 => 0 / 0,
- 2 => 0 / 0,
- 1, 20 => 0 / 0,
- 10, 28 => 0 / 0,
- 8, 12, 26 => 0 / 0,
- 4, 9, 13 => 0 / 0,
+ 2 => 0 / 0,
+ 1, 20 => 0 / 0,
+ 10, 28 => 0 / 0,
+ 8, 12, 26 => 0 / 0,
+ 4, 9, 13 => 0 / 0,
- 31 => 0 / 0,
+ 31 => 0 / 0,
- 29 => 0 / 0,
+ 29 => 0 / 0,
- 11 => 0 / 0,
+ 11 => 0 / 0,
- 3, 19, 23 => 0 / 0,
+ 3, 19, 23 => 0 / 0,
- 27 => 0 / 0,
+ 27 => 0 / 0,
- 30 => 0 / 0,
+ 30 => 0 / 0,
};
- } finally {
- f($i - 1);
+ } finally {
+ f($i - 1);
}
}
@@ -201,8 +201,8 @@ function f(int $i) {
-function g() {
- return __LINE__;
+function g() {
+ return __LINE__;
}
@@ -247,19 +247,19 @@ function g() {
このうち 1つ目のケースは、finally節の中でエラーを投げると PHP 処理系が勝手に$previousを設定してくれる。
- <?php
+ <?php
-try {
- try {
- throw new Exception("Error 1");
- } finally {
- throw new Exception("Error 2");
+try {
+ try {
+ throw new Exception("Error 1");
+ } finally {
+ throw new Exception("Error 2");
}
-} catch (Exception $e) {
- echo $e->getMessage() . PHP_EOL;
- // => Error 2
- echo $e->getPrevious()->getMessage() . PHP_EOL;
- // => Error 1
+} catch (Exception $e) {
+ echo $e->getMessage() . PHP_EOL;
+ // => Error 2
+ echo $e->getPrevious()->getMessage() . PHP_EOL;
+ // => Error 1
}
@@ -273,14 +273,14 @@ try {
出力部をコメントや改行を追加して再掲する:
- <?php
-try {
- f(g() / __LINE__);
-} catch (Throwable $e) {
- while ($e = $e->getPrevious()) {
- printf('%c', $e->getLine() + 23);
+ <?php
+try {
+ f(g() / __LINE__);
+} catch (Throwable $e) {
+ while ($e = $e->getPrevious()) {
+ printf('%c', $e->getLine() + 23);
}
- echo "\n";
+ echo "\n";
}
@@ -291,7 +291,7 @@ try {
フォーマット指定子%cは、整数を ASCII コードと見做して印字する。トークン#base64_decode('SGVsbG8sIFdvcmxkIQ==')のbであれば、ASCII コード98なので、75 行目で発生したエラー、
- 1, 20 => 0 / 0,
+ 1, 20 => 0 / 0,
によって表現されている。エラーを起こす方法はいろいろと考えられるが、今回はゼロ除算を使った。
@@ -308,24 +308,24 @@ try {
f()の定義を再掲する (エラーオブジェクトの行数を利用しているので、一部分だけ抜き出すと値が変わることに注意):
- function f(int $i) {
- if ($i < 0) f();
- try {
- match ($i) {
- 0 => 0 / 0, // 12 行目
+ function f(int $i) {
+ if ($i < 0) f();
+ try {
+ match ($i) {
+ 0 => 0 / 0, // 12 行目
- 15, 36 => 0 / 0,
- 14 => 0 / 0,
- 37 => 0 / 0,
+ 15, 36 => 0 / 0,
+ 14 => 0 / 0,
+ 37 => 0 / 0,
- // (略)
+ // (略)
- 30 => 0 / 0, // 97 行目
+ 30 => 0 / 0, // 97 行目
};
- } finally {
- f($i - 1);
+ } finally {
+ f($i - 1);
}
}
@@ -333,12 +333,12 @@ try {
前述のように、finally節でエラーを投げると PHP 処理系が$previousを設定する。ここでは、エラーを繋げるためにf()を再帰呼び出ししている。最初にf()を呼び出している箇所を確認すると、
- <?php
-try {
- f(g() / __LINE__); // 3 行目
+ <?php
+try {
+ f(g() / __LINE__); // 3 行目
- function g() {
- return __LINE__; // 111 行目
+ function g() {
+ return __LINE__; // 111 行目
}
diff --git a/public/posts/2023-03-10/rewrite-this-blog-generator/index.html b/public/posts/2023-03-10/rewrite-this-blog-generator/index.html
index 0d05ca5..855203b 100644
--- a/public/posts/2023-03-10/rewrite-this-blog-generator/index.html
+++ b/public/posts/2023-03-10/rewrite-this-blog-generator/index.html
@@ -9,7 +9,7 @@
このブログのジェネレータを書き直した | REPL: Rest-Eat-Program Loop
-
+
--
cgit v1.2.3-70-g09d2