Neue eingebaute Operatoren definieren
Der standardmäßige GolfScript-Interpreter verfügt über eine selten verwendete Funktion , die interpolierten Ruby-Code in Strings in doppelten Anführungszeichen ermöglicht.
Ein Grund, warum diese Funktion nicht häufiger verwendet wird, ist, dass der interpolierte Code umständlich zur Kompilierungszeit ausgeführt wird und die Ausgabe vom GolfScript-Interpreter zwischengespeichert wird, so dass dasselbe Zeichenfolgenliteral auch innerhalb immer den gleichen Wert ergibt string eval.
Eine Sache, für die sich diese Funktion als gut herausstellt, ist die Definition neuer GolfScript-Operatoren, die in Ruby-Code implementiert sind. So definieren Sie beispielsweise einen neuen binären Additionsoperator, der genau wie der integrierte Standardoperator funktioniert +
:
"#{var'add','gpush a+b'.cc2}";
Es spielt keine Rolle, wo Sie die Definition in Ihren Code einfügen. Der neue Operator wird definiert, sobald die doppelte Zeichenfolge mit dem Ruby-Code analysiert wird. Der add
oben definierte Operator funktioniert genauso wie der eingebaute +
Operator und kann genauso verwendet werden:
1 2 add # evaluates to 3
"foo" "bar" add # evaluates to "foobar"
Das Definieren eines neuen Additionsoperators ist natürlich ziemlich nutzlos, es sei denn, Sie haben etwas Dummes getan, wie den eingebauten +
Operator zu löschen . Mit demselben Trick können Sie jedoch neue Operatoren definieren, die Dinge tun, die Golfscript nicht (ohne weiteres) von Haus aus tun kann, z. B. das einheitliche Mischen eines Arrays:
"#{var'shuf','gpush a.factory(a.val.shuffle)'.cc1}";
10,shuf # evaluates to 0,1,2,...,9 in random order
oder den Inhalt des gesamten Stapels drucken:
"#{var'debug','puts Garray.new($stack).ginspect'.cc}";
4,) ["foo" debug # prints ["" [0 1 2] 3 "foo"], leaving the stack untouched
oder interaktive Eingabe:
"#{var'gets','gpush Gstring.new(STDIN.gets)'.cc}";
]; { "> " print gets ~ ]p 1 } do # simple GolfScript REPL
oder sogar Webzugriff:
"#{
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
Eine etwas golferischere (und riskantere!) Implementierung der letzteren wäre natürlich zB:
"#{var'get','gpush Gstring.new(`curl -s #{a}`)'.cc1}";
Dies ist an sich nicht besonders golfen, ermöglicht Ihnen jedoch, die Fähigkeiten von GolfScript über das hinaus zu erweitern, was die eingebauten Befehle bieten.
Wie funktioniert es?
Die maßgebliche Referenz zur Definition neuer GolfScript-Operatoren auf diese Weise ist natürlich der Quellcode für den Interpreter . Das heißt, hier sind ein paar kurze Tipps:
Um einen neuen Operator zu definieren name
, der den Ruby-Code ausführt code
, verwenden Sie:
var'name','code'.cc
Verwenden Sie im Code, um gpop
einen Wert aus dem Stapel zu lesen und gpush
wieder einzuschieben. Sie können auch direkt über das Array auf den Stapel zugreifen $stack
. Zum Beispiel, um beide a
und b
auf den Stapel zu schieben , ist es golfer, $stack<<a<<b
als zu tun gpush a;gpush b
.
- Die Positionen der
[
Array-Startmarkierungen werden im $lb
Array gespeichert . Die gpop
Funktion sorgt dafür, dass diese Markierungen nach unten korrigiert werden, wenn der Stapel unter ihre Position schrumpft, nicht jedoch, wenn das $stack
Array direkt manipuliert wird.
Die .cc
Zeichenfolgenmethode, mit der Ruby-Code in einer Zeichenfolge in einen GolfScript-Operator kompiliert wird, ist nur ein praktischer Wrapper Gblock.new()
. Es hat auch die Varianten .cc1
, .cc2
und .cc3
das macht den Bediener automatisch 1 Pop, 2 oder 3 Argumente vom Stapel und weisen Sie auf die Variablen a
, b
und c
. Es gibt auch ein .order
Verfahren , das funktioniert wie .cc2
, mit der Ausnahme , dass es automatisch die Argumente sortiert Typ Priorität .
Alle Werte auf dem GolfScript Stapel (und sollen!) Objekte vom Typ Gint
, Garray
, Gstring
oder Gblock
. Auf die zugrunde liegende native Ganzzahl oder das zugrunde liegende Array kann bei Bedarf über die .val
Methode zugegriffen werden .
- Beachten Sie jedoch, dass
Gstring.val
ein Array von Gint
s! Um eine Gstring
in eine native Ruby-Zeichenfolge zu verwandeln , rufen Sie .to_s
sie stattdessen auf (oder verwenden Sie sie in einem Kontext, der dies automatisch ausführt, z. B. bei der Zeichenfolgeninterpolation). Der Aufruf .to_gs
auf jedem GS Wert verwandelt es in ein Gstring
, so kann jeder GS - Wert mit Zeichenfolge werden .to_gs.to_s
.
Die gpush
Funktion bricht native Ruby-Zahlen, -Strings oder -Arrays nicht automatisch in die entsprechenden GS-Typen ein, sodass Sie dies häufig selbst tun müssen, indem Sie z Gstring.new()
. B. explizit aufrufen . Wenn Sie etwas anderes als einen der GS-Werttypen auf den Stapel schieben, stürzt wahrscheinlich jeder Code ab, der später versucht, ihn zu manipulieren.
Die GS- .factory
Werttypen verfügen auch über eine Methode, die den Konstruktor des Typs aufruft. Dies kann nützlich sein, um z. B. Arrays / Strings nach der Bearbeitung ihres Inhalts neu zu verpacken. Alle Typen haben auch eine .coerce
Methode, mit der Typenzwang ausgeführt wird : a.coerce(b)
Gibt ein Paar zurück, das denselben Typ enthält a
und zu diesem b
gezwungen wird.
... x
in etwas zu verwandeln... [x]
? Das Beste, was ich sehen kann, ist[.;]
.