Mercurial > repo
view golfscript.rb @ 3023:dfd73e2917ba
<nooodl_> fetch http://www.golfscript.com/golfscript/golfscript.rb
author | HackBot |
---|---|
date | Sat, 01 Jun 2013 19:35:00 +0000 |
parents | |
children |
line wrap: on
line source
#!/usr/bin/ruby #(c) Copyright 2008 Darren Smith. All Rights Reserved. $lb = [] class Gtype def go $stack<<self end def val @val end '+-|&^'.each_byte{|i| eval'def %c(rhs) if rhs.class != self.class a,b=coerce(rhs) a %c b else factory(@val %c rhs.val) end end'%([i]*3) } def ==(rhs) @val==rhs.val end def eql?(rhs) @val==rhs.val end def hash @val.hash end def <=>(rhs) @val<=>rhs.val end end class Gint < Gtype def initialize(i) @val = case i when true then 1 when false then 0 else;i end end def factory(a) Gint.new(a) end def to_gs Gstring.new(@val.to_s) end def to_int #for pack @val end def ginspect to_gs end def class_id; 0; end def coerce(b) [if b.class == Garray Garray.new([self]) elsif b.class == Gstring to_gs else #Gblock to_gs.to_s.compile end,b] end def ~ Gint.new(~@val) end def notop Gint.new(@val == 0) end '*/%<>'.each_byte{|i| eval'def %c(rhs) Gint.new(@val %c rhs.val) end'%[i,i] } def equalop(rhs) Gint.new(@val == rhs.val) end def question(b) Gint.new(@val**b.val) end def base(a) if Garray===a r=0 a.val.each{|i| r*=@val r+=i.val } Gint.new(r) else i=a.val.abs r=[] while i!=0 r.unshift Gint.new(i%@val) i/=@val end Garray.new(r) end end def leftparen Gint.new(@val-1) end def rightparen Gint.new(@val+1) end end class Garray < Gtype def initialize(a) @val = a || [] end def factory(a) Garray.new(a) end def to_gs @val.inject(Gstring.new("")){|s,i|s+i.to_gs} end def flatten #maybe name to_a ? # Garray.new(@val.inject([]){|s,i|s+case i # when Gstring then i.val # when Gint then [i] # when Garray then i.flatten.val # when Gblock then i.val # end # }) # end #use Peter Taylor's fix to avoid quadratic flatten times Garray.new(flatten_append([])) end def flatten_append(prefix) @val.inject(prefix){|s,i|case i when Gint then s<<i when Garray then i.flatten_append(s) when Gstring then s.concat(i.val) when Gblock then s.concat(i.val) end } end def ginspect Gstring.new('[')+Garray.new(@val.map{|i|i.ginspect})*Gstring.new(' ')+Gstring.new(']') end def go $stack<<self end def class_id; 1; end def coerce(b) if b.class == Gint b.coerce(self).reverse elsif b.class == Gstring [Gstring.new(self),b] else [(self*Gstring.new(' ')).to_s.compile,b] end end def leftparen [factory(@val[1..-1]),@val[0]] end def rightparen [factory(@val[0..-2]),@val[-1]] end def *(b) if b.class == Gint factory(@val*b.val) else return b*self if self.class == Gstring && b.class == Garray return self/Gint.new(1)*b if self.class == Gstring return b.factory([]) if @val.size<1 r=@val.first r,x=r.coerce(b) if r.class != b.class #for size 1 @val[1..-1].each{|i|r=r+b+i} r end end def /(b) if b.class == Gint r=[] a = b.val < 0 ? @val.reverse : @val i = -b = b.val.abs r << factory(a[i,b]) while (i+=b)<a.size Garray.new(r) else r=[] i=b.factory([]) j=0 while j<@val.size if @val[j,b.val.size]==b.val r<<i i=b.factory([]) j+=b.val.size else i.val<<@val[j] j+=1 end end r<<i Garray.new(r) end end def %(b) if b.class == Gint b=b.val factory((0..(@val.size-1)/b.abs).inject([]){|s,i| s<<@val[b < 0 ? i*b - 1 : i*b] }) else self/b-Garray.new([Garray.new([])]) end end def notop Gint.new(@val.empty?) end def question(b) Gint.new(@val.index(b)||-1) end def equalop(b) if b.class == Gint @val[b.val] else Gint.new(@val==b.val) end end def <(b) if b.class == Gint factory(@val[0...b.val]) else Gint.new(@val<b.val) end end def >(b) if b.class == Gint factory(@val[[b.val,-@val.size].max..-1]) else Gint.new(@val>b.val) end end def sort factory(@val.sort) end def zip r=[] @val.size.times{|x| @val[x].val.size.times{|y| (r[y]||=@val[0].factory([])).val<<@val[x].val[y] } } Garray.new(r) end def ~ val end end class Gstring < Garray def initialize(a) @val=case a when NilClass then [] when String then a.unpack('C*').map{|i|Gint.new(i)} when Array then a when Garray then a.flatten.val end end def factory(a) Gstring.new(a) end def to_gs self end def ginspect factory(to_s.inspect) end def to_s @val.pack('C*') end def class_id; 2; end def coerce(b) if b.class == Gblock [to_s.compile,b] else b.coerce(self).reverse end end def question(b) if b.class == Gstring Gint.new(to_s.index(b.to_s)||-1) elsif b.class == Garray b.question(self) else Gint.new(@val.index(b)||-1) end end def ~ to_s.compile.go nil end end class Gblock < Garray def initialize(_a,_b=nil) @val=Gstring.new(_b).val @native = eval("lambda{#{_a}}") end def go @native.call end def factory(b) Gstring.new(b).to_s.compile end def class_id; 3; end def to_gs Gstring.new("{"+Gstring.new(@val).to_s+"}") end def ginspect to_gs end def coerce(b) b.coerce(self).reverse end def +(b) if b.class != self.class a,b=coerce(b) a+b else Gstring.new(@val+Gstring.new(" ").val+b.val).to_s.compile end end def *(b) if b.class == Gint b.val.times{go} else gpush b.val.first (b.val[1..-1]||[]).each{|i|$stack<<i; go} end nil end def /(b) if b.class==Garray||b.class==Gstring b.val.each{|i|gpush i; go} nil else #unfold r=[] loop{ $stack<<$stack.last go break if gpop.notop.val!=0; r<<$stack.last b.go } gpop Garray.new(r) end end def %(b) r=[] b.val.each{|i| lb=$stack.size $stack<<i; go r.concat($stack.slice!(lb..$stack.size)) } r=Garray.new(r) b.class == Gstring ? Gstring.new(r) : r end def ~ go nil end def sort a=gpop a.factory(a.val.sort_by{|i|gpush i; go; gpop}) end def select(a) a.factory(a.val.select{|i|gpush i;go; gpop.notop.val==0}) end def question(b) b.val.find{|i|gpush i; go; gpop.notop.val==0} end end class NilClass def go end end class Array def ^(rhs) self-rhs|rhs-self end include Comparable end code=gets(nil)||'' $_=$stdin.isatty ? '' : $stdin.read $stack = [Gstring.new($_)] $var_lookup={} def var(name,val=nil) eval"#{s="$_#{$var_lookup[name]||=$var_lookup.size}"}||=val" s end $nprocs=0 class String def compile(tokens=scan(/[a-zA-Z_][a-zA-Z0-9_]*|'(?:\\.|[^'])*'?|"(?:\\.|[^"])*"?|-?[0-9]+|#[^\n\r]*|./m)) orig=tokens.dup native="" while t=tokens.slice!(0) native<<case t when "{" then "$stack<<"+var("{#{$nprocs+=1}",compile(tokens)) when "}" then break when ":" then var(tokens.slice!(0))+"=$stack.last" when /^["']/ then var(t,Gstring.new(eval(t)))+".go" when /^-?[0-9]+/ then var(t,Gint.new(t.to_i))+".go" else; var(t)+".go" end+"\n" end source=orig[0,orig.size-tokens.size-(t=="}"?1:0)]*"" Gblock.new(native,source) end end def gpop ($lb.size-1).downto(0){|i| break if $lb[i]<$stack.size $lb[i]-=1 } $stack.pop end def gpush a $stack.push(*a) if a end class String def cc Gblock.new(self) end def cc1 ('a=gpop;'+self).cc end def cc2 ('b=gpop;a=gpop;'+self).cc end def cc3 ('c=gpop;b=gpop;a=gpop;'+self).cc end def order ('b=gpop;a=gpop;a,b=b,a if a.class_id<b.class_id;'+self).cc end end var'[','$lb<<$stack.size'.cc var']','gpush Garray.new($stack.slice!(($lb.pop||0)..-1))'.cc var'~','gpush ~a'.cc1 var'`','gpush a.ginspect'.cc1 var';',''.cc1 var'.','$stack<<a<<a'.cc1 var'\\','$stack<<b<<a'.cc2 var'@','$stack<<b<<c<<a'.cc3 var'+','gpush a+b'.cc2 var'-','gpush a-b'.cc2 var'|','gpush a|b'.cc2 var'&','gpush a&b'.cc2 var'^','gpush a^b'.cc2 var'*','gpush a*b'.order var'/','gpush a/b'.order var'%','gpush a%b'.order var'=','gpush a.equalop(b)'.order var'<','gpush a<b'.order var'>','gpush a>b'.order var'!','gpush a.notop'.cc1 var'?','gpush a.question(b)'.order var'$','gpush (a.class==Gint ? $stack[~a.val] : a.sort)'.cc1 var',','gpush case a when Gint then Garray.new([*0...a.val].map{|i|Gint.new(i)}) when Gblock then a.select(gpop) when Garray then Gint.new(a.val.size) end'.cc1 var')','gpush a.rightparen'.cc1 var'(','gpush a.leftparen'.cc1 var'rand','gpush Gint.new(rand([1,a.val].max))'.cc1 var'abs','gpush Gint.new(a.val.abs)'.cc1 var'print','print a.to_gs'.cc1 var'if',"#{var'!'}.go;(gpop.val==0?a:b).go".cc2 var'do',"loop{a.go; #{var'!'}.go; break if gpop.val!=0}".cc1 var'while',"loop{a.go; #{var'!'}.go; break if gpop.val!=0; b.go}".cc2 var'until',"loop{a.go; #{var'!'}.go; break if gpop.val==0; b.go}".cc2 var'zip','gpush a.zip'.cc1 var'base','gpush b.base(a)'.cc2 '"\n":n; {print n print}:puts; {`puts}:p; {1$if}:and; {1$\if}:or; {\!!{!}*}:xor; '.compile.go code.compile.go gpush Garray.new($stack) 'puts'.compile.go