新しい組み込み演算子の定義
標準のGolfScriptインタープリターには、二重引用符で囲まれた文字列リテラルで補間されたRubyコードを許可する、めったに使用されない機能があります。
この機能がより一般的に使用されない理由の1つは、厄介なことに、補間コードがコンパイル時に実行されることです。に、出力がGolfScriptインタープリターによってキャッシュされるため、その後も同じ文字列リテラルが常に同じ値を生成するためです文字列評価。
ただし、この機能の利点の1つは、Rubyコードで実装された新しいGolfScript演算子を定義することです。たとえば、標準の組み込み演算子と同じように機能する新しいバイナリ加算演算子を定義する方法は+
次のとおりです。
"#{var'add','gpush a+b'.cc2}";
コードのどこに定義を入れてもかまいません。new演算子は、Rubyコードを含む二重引用符で囲まれた文字列が解析されるとすぐに定義されます。add
作品上で定義された演算子を正確に内蔵されたような+
オペレータ、およびまったく同じように使用できます。
1 2 add # evaluates to 3
"foo" "bar" add # evaluates to "foobar"
もちろん、組み込み演算子を消去するような愚かなことをしていない限り、新しい加算演算子を定義することはほとんど役に立たない+
。しかし、同じトリックを使用して、Golfscriptがネイティブに(簡単に)できないことを行う新しい演算子を定義できます。たとえば、配列を均一にシャッフルするなどです。
"#{var'shuf','gpush a.factory(a.val.shuffle)'.cc1}";
10,shuf # evaluates to 0,1,2,...,9 in random order
または、スタック全体の内容を印刷します。
"#{var'debug','puts Garray.new($stack).ginspect'.cc}";
4,) ["foo" debug # prints ["" [0 1 2] 3 "foo"], leaving the stack untouched
またはインタラクティブな入力:
"#{var'gets','gpush Gstring.new(STDIN.gets)'.cc}";
]; { "> " print gets ~ ]p 1 } do # simple GolfScript REPL
またはWebアクセス:
"#{
require 'net/http'
require 'uri'
var'get','gpush Gstring.new(Net::HTTP.get_response(URI.parse(a.to_s)).body)'.cc1
}";
"http://example.com" get
もちろん、後者のややゴルファーな(そしてより危険な!)実装は次のようになります:
"#{var'get','gpush Gstring.new(`curl -s #{a}`)'.cc1}";
それ自体は特にゴルフではありませんが、これにより、組み込みコマンドが提供するものを超えてGolfScriptの機能を拡張できます。
どのように機能しますか?
この方法で新しいGolfScriptオペレーターを定義する方法に関する信頼できるリファレンスは、もちろんインタープリターのソースコードです。。とはいえ、ここにいくつかの簡単なヒントがあります。
name
Rubyコードを実行する新しい演算子を定義するにはcode
、次を使用します。
var'name','code'.cc
コード内でを使用gpop
して、スタックから値を読み取り、gpush
1つをプッシュバックします。また、配列を介してスタックに直接アクセスすることもできます$stack
。たとえば、両方a
をb
スタックにプッシュするには$stack<<a<<b
、ゴルファーよりもgpush a;gpush b
。
[
配列の開始マーカーの位置は、配列に保存され$lb
ます。このgpop
関数は、スタックがその位置よりも小さくなった場合にこれらのマーカーを調整しますが、$stack
配列を直接操作してもしません。
.cc
GolfScriptオペレータに文字列にRubyコードをコンパイル列方法は、ラッパーだけ便宜ですGblock.new()
。また、バリアントを持っている.cc1
、.cc2
そして.cc3
それは、オペレータが自動的にスタックから1、2または3つの引数をポップし、変数に割り当てる作るa
、b
とc
。.order
同様.cc2
に機能するメソッドもありますが、タイプ優先度によって引数を自動的にソートします。
GolfScriptスタック上のすべての値がある(とする必要があります!)型のオブジェクトGint
、Garray
、Gstring
またはGblock
。基になるネイティブ整数または配列は、必要に応じて、.val
メソッドを介してアクセスできます。
- ただし、sの
Gstring.val
配列を返すことに注意してくださいGint
!をGstring
ネイティブのRuby文字列に変換するには、.to_s
代わりに呼び出します(または、文字列補間のように自動的にそれを行うコンテキストで使用します)。.to_gs
GS値を呼び出すと、aに変換されるGstring
ため、GS値はで文字列化できます.to_gs.to_s
。
このgpush
関数は、ネイティブのRubyの数値、文字列、または配列を対応するGS型に自動ラップしないため、明示的に次のように呼び出すことで、多くの場合自分で行う必要がありますGstring.new()
。GS値タイプの1つ以外をスタックにプッシュすると、後でそれを操作しようとするコードがクラッシュする可能性があります。
GS値型に.factory
は、型のコンストラクターを呼び出すメソッドもあります。これは、たとえば、コンテンツを操作した後に配列/文字列を再ラップする場合に便利です。すべてのタイプも持って.coerce
行うことメソッド型変換は:a.coerce(b)
を含む一対の戻りa
とb
同じ型に強制します。
... x
には... [x]
?私が見ることができる最高のものです[.;]
。