定义新的内置运算符
标准的GolfScript解释器具有很少使用的功能,该功能允许在双引号字符串文字中插入Ruby代码。
之所以不常用此功能的原因之一是,尴尬的是,内插的代码在编译时执行,并且输出由GolfScript解释器缓存,因此,即使在内部,相同的字符串文字也始终会产生相同的值。字符串评估。
但是,此功能最有利的一件事是定义以Ruby代码实现的新的GolfScript运算符。例如,以下是定义新的二进制加法运算符的方法,该运算符的工作方式与标准内置+
运算符相同:
"#{var'add','gpush a+b'.cc2}";
将定义放在代码中的位置并不重要;解析包含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
甚至是网络访问:
"#{
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
将其压回。您还可以直接通过array访问堆栈$stack
。例如,要将两者a
同时b
推入堆栈,要比做高尔夫球手$stack<<a<<b
要好gpush a;gpush b
。
- 所述的位置
[
阵列启动标记被存储在所述$lb
阵列。gpop
如果堆栈缩小到其位置以下,该函数会注意将这些标记向下调整,但$stack
直接操作数组则不会。
将.cc
字符串中的Ruby代码编译为GolfScript运算符的字符串方法只是一个方便的包装Gblock.new()
。它也有变种.cc1
,.cc2
并且.cc3
使操作者自动弹出1,2或3个参数从堆栈中,并将其分配给变量a
,b
和c
。还有一种.order
类似的方法.cc2
,除了它会根据类型priority将参数自动排序。
在GolfScript堆栈上的所有值(也应该!)类型的对象Gint
,Garray
,Gstring
或Gblock
。底层本地整数或数组(如果需要)可以通过.val
方法访问。
- 但是,请注意
Gstring.val
返回Gint
s 的数组!要将a Gstring
转换为本地Ruby字符串,请调用.to_s
它(或在自动执行此操作的上下文中使用它,例如字符串插值)。调用.to_gs
任何GS值都会将其转换为Gstring
,因此任何GS值都可以使用进行字符串化.to_gs.to_s
。
该gpush
函数不会自动将本地Ruby数字,字符串或数组自动包装到相应的GS类型中,因此,您通常必须自己通过显式调用eg来做到这一点Gstring.new()
。如果将GS值类型之一以外的任何其他内容推入堆栈,则以后尝试对其进行操作的任何代码都可能崩溃。
GS值类型还具有.factory
调用该类型的构造函数的方法,该方法可能非常有用,例如,在处理它们的内容后重新包装数组/字符串。所有类型都有一个.coerce
执行类型强制的方法:a.coerce(b)
返回一对包含a
并b
强制为相同类型的对。
... x
成... [x]
?我所能看到的最好的是[.;]
。