Mercurial > repo
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/golfscript.rb Sat Jun 01 19:35:00 2013 +0000 @@ -0,0 +1,500 @@ +#!/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