Definizione di nuovi operatori integrati
L'interprete GolfScript standard ha una funzione usata raramente che consente il codice Ruby interpolato in valori letterali di stringa tra virgolette doppie.
Uno dei motivi per cui questa funzione non è più comunemente usata è che, a disagio, il codice interpolato viene eseguito in fase di compilazione e l'output viene memorizzato nella cache dall'interprete GolfScript in modo che la stessa stringa letterale da allora in poi produrrà sempre lo stesso valore, anche all'interno valutazione delle stringhe.
Tuttavia, una cosa per cui questa funzionalità risulta utile è la definizione di nuovi operatori GolfScript implementati nel codice Ruby. Ad esempio, ecco come definire un nuovo operatore di aggiunta binaria che funziona esattamente come l' +operatore integrato standard :
"#{var'add','gpush a+b'.cc2}";
Non importa dove metti la definizione nel tuo codice; il nuovo operatore viene definito non appena viene analizzata la stringa tra virgolette doppie contenente il codice Ruby. L' addoperatore sopra definito funziona esattamente come l' +operatore integrato e può essere utilizzato esattamente allo stesso modo:
1 2 add # evaluates to 3
"foo" "bar" add # evaluates to "foobar"
Naturalmente, definire un nuovo operatore addizione è abbastanza inutile, a meno che tu non abbia fatto qualcosa di stupido come cancellare l' +operatore incorporato . Ma puoi usare lo stesso trucco per definire nuovi operatori che fanno cose che Golfscript non può (facilmente) fare nativamente come, per esempio, mescolare uniformemente un array:
"#{var'shuf','gpush a.factory(a.val.shuffle)'.cc1}";
10,shuf # evaluates to 0,1,2,...,9 in random order
o stampando il contenuto dell'intera pila:
"#{var'debug','puts Garray.new($stack).ginspect'.cc}";
4,) ["foo" debug # prints ["" [0 1 2] 3 "foo"], leaving the stack untouched
o input interattivo:
"#{var'gets','gpush Gstring.new(STDIN.gets)'.cc}";
]; { "> " print gets ~ ]p 1 } do # simple GolfScript REPL
o persino l'accesso al 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
Naturalmente, un'implementazione un po 'più golfosa (e più rischiosa!) Di quest'ultima sarebbe ad esempio:
"#{var'get','gpush Gstring.new(`curl -s #{a}`)'.cc1}";
Sebbene non sia particolarmente golfoso in sé, ciò consente di estendere le capacità di GolfScript oltre a ciò che offrono i comandi integrati.
Come funziona?
Il riferimento autorevole su come definire i nuovi operatori GolfScript in questo modo è, ovviamente, il codice sorgente per l'interprete . Detto questo, ecco alcuni suggerimenti rapidi:
Per definire un nuovo operatore nameche esegue il codice Ruby code, utilizzare:
var'name','code'.cc
All'interno del codice, utilizzare gpopper leggere un valore dallo stack e gpushper reinserirne uno. È inoltre possibile accedere allo stack direttamente tramite l'array $stack. Ad esempio, per spingere entrambi ae bnello stack, è più golfoso di $stack<<a<<bquello gpush a;gpush b.
- Le posizioni dei
[marker di inizio dell'array sono memorizzate $lbnell'array. La gpopfunzione si occupa di regolare questi marker verso il basso se lo stack si riduce al di sotto della loro posizione, ma la manipolazione $stackdiretta dell'array no.
Il .ccmetodo stringa che compila il codice Ruby in una stringa in un operatore GolfScript è solo un comodo wrapper Gblock.new(). Ha anche le varianti .cc1, .cc2e .cc3che rendono l'operatore pop automaticamente 1, 2 o 3 argomenti dallo stack e li assegna alle variabili a, be c. C'è anche un .ordermetodo che funziona come .cc2, tranne che ordina automaticamente gli argomenti per tipo di priorità .
Tutti i valori sullo stack GolfScript sono (e dovrebbe essere!) Oggetti di tipo Gint, Garray, Gstringo Gblock. L'intero o l'array nativo sottostante, ove necessario, è accessibile tramite il .valmetodo.
- Tuttavia, si noti che
Gstring.valrestituisce una matrice di Gints! Per trasformare a Gstringin una stringa Ruby nativa, chiamala .to_sinvece (o usala in un contesto che lo fa automaticamente, come l'interpolazione di stringhe). La chiamata .to_gsa qualsiasi valore GS lo trasforma in a Gstring, quindi è possibile stringere qualsiasi valore GS .to_gs.to_s.
La gpushfunzione non avvolge automaticamente numeri, stringhe o matrici di Ruby nativi nei corrispondenti tipi GS, quindi spesso dovrai farlo tu stesso chiamando esplicitamente ad es Gstring.new(). Se si inserisce nello stack qualcosa di diverso da uno dei tipi di valore GS, è probabile che si verifichi un arresto anomalo di qualsiasi codice che successivamente tenta di manipolarlo.
I tipi di valore GS hanno anche un .factorymetodo che chiama il costruttore del tipo, che può essere utile, ad esempio, per riavvolgere matrici / stringhe dopo averne manipolato il contenuto. Tutti i tipi hanno anche un .coercemetodo che esegue la coercizione del tipo : a.coerce(b)restituisce una coppia contenente ae bcostretta allo stesso tipo.
... xin... [x]? Il meglio che posso vedere è[.;].